@desynova-digital/player 4.0.89 → 4.0.91

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/actions/player.js CHANGED
@@ -199,13 +199,37 @@ function mute(muted) {
199
199
  operation: operation
200
200
  };
201
201
  }
202
+ function safeAppend(parent, child) {
203
+ if (!parent || !child) return;
204
+
205
+ // Prevent circular nesting
206
+ if (child.contains(parent)) return; // ❌ cannot append parent inside child
207
+
208
+ // Prevent duplicates
209
+ if (parent.contains(child)) return; // already appended
210
+
211
+ parent.appendChild(child); // safe
212
+ }
213
+
214
+ // keep this outside so original parent is remembered across toggles
215
+ var toastOriginalParent = null;
202
216
  function toggleFullscreen(player) {
203
217
  if (_fullscreen["default"].enabled) {
204
- // var elem = document.getElementsByClassName('left-video-section')[0];
205
- var elem = document.getElementsByClassName('player-container')[0];
218
+ var elem = document.querySelector('.player-container');
206
219
  var right = document.querySelector('.right-video-section');
220
+ var root = document.getElementById('root'); // app root
221
+ var toastRoot = root.children[0];
222
+ var fallbackParent = root || document.body;
207
223
  if (_fullscreen["default"].isFullscreen) {
224
+ // exit fullscreen
208
225
  _fullscreen["default"].exit();
226
+
227
+ // restore toast to its original parent (or fallback)
228
+ if (toastRoot) {
229
+ var parentToRestore = toastOriginalParent || fallbackParent;
230
+ // parentToRestore.appendChild(toastRoot);
231
+ safeAppend(parentToRestore, toastRoot);
232
+ }
209
233
  setTimeout(function () {
210
234
  if (right) {
211
235
  right.style.removeProperty('transition');
@@ -215,6 +239,14 @@ function toggleFullscreen(player) {
215
239
  }
216
240
  }, 300);
217
241
  } else {
242
+ // entering fullscreen
243
+ if (toastRoot && !toastOriginalParent) {
244
+ toastOriginalParent = toastRoot.parentNode || fallbackParent;
245
+ }
246
+ if (toastRoot && elem) {
247
+ // elem.appendChild(toastRoot);
248
+ safeAppend(elem, toastRoot);
249
+ }
218
250
  _fullscreen["default"].request(elem);
219
251
  }
220
252
  return {
@@ -225,11 +257,48 @@ function toggleFullscreen(player) {
225
257
  }
226
258
  };
227
259
  }
260
+
261
+ // <-- this return must be outside the if-block
228
262
  return {
229
263
  type: FULLSCREEN_CHANGE,
230
264
  isFullscreen: !player.isFullscreen
231
265
  };
232
266
  }
267
+
268
+ // export function toggleFullscreen(player) {
269
+ // if (fullscreen.enabled) {
270
+ // // var elem = document.getElementsByClassName('left-video-section')[0];
271
+ // var elem = document.getElementsByClassName('player-container')[0];
272
+ // const right = document.querySelector('.right-video-section');
273
+
274
+ // if (fullscreen.isFullscreen) {
275
+ // fullscreen.exit();
276
+ // setTimeout(() => {
277
+ // if (right) {
278
+ // right.style.removeProperty('transition');
279
+ // right.style.removeProperty('display');
280
+ // right.style.removeProperty('transform');
281
+ // right.style.removeProperty('opacity');
282
+ // }
283
+ // }, 300);
284
+ // } else {
285
+ // fullscreen.request(elem);
286
+ // }
287
+ // return {
288
+ // type: OPERATE,
289
+ // operation: {
290
+ // action: 'toggle-fullscreen',
291
+ // source: ''
292
+ // }
293
+ // };
294
+ // }
295
+
296
+ // return {
297
+ // type: FULLSCREEN_CHANGE,
298
+ // isFullscreen: !player.isFullscreen
299
+ // };
300
+ // }
301
+
233
302
  function toggleRightBar(player, showRightMenu) {
234
303
  var right = document.querySelector('.right-video-section');
235
304
  var sidebarWidth = right.offsetWidth; // actual width of sidebar
@@ -39,7 +39,9 @@ var propTypes = {
39
39
  var defaultProps = {
40
40
  height: 0
41
41
  };
42
- var RangeBlock = (0, _styledComponents["default"])('div')(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n position: absolute;\n right: -12px;\n height: 100%;\n overflow: hidden;\n .range {\n color: #aaaaaa;\n font-family: SFUIText-Medium;\n text-align: right;\n font-size: 8px;\n box-sizing: border-box;\n }\n"])));
42
+ var RangeBlock = (0, _styledComponents["default"])('div')(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n position: absolute;\n right: -12px;\n background-color: ", ";\n height: 100%;\n overflow: hidden;\n .range {\n color: #aaaaaa;\n font-family: SFUIText-Medium;\n text-align: right;\n font-size: 8px;\n box-sizing: border-box;\n }\n"])), function (props) {
43
+ return props.isFullscreen ? '#000' : 'unset';
44
+ });
43
45
  var MeterBlock = (0, _styledComponents["default"])('div')(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n width: 100%;\n height: 100%;\n position: absolute;\n left: 0;\n top: 0;\n display: flex;\n justify-content: space-evenly;\n align-items: center;\n .track-block {\n position: relative;\n width: 15px;\n height: 100%;\n overflow: visible;\n &.left-track,\n &.right-track {\n &:after {\n position: absolute;\n color: #aaaaaa;\n bottom: -12px;\n font-size: 10px;\n left: 50%;\n transform: translateX(-50%);\n font-family: SFUIText-Regular;\n }\n }\n &.left-track:after {\n content: 'L';\n }\n &.right-track:after {\n content: 'R';\n }\n }\n"])));
44
46
  var ColorMeter = (0, _styledComponents["default"])('div')(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n width: 100%;\n height: 100%;\n background: linear-gradient(\n to top,\n #00c8e7,\n #00e6b9 57%,\n #ff8d29 83%,\n #f6462c\n );\n position: absolute;\n left: 0;\n top: 0;\n z-index: 1;\n .stack-block {\n height: 2px;\n margin-bottom: 3px;\n background: #000000;\n }\n"])));
45
47
  var BlackMeter = (0, _styledComponents["default"])('div')(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n width: 100%;\n background: #000000;\n position: absolute;\n left: 0;\n top: 0;\n z-index: 1;\n height: 100%;\n transition: all 0.25s ease-in-out;\n -moz-transition: all 0.25s ease-in-out;\n -webkit-transition: all 0.25s ease-in-out;\n -ms-transition: all 0.25s ease-in-out;\n -o-transition: all 0.25s ease-in-out;\n .stack-block {\n height: 2px;\n margin-bottom: 3px;\n background: #304153;\n }\n"])));
@@ -290,7 +292,10 @@ var AudioMeter = exports["default"] = /*#__PURE__*/function (_Component) {
290
292
  rangeArray = _this$state.rangeArray,
291
293
  unitBlockHeight = _this$state.unitBlockHeight,
292
294
  audioPan = _this$state.audioPan;
293
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement(RangeBlock, null, rangeArray.map(function (range) {
295
+ var isFullscreen = this.props.isFullscreen;
296
+ return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement(RangeBlock, {
297
+ isFullscreen: isFullscreen
298
+ }, rangeArray.map(function (range) {
294
299
  return /*#__PURE__*/_react["default"].createElement("div", {
295
300
  key: 'range' + range,
296
301
  style: {
@@ -158,7 +158,7 @@ var defaultProps = {
158
158
  onVolumeChange: null
159
159
  };
160
160
  var PlayerBlock = _styledComponents["default"].div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n height: 100%;\n"])));
161
- var PlayerContainer = _styledComponents["default"].div(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n display: flex;\n justify-content: flex-start;\n background: #000000;\n .left-video-section {\n width: ", ";\n position: relative;\n }\n .audio-meter-block {\n position: relative;\n width: 0px;\n display: none;\n &.qc {\n width: 70px;\n display: block;\n }\n }\n .right-video-section {\n width: ", ";\n position: relative;\n }\n"])), function (props) {
161
+ var PlayerContainer = _styledComponents["default"].div(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n display: flex;\n justify-content: flex-start;\n background: #000000;\n .left-video-section {\n width: ", ";\n position: relative;\n }\n .audio-meter-block {\n position: relative;\n width: 0px;\n display: none;\n &.qc {\n width: 70px;\n display: block;\n }\n }\n .right-video-section {\n width: ", ";\n"])), function (props) {
162
162
  if (!props.isRightMenuVisible) {
163
163
  return '100%';
164
164
  }
@@ -168,7 +168,9 @@ var PlayerContainer = _styledComponents["default"].div(_templateObject2 || (_tem
168
168
  return '100%';
169
169
  }
170
170
  }, function (props) {
171
- if (props.playerType === 'qc') {
171
+ if (props.isFullscreen && props.playerType === 'qc') {
172
+ return 'calc(38.1% - 70px)';
173
+ } else if (props.playerType === 'qc') {
172
174
  return 'calc(36.33% - 70px)';
173
175
  } else {
174
176
  return '36.33%';
@@ -208,6 +210,42 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
208
210
  onRightMenuVisible(false);
209
211
  }
210
212
  });
213
+ // handleFullScreenChange() {
214
+ // this.actions.handleFullscreenChange(fullscreen.isFullscreen);
215
+ // }
216
+ _defineProperty(_this, "handleFullScreenChange", function () {
217
+ var onRightMenuVisible = _this.props.onRightMenuVisible;
218
+ var rightSectionRef = _this._rightSectionRef;
219
+ var playerHeader = (0, _reactDom.findDOMNode)(_this._playerHeader);
220
+ var headerHeight = playerHeader ? playerHeader.offsetHeight : 60;
221
+ var totalHeight = window.innerHeight;
222
+ var newHeight;
223
+ var isFS = _fullscreen["default"].isFullscreen;
224
+ _this.actions.handleFullscreenChange(isFS);
225
+ if (isFS) {
226
+ rightSectionRef.style.position = 'relative';
227
+ newHeight = totalHeight - headerHeight;
228
+ rightSectionRef.style.top = "".concat(headerHeight, "px");
229
+ rightSectionRef.style.height = "".concat(newHeight, "px");
230
+ }
231
+ // If exited fullscreen
232
+ if (!isFS) {
233
+ // Hide right sidebar
234
+ var right = document.querySelector('.right-video-section');
235
+ if (right) {
236
+ right.style.removeProperty('transition');
237
+ right.style.removeProperty('display');
238
+ right.style.removeProperty('transform');
239
+ right.style.removeProperty('opacity');
240
+ right.style.removeProperty('right');
241
+ }
242
+
243
+ // Reset UI state in parent
244
+ if (onRightMenuVisible) {
245
+ onRightMenuVisible(true);
246
+ }
247
+ }
248
+ });
211
249
  _this.controlsHideTimer = null;
212
250
  _this.meterHeight = 40;
213
251
  _this.video = null; // the Video component
@@ -455,7 +493,8 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
455
493
  key: "control-bar",
456
494
  pauseOnOutMarkerSelect: fullProps.pauseOnOutMarkerSelect,
457
495
  order: 5,
458
- playerType: fullProps.playerType
496
+ playerType: fullProps.playerType,
497
+ onRightMenuVisible: onRightMenuVisible
459
498
  }, this.props)), /*#__PURE__*/_react["default"].createElement(_Shortcut["default"], _extends({
460
499
  key: "shortcut",
461
500
  pauseOnOutMarkerSelect: fullProps.pauseOnOutMarkerSelect,
@@ -549,7 +588,8 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
549
588
  key: "control-bar",
550
589
  pauseOnOutMarkerSelect: fullProps.pauseOnOutMarkerSelect,
551
590
  order: 3,
552
- playerType: fullProps.playerType
591
+ playerType: fullProps.playerType,
592
+ onRightMenuVisible: onRightMenuVisible
553
593
  }, this.props)), /*#__PURE__*/_react["default"].createElement(_Shortcut["default"], _extends({
554
594
  key: "shortcut",
555
595
  pauseOnOutMarkerSelect: fullProps.pauseOnOutMarkerSelect,
@@ -735,6 +775,8 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
735
775
 
736
776
  //added for header height
737
777
  var headerHeight = playerHeader ? playerHeader.offsetHeight : 60;
778
+ var progressControlHeight = controlBar ? controlBar.offsetHeight : 0;
779
+ var controlBarHeight = progressControl ? progressControl.offsetHeight : 0;
738
780
  var totalHeight = window.innerHeight;
739
781
  var totalWidth = window.innerWidth;
740
782
  var newHeight;
@@ -796,7 +838,7 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
796
838
  availableWidth = totalWidth - rightSectionRef.offsetWidth;
797
839
  }
798
840
  // Calculate video dimensions based on available space
799
- videoHeight = totalHeight - headerHeight - progressControl.offsetHeight - controlBar.offsetHeight;
841
+ videoHeight = totalHeight - headerHeight - progressControlHeight - controlBarHeight;
800
842
  videoWidth = videoHeight * (16 / 9);
801
843
  // If video width exceeds available width, recalculate based on width
802
844
  if (videoWidth > availableWidth) {
@@ -847,11 +889,6 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
847
889
  }
848
890
  // this.video.handleResize();
849
891
  }
850
- }, {
851
- key: "handleFullScreenChange",
852
- value: function handleFullScreenChange() {
853
- this.actions.handleFullscreenChange(_fullscreen["default"].isFullscreen);
854
- }
855
892
  }, {
856
893
  key: "handleStateChange",
857
894
  value: function handleStateChange(state, prevState) {
@@ -868,14 +905,19 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
868
905
  }, {
869
906
  key: "handleBlur",
870
907
  value: function handleBlur() {
908
+ var _this$manager$getStat3 = this.manager.getState(),
909
+ player = _this$manager$getStat3.player;
910
+ if (player.isFullscreen) return;
871
911
  this.actions.activate(false);
872
912
  }
873
913
  }, {
874
914
  key: "render",
875
915
  value: function render() {
876
- var _this5 = this;
877
- var _this$manager$getStat3 = this.manager.getState(),
878
- player = _this$manager$getStat3.player;
916
+ var _this5 = this,
917
+ _props$player,
918
+ _props$player2;
919
+ var _this$manager$getStat4 = this.manager.getState(),
920
+ player = _this$manager$getStat4.player;
879
921
  var props = _objectSpread(_objectSpread({}, this.props), {}, {
880
922
  player: player,
881
923
  actions: this.actions,
@@ -905,7 +947,8 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
905
947
  }
906
948
  }, props, {
907
949
  hasRightSection: !!rightSection,
908
- isRightMenuVisible: isRightMenuVisible
950
+ isRightMenuVisible: isRightMenuVisible,
951
+ isFullscreen: (_props$player = props.player) === null || _props$player === void 0 ? void 0 : _props$player.isFullscreen
909
952
  }), /*#__PURE__*/_react["default"].createElement("div", {
910
953
  className: "left-video-section",
911
954
  ref: function ref(leftSectionRef) {
@@ -924,7 +967,8 @@ var Player = exports["default"] = /*#__PURE__*/function (_Component) {
924
967
  active: true
925
968
  }, /*#__PURE__*/_react["default"].createElement(_AudioMeter["default"], {
926
969
  player: props.player,
927
- height: this.meterHeight
970
+ height: this.meterHeight,
971
+ isFullscreen: (_props$player2 = props.player) === null || _props$player2 === void 0 ? void 0 : _props$player2.isFullscreen
928
972
  }))), rightSection ? /*#__PURE__*/_react["default"].createElement("div", {
929
973
  className: "right-video-section",
930
974
  ref: function ref(rightSectionRef) {
@@ -355,7 +355,7 @@ var PlayerHeader = exports["default"] = /*#__PURE__*/function (_Component) {
355
355
  onClick: function onClick() {
356
356
  return _this2.openQCReport();
357
357
  }
358
- }, this.props)), playerType !== 'default' && playerType !== 'clipping_default' ? /*#__PURE__*/_react["default"].createElement(_components.Button, _extends({
358
+ }, this.props)), !isFullscreen && playerType !== 'default' && playerType !== 'clipping_default' ? /*#__PURE__*/_react["default"].createElement(_components.Button, _extends({
359
359
  display: "rounded",
360
360
  appearance: "cta",
361
361
  icon: playerType === 'dubbing_review' ? 'access_dubbing_studio' : playerType,
@@ -91,7 +91,12 @@ var MarkInControl = exports["default"] = /*#__PURE__*/function (_Component) {
91
91
  onAddMarker = _this$props2.onAddMarker,
92
92
  frameRate = _this$props2.frameRate,
93
93
  playerType = _this$props2.playerType,
94
- enablePlayerActions = _this$props2.enablePlayerActions;
94
+ enablePlayerActions = _this$props2.enablePlayerActions,
95
+ onRightMenuVisible = _this$props2.onRightMenuVisible;
96
+ if (player.isFullscreen) {
97
+ actions.toggleRightBar(player, true);
98
+ onRightMenuVisible(true);
99
+ }
95
100
  if (["snp_edit", "promo_review", "pgm_edit", "dubbing_review"].includes(playerType) || enablePlayerActions.includes('single_annotation')) {
96
101
  var currentAdjustedTime = (0, _utils.handleAdjustingVideoAsPerFrame)(player.currentTime, frameRate);
97
102
  var data = {
@@ -98,7 +98,8 @@ var MarkOutControl = exports["default"] = /*#__PURE__*/function (_Component) {
98
98
  onMarkerSelect = _this$props2.onMarkerSelect,
99
99
  onAddMarker = _this$props2.onAddMarker,
100
100
  frameRate = _this$props2.frameRate,
101
- pauseOnOutMarkerSelect = _this$props2.pauseOnOutMarkerSelect;
101
+ pauseOnOutMarkerSelect = _this$props2.pauseOnOutMarkerSelect,
102
+ onRightMenuVisible = _this$props2.onRightMenuVisible;
102
103
  if (leftMarker > -1 && player.currentTime > leftMarker) {
103
104
  // actions.handleMarkerPointChange('add', 'right', player.currentTime);
104
105
  //Commented for CN-632.
@@ -106,6 +107,10 @@ var MarkOutControl = exports["default"] = /*#__PURE__*/function (_Component) {
106
107
  // onMarkerSelect(leftMarker, player.currentTime);
107
108
  // }
108
109
  // actions.handleMarkerPointChange('create');
110
+ if (player.isFullscreen) {
111
+ actions.toggleRightBar(player, true);
112
+ onRightMenuVisible(true);
113
+ }
109
114
  if (pauseOnOutMarkerSelect && !player.paused) {
110
115
  actions.pause({
111
116
  action: 'pause',
@@ -57,7 +57,8 @@ function MarkingControl(_ref) {
57
57
  theme = _ref.theme,
58
58
  enablePlayerActions = _ref.enablePlayerActions,
59
59
  pauseOnOutMarkerSelect = _ref.pauseOnOutMarkerSelect,
60
- timeCodeFormat = _ref.timeCodeFormat;
60
+ timeCodeFormat = _ref.timeCodeFormat,
61
+ onRightMenuVisible = _ref.onRightMenuVisible;
61
62
  return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, playerType !== 'panel' && playerType !== 'default' && playerType !== 'clipping_default' ? /*#__PURE__*/_react["default"].createElement(MarkingBlock, {
62
63
  theme: theme
63
64
  }, (!((playerSelectedMarker === null || playerSelectedMarker === void 0 ? void 0 : playerSelectedMarker.leftMarker) > -1) || !((playerSelectedMarker === null || playerSelectedMarker === void 0 ? void 0 : playerSelectedMarker.rightMarker) > -1)) && playerType !== 'panel' && playerType !== 'default' && playerType !== 'clipping_default' && !playerReadOnlyMode && !disablePlayerActions.includes('marking_controls') ? /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, /*#__PURE__*/_react["default"].createElement(_MarkInControl["default"], {
@@ -69,7 +70,8 @@ function MarkingControl(_ref) {
69
70
  allowMarkerOverlap: allowMarkerOverlap,
70
71
  onAddMarker: onAddMarker,
71
72
  enablePlayerActions: enablePlayerActions,
72
- playerType: playerType
73
+ playerType: playerType,
74
+ onRightMenuVisible: onRightMenuVisible
73
75
  }), /*#__PURE__*/_react["default"].createElement(_MarkOutControl["default"], {
74
76
  theme: theme,
75
77
  leftMarker: playerSelectedMarker === null || playerSelectedMarker === void 0 ? void 0 : playerSelectedMarker.leftMarker,
@@ -81,7 +83,8 @@ function MarkingControl(_ref) {
81
83
  onMarkerSelect: onMarkerSelect,
82
84
  allowMarkerOverlap: allowMarkerOverlap,
83
85
  onAddMarker: onAddMarker,
84
- pauseOnOutMarkerSelect: pauseOnOutMarkerSelect
86
+ pauseOnOutMarkerSelect: pauseOnOutMarkerSelect,
87
+ onRightMenuVisible: onRightMenuVisible
85
88
  })) : null, (playerSelectedMarker === null || playerSelectedMarker === void 0 ? void 0 : playerSelectedMarker.leftMarker) > -1 || (playerSelectedMarker === null || playerSelectedMarker === void 0 ? void 0 : playerSelectedMarker.rightMarker) > -1 ? /*#__PURE__*/_react["default"].createElement(_MarkingDuration["default"], {
86
89
  theme: theme,
87
90
  leftMarker: playerSelectedMarker === null || playerSelectedMarker === void 0 ? void 0 : playerSelectedMarker.leftMarker,
@@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", {
7
7
  exports["default"] = void 0;
8
8
  var _react = _interopRequireWildcard(require("react"));
9
9
  var _styledComponents = _interopRequireDefault(require("styled-components"));
10
+ var _components = require("@desynova-digital/components");
10
11
  var _templateObject, _templateObject2, _templateObject3, _templateObject4, _templateObject5, _templateObject6, _templateObject7, _templateObject8, _templateObject9, _templateObject10;
11
12
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
12
13
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
@@ -22,67 +23,83 @@ function _taggedTemplateLiteral(e, t) { return t || (t = e.slice(0)), Object.fre
22
23
  TIMELINE MAIN WRAPPER
23
24
  ---------------------------------------------------------- */
24
25
  var MarkerTimeline = _styledComponents["default"].div(_templateObject || (_templateObject = _taggedTemplateLiteral(["\n position: relative;\n width: 100%;\n height: 11px;\n"])));
26
+
25
27
  /* ----------------------------------------------------------
26
- MARKER DOT (start dot)
28
+ MARKER DOT
27
29
  ---------------------------------------------------------- */
28
- var MarkerDot = _styledComponents["default"].div(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: -6px;\n transform: translateX(-50%);\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #47d2c7;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #0a0f18;\n font-weight: 600;\n font-size: 10px;\n cursor: pointer;\n z-index: 9000;\n\n &:hover {\n background: #3bbfb6;\n }\n"])));
30
+ var MarkerDot = _styledComponents["default"].div(_templateObject2 || (_templateObject2 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: -6px;\n transform: translateX(-50%);\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #47d2c7;\n display: flex;\n align-items: center;\n justify-content: center;\n color: #0a0f18;\n font-weight: 600;\n font-size: 10px;\n cursor: pointer;\n z-index: ", ";\n pointer-events: auto;\n\n /* invisible hit-box (prevents overlap hover loss) */\n &::before {\n content: \"\";\n position: absolute;\n width: 32px;\n height: 32px;\n top: -6px;\n left: -6px;\n }\n\n &:hover {\n background: #3bbfb6;\n }\n"])), function (p) {
31
+ return p.isHovered ? 99999 : 9000;
32
+ });
33
+
29
34
  /* ----------------------------------------------------------
30
- END MARKER DOT (VISIBLE ONLY ON HOVER)
35
+ END MARKER DOT
31
36
  ---------------------------------------------------------- */
32
- var EndMarkerDot = _styledComponents["default"].div(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: -6px;\n transform: translateX(-50%);\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #2ee8dd;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9000;\n opacity: 0;\n transition: opacity 0.15s ease-out;\n cursor: pointer;\n\n &::after {\n content: '';\n width: 10px;\n height: 10px;\n background: white;\n border-radius: 50%;\n }\n"])));
37
+ var EndMarkerDot = _styledComponents["default"].div(_templateObject3 || (_templateObject3 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: -6px;\n transform: translateX(-50%);\n width: 20px;\n height: 20px;\n border-radius: 50%;\n background: #2ee8dd;\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 9000;\n opacity: 0;\n transition: opacity 0.15s ease-out;\n\n &::after {\n content: '';\n width: 10px;\n height: 10px;\n background: white;\n border-radius: 50%;\n }\n"])));
38
+
33
39
  /* ----------------------------------------------------------
34
- HORIZONTAL SEGMENT LINE
40
+ SEGMENT LINE
35
41
  ---------------------------------------------------------- */
36
- var MarkerLine = _styledComponents["default"].div(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: 4px;\n height: 3px;\n background: #47d2c7;\n border-radius: 2px;\n z-index: 8000;\n\n opacity: 0;\n transition: opacity 0.15s ease-out;\n"])));
42
+ var MarkerLine = _styledComponents["default"].div(_templateObject4 || (_templateObject4 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: 4px;\n height: 3px;\n background: #47d2c7;\n border-radius: 2px;\n opacity: 0;\n transition: opacity 0.15s ease-out;\n"])));
37
43
 
38
44
  /* ----------------------------------------------------------
39
45
  HOVER BOX
40
46
  ---------------------------------------------------------- */
41
- var HoverBox = _styledComponents["default"].div(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: 30px;\n left: var(--left);\n transform: translateX(-50%);\n // width: auto;\n min-width: 150px;\n max-width: 220px;\n max-height: 400px;\n background: #303f51;\n backdrop-filter: blur(12px);\n border-radius: 10px;\n padding: ", ";\n color: white;\n z-index: 999999;\n box-shadow: 0 6px 22px rgba(0, 0, 0, 0.32);\n font-family: 'SF Pro Text';\n overflow-y: auto;\n animation: fadeInBox 0.18s ease-out;\n"])), function (props) {
42
- return props.commentLength > 1 ? '0px 9px 8px 4px' : '10px 9px 8px 4px';
47
+ var HoverBox = _styledComponents["default"].div(_templateObject5 || (_templateObject5 = _taggedTemplateLiteral(["\n position: absolute;\n bottom: 30px;\n background: #303f51;\n backdrop-filter: blur(12px);\n border-radius: 10px;\n padding: ", ";\n color: white;\n z-index: 999999;\n box-shadow: 0 6px 22px rgba(0,0,0,0.32);\n overflow-y: auto;\n animation: fadeInBox 0.18s ease-out;\n min-width: 150px;\n max-width: 240px;\n max-height: 400px;\n"])), function (p) {
48
+ return p.commentLength > 1 ? "0px 9px 8px 4px" : "10px 9px 8px 4px";
43
49
  });
44
- var HoverHeader = _styledComponents["default"].div(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n width: calc(100% + 18px);\n position: relative;\n left: -9px;\n background: #3e6673;\n color: #46d7ff;\n font-size: 12px;\n font-weight: 700;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n padding: 10px 12px;\n border-top-left-radius: 10px;\n border-top-right-radius: 10px;\n margin-bottom: 8px;\n"])));
45
- var HoverComment = _styledComponents["default"].div(_templateObject7 || (_templateObject7 = _taggedTemplateLiteral(["\n padding: 10px 0;\n position: relative;\n border-radius: 5px;\n transition: background 0.15s ease, transform 0.15s ease;\n &:hover {\n background: rgba(255, 255, 255, 0.08); /* subtle highlight */\n transform: translateX(2px); /* slight movement */\n }\n &:not(:last-child)::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: -9px;\n width: calc(100% + 18px);\n height: 1px;\n background: rgba(255, 255, 255, 0.12);\n }\n"])));
50
+ var HoverHeader = _styledComponents["default"].div(_templateObject6 || (_templateObject6 = _taggedTemplateLiteral(["\n width: calc(100% + 18px);\n position: relative;\n left: -9px;\n background: #3e6673;\n color: #46d7ff;\n font-size: 12px;\n font-weight: 700;\n padding: 10px 12px;\n border-top-left-radius: 10px;\n border-top-right-radius: 10px;\n margin-bottom: 8px;\n"])));
51
+ var HoverComment = _styledComponents["default"].div(_templateObject7 || (_templateObject7 = _taggedTemplateLiteral(["\n padding: 10px 0;\n position: relative;\n border-radius: 5px;\n transition: background 0.15s ease, transform 0.15s ease;\n &:hover {\n background: rgba(255,255,255,0.08);\n transform: translateX(2px);\n }\n &:not(:last-child)::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: -9px;\n width: calc(100% + 18px);\n height: 1px;\n background: rgba(255,255,255,0.12);\n }\n"])));
46
52
  var HoverName = _styledComponents["default"].div(_templateObject8 || (_templateObject8 = _taggedTemplateLiteral(["\n font-size: 13px;\n font-weight: 700;\n color: #afb2ba;\n margin-bottom: 8px;\n"])));
47
53
  var HoverTime = _styledComponents["default"].div(_templateObject9 || (_templateObject9 = _taggedTemplateLiteral(["\n font-size: 11px;\n color: #afb2ba;\n margin-bottom: 5px;\n"])));
48
- var HoverText = _styledComponents["default"].div(_templateObject10 || (_templateObject10 = _taggedTemplateLiteral(["\n font-size: 14px;\n font-family: 'SF Pro Text';\n color: #fff;\n line-height: 1.35;\n display: -webkit-box;\n -webkit-line-clamp: 4;\n -webkit-box-orient: vertical;\n overflow: hidden;\n font-weight: 300;\n line-height: 21px;\n font-style: normal;\n"])));
54
+ var HoverText = _styledComponents["default"].div(_templateObject10 || (_templateObject10 = _taggedTemplateLiteral(["\n font-size: 14px;\n color: #fff;\n line-height: 21px;\n overflow: hidden;\n"])));
49
55
 
50
56
  /* ----------------------------------------------------------
51
- SAFE LEFT POSITION
57
+ UTILITIES (FIXED)
52
58
  ---------------------------------------------------------- */
53
- var getSafeLeft = function getSafeLeft(percent) {
54
- if (percent < 3) return 3;
55
- if (percent > 95) return 95;
56
- return percent;
59
+ var clampPx = function clampPx(px, containerWidth) {
60
+ var SAFE = 10;
61
+ if (px <= SAFE) return SAFE;
62
+ if (px >= containerWidth - SAFE) return containerWidth - SAFE;
63
+ return px;
64
+ };
65
+ var getMarkerPercent = function getMarkerPercent(time, duration, zoom) {
66
+ if (!duration) return 0;
67
+ var pct = time / duration;
68
+ return pct * 100 * (zoom > 0 ? zoom * 20 : 1);
69
+ };
70
+ var getSafeLeftPx = function getSafeLeftPx(percent, containerWidth) {
71
+ if (!containerWidth) return "".concat(percent, "%");
72
+ var px = percent / 100 * containerWidth;
73
+ return "".concat(clampPx(px, containerWidth), "px");
57
74
  };
58
75
 
59
76
  /* ----------------------------------------------------------
60
- TIME PERCENT
77
+ HOVER BOX CLAMP
61
78
  ---------------------------------------------------------- */
62
- var getMarkerPercent = function getMarkerPercent(time, duration, zoom) {
63
- if (!duration || duration <= 0) return 0;
64
- var percent = time / duration;
65
- percent = percent >= 1 ? 1 : percent;
66
- if (zoom > 0) return percent * 100 * zoom * 20;
67
- return percent * 100;
79
+ var clampHoverBoxLeft = function clampHoverBoxLeft(rawLeftPx, boxWidth, containerWidth) {
80
+ var SAFE = 10;
81
+ var max = containerWidth - boxWidth - SAFE;
82
+ return Math.max(SAFE, Math.min(rawLeftPx, max));
68
83
  };
69
84
 
70
85
  /* ----------------------------------------------------------
71
86
  MAIN COMPONENT
72
87
  ---------------------------------------------------------- */
73
- var RenderCommentMarkers = function RenderCommentMarkers(props) {
74
- var _props$data = props.data,
75
- data = _props$data === void 0 ? [] : _props$data,
76
- _props$duration = props.duration,
77
- duration = _props$duration === void 0 ? 100.0 : _props$duration,
78
- _props$zoom = props.zoom,
79
- zoom = _props$zoom === void 0 ? 0 : _props$zoom,
80
- playerType = props.playerType,
81
- onSegmentClick = props.onSegmentClick,
82
- onRightMenuVisible = props.onRightMenuVisible,
83
- actions = props.actions,
84
- player = props.player;
85
- if (!['snp_edit', 'pgm_edit'].includes(playerType)) return null;
88
+ var RenderCommentMarkers = function RenderCommentMarkers(_ref) {
89
+ var _containerRef$current;
90
+ var _ref$data = _ref.data,
91
+ data = _ref$data === void 0 ? [] : _ref$data,
92
+ _ref$duration = _ref.duration,
93
+ duration = _ref$duration === void 0 ? 100 : _ref$duration,
94
+ _ref$zoom = _ref.zoom,
95
+ zoom = _ref$zoom === void 0 ? 0 : _ref$zoom,
96
+ playerType = _ref.playerType,
97
+ onSegmentClick = _ref.onSegmentClick,
98
+ onRightMenuVisible = _ref.onRightMenuVisible,
99
+ actions = _ref.actions,
100
+ player = _ref.player,
101
+ frameRate = _ref.frameRate;
102
+ if (!["snp_edit", "pgm_edit"].includes(playerType)) return null;
86
103
  var _useState = (0, _react.useState)(null),
87
104
  _useState2 = _slicedToArray(_useState, 2),
88
105
  hovered = _useState2[0],
@@ -91,90 +108,80 @@ var RenderCommentMarkers = function RenderCommentMarkers(props) {
91
108
  _useState4 = _slicedToArray(_useState3, 2),
92
109
  hoverBoxHold = _useState4[0],
93
110
  setHoverBoxHold = _useState4[1];
94
- var _useState5 = (0, _react.useState)(null),
95
- _useState6 = _slicedToArray(_useState5, 2),
96
- selectedComment = _useState6[0],
97
- setSelectedComment = _useState6[1];
111
+ var containerRef = (0, _react.useRef)(null);
98
112
  var hideTimer = (0, _react.useRef)(null);
99
113
  var startHideTimer = function startHideTimer() {
100
- if (hideTimer.current) clearTimeout(hideTimer.current);
114
+ clearTimeout(hideTimer.current);
101
115
  hideTimer.current = setTimeout(function () {
102
116
  setHoverBoxHold(false);
103
117
  setHovered(null);
104
- setSelectedComment(null);
105
- }, 2000);
118
+ }, 1500);
106
119
  };
107
- var handleLeaveMarker = function handleLeaveMarker() {
108
- if (!hoverBoxHold) startHideTimer();
109
- };
110
- if (!Array.isArray(data) || data.length === 0) return null;
120
+ if (!data.length) return null;
111
121
  var grouped = data.reduce(function (acc, item) {
112
122
  var key = item.value.in_time;
113
- if (!acc[key]) acc[key] = [];
114
- acc[key].push(item);
123
+ (acc[key] = acc[key] || []).push(item);
115
124
  return acc;
116
125
  }, {});
117
- return /*#__PURE__*/_react["default"].createElement(MarkerTimeline, null, Object.entries(grouped).map(function (_ref) {
126
+ var containerWidth = (_containerRef$current = containerRef.current) === null || _containerRef$current === void 0 ? void 0 : _containerRef$current.offsetWidth;
127
+ return /*#__PURE__*/_react["default"].createElement(MarkerTimeline, {
128
+ ref: containerRef
129
+ }, Object.entries(grouped).map(function (_ref2) {
118
130
  var _comments$;
119
- var _ref2 = _slicedToArray(_ref, 2),
120
- time = _ref2[0],
121
- comments = _ref2[1];
131
+ var _ref3 = _slicedToArray(_ref2, 2),
132
+ time = _ref3[0],
133
+ comments = _ref3[1];
122
134
  var start = comments[0].value.in_time;
123
135
  var end = comments[0].value.out_time;
124
- var startPercent = getMarkerPercent(start, duration, zoom);
125
- var endPercent = end ? getMarkerPercent(end, duration, zoom) : null;
126
-
127
- // --- NEW: detect first & last markers ---
128
- var times = Object.keys(grouped).map(Number).sort(function (a, b) {
129
- return a - b;
130
- });
131
- var firstTime = times[0];
132
- var lastTime = times[times.length - 1];
133
- var isFirst = Number(time) === firstTime;
134
- var isLast = Number(time) === lastTime;
135
-
136
- // --- NEW: apply safe-left/right only to first & last ---
137
- var safeStart = isFirst ? getSafeLeft(startPercent) : startPercent;
138
- var safeEnd = isLast && endPercent !== null ? getSafeLeft(endPercent) : endPercent;
139
- var initials = ((_comments$ = comments[0]) === null || _comments$ === void 0 || (_comments$ = _comments$.value) === null || _comments$ === void 0 || (_comments$ = _comments$.created_by) === null || _comments$ === void 0 || (_comments$ = _comments$.name) === null || _comments$ === void 0 || (_comments$ = _comments$.split(' ')) === null || _comments$ === void 0 || (_comments$ = _comments$.map(function (n) {
136
+ var startPct = getMarkerPercent(start, duration, zoom);
137
+ var endPct = end ? getMarkerPercent(end, duration, zoom) : null;
138
+ var safeStart = getSafeLeftPx(startPct, containerWidth);
139
+ var safeEnd = endPct !== null ? getSafeLeftPx(endPct, containerWidth) : null;
140
+ var initials = ((_comments$ = comments[0]) === null || _comments$ === void 0 || (_comments$ = _comments$.value) === null || _comments$ === void 0 || (_comments$ = _comments$.created_by) === null || _comments$ === void 0 || (_comments$ = _comments$.name) === null || _comments$ === void 0 || (_comments$ = _comments$.split(" ")) === null || _comments$ === void 0 || (_comments$ = _comments$.map(function (n) {
140
141
  return n[0];
141
- })) === null || _comments$ === void 0 || (_comments$ = _comments$.join('')) === null || _comments$ === void 0 || (_comments$ = _comments$.slice(0, 2)) === null || _comments$ === void 0 ? void 0 : _comments$.toUpperCase()) || 'CM';
142
- var displayLabel = comments.length > 1 ? comments.length : initials;
142
+ })) === null || _comments$ === void 0 || (_comments$ = _comments$.join("")) === null || _comments$ === void 0 || (_comments$ = _comments$.slice(0, 2)) === null || _comments$ === void 0 ? void 0 : _comments$.toUpperCase()) || "CM";
143
+ var label = comments.length > 1 ? comments.length : initials;
144
+ var isHovered = hovered === time;
143
145
  return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, {
144
146
  key: time
145
- }, endPercent !== null && /*#__PURE__*/_react["default"].createElement(MarkerLine, {
147
+ }, endPct !== null && /*#__PURE__*/_react["default"].createElement(MarkerLine, {
146
148
  style: {
147
- left: "".concat(safeStart, "%"),
148
- width: "calc(".concat(safeEnd - safeStart, "% )"),
149
- opacity: hovered === time ? 1 : 0
149
+ left: safeStart,
150
+ width: "calc(".concat(endPct - startPct, "% )"),
151
+ opacity: isHovered ? 1 : 0
150
152
  }
151
153
  }), /*#__PURE__*/_react["default"].createElement(MarkerDot, {
152
154
  style: {
153
- left: "".concat(safeStart, "%")
155
+ left: safeStart
154
156
  },
157
+ isHovered: isHovered,
155
158
  onMouseEnter: function onMouseEnter() {
156
159
  return setHovered(time);
157
160
  },
158
- onMouseLeave: handleLeaveMarker,
161
+ onMouseLeave: function onMouseLeave() {
162
+ return !hoverBoxHold && startHideTimer();
163
+ },
159
164
  onClick: function onClick(e) {
160
165
  e.stopPropagation();
161
166
  setHoverBoxHold(true);
162
167
  setHovered(time);
163
- setSelectedComment(comments);
164
168
  }
165
- }, displayLabel), endPercent !== null && /*#__PURE__*/_react["default"].createElement(EndMarkerDot, {
169
+ }, label), endPct !== null && /*#__PURE__*/_react["default"].createElement(EndMarkerDot, {
166
170
  style: {
167
- left: "".concat(safeEnd, "%"),
168
- opacity: hovered === time ? 1 : 0
171
+ left: safeEnd,
172
+ opacity: isHovered ? 1 : 0
169
173
  }
170
- }), hovered === time && /*#__PURE__*/_react["default"].createElement(HoverBox, {
174
+ }), isHovered && /*#__PURE__*/_react["default"].createElement(HoverBox, {
171
175
  commentLength: comments.length,
172
- tabIndex: 0,
173
- style: {
174
- '--left': "".concat(getSafeLeft(safeStart), "%") // <-- updated for first/last
176
+ ref: function ref(el) {
177
+ if (el && containerWidth) {
178
+ var rawPx = parseFloat(safeStart);
179
+ var clamped = clampHoverBoxLeft(rawPx, el.offsetWidth, containerWidth);
180
+ el.style.left = "".concat(clamped, "px");
181
+ }
175
182
  },
176
183
  onMouseEnter: function onMouseEnter() {
177
- if (hideTimer.current) clearTimeout(hideTimer.current);
184
+ clearTimeout(hideTimer.current);
178
185
  setHoverBoxHold(true);
179
186
  },
180
187
  onMouseLeave: function onMouseLeave() {
@@ -183,16 +190,24 @@ var RenderCommentMarkers = function RenderCommentMarkers(props) {
183
190
  }
184
191
  }, comments.length > 1 && /*#__PURE__*/_react["default"].createElement(HoverHeader, null, comments.length, " COMMENTS"), comments.map(function (c) {
185
192
  var _c$value$created_by;
193
+ var selectedFormat = localStorage.getItem("timeCodeFormat");
186
194
  return /*#__PURE__*/_react["default"].createElement(HoverComment, {
187
195
  key: c.id,
188
196
  onClick: function onClick(e) {
189
197
  e.stopPropagation();
190
- setSelectedComment(c);
191
198
  onSegmentClick(c.value.in_time, c.value.out_time, false);
192
199
  onRightMenuVisible(true);
193
200
  actions.toggleRightBar(player, true);
194
201
  }
195
- }, /*#__PURE__*/_react["default"].createElement(HoverName, null, (_c$value$created_by = c.value.created_by) === null || _c$value$created_by === void 0 || (_c$value$created_by = _c$value$created_by.name) === null || _c$value$created_by === void 0 ? void 0 : _c$value$created_by.toUpperCase()), /*#__PURE__*/_react["default"].createElement(HoverTime, null, c.value.in_timecode, c.value.out_timecode ? " - ".concat(c.value.out_timecode) : ''), /*#__PURE__*/_react["default"].createElement(HoverText, null, c.value.remark || c.value.sub_title || c.value.title || '—'));
202
+ }, /*#__PURE__*/_react["default"].createElement(HoverName, null, (_c$value$created_by = c.value.created_by) === null || _c$value$created_by === void 0 || (_c$value$created_by = _c$value$created_by.name) === null || _c$value$created_by === void 0 ? void 0 : _c$value$created_by.toUpperCase()), /*#__PURE__*/_react["default"].createElement(HoverTime, null, /*#__PURE__*/_react["default"].createElement(_components.TimeCodeDisplay, {
203
+ timecode: c.value.in_timecode,
204
+ selectedTimecodeFormat: selectedFormat,
205
+ fps: frameRate
206
+ }), c.value.out_timecode && /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, " - ", /*#__PURE__*/_react["default"].createElement(_components.TimeCodeDisplay, {
207
+ timecode: c.value.out_timecode,
208
+ selectedTimecodeFormat: selectedFormat,
209
+ fps: frameRate
210
+ }))), /*#__PURE__*/_react["default"].createElement(HoverText, null, c.value.remark || c.value.sub_title || c.value.title || "—"));
196
211
  })));
197
212
  }));
198
213
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@desynova-digital/player",
3
- "version": "4.0.89",
3
+ "version": "4.0.91",
4
4
  "description": "Video Player Package for Contido Application",
5
5
  "main": "index.js",
6
6
  "scripts": {