@rolster/react-components 19.11.0 → 19.12.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.
@@ -3823,11 +3823,20 @@ const RlsModal = require$$0.memo(RlsModalComponent);
3823
3823
  function formatTime(value) {
3824
3824
  return String(value).padStart(2, '0');
3825
3825
  }
3826
+ function pointerIsInsideTick({ clientX, clientY }, tick) {
3827
+ const { left, top, width, height } = tick.getBoundingClientRect();
3828
+ const distanceX = clientX - (left + width / 2);
3829
+ const distanceY = clientY - (top + height / 2);
3830
+ const radius = Math.min(width, height) / 2;
3831
+ return distanceX ** 2 + distanceY ** 2 <= radius ** 2;
3832
+ }
3826
3833
  const CLOCK_VALUES = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
3834
+ const CLOCK_HOURS = 12;
3835
+ const CLOCK_MINUTES = 60;
3827
3836
  const RADIUS = 48;
3828
3837
  const DIAL_RADIUS = 60;
3829
3838
  const TICK_RADIUS = 7;
3830
- function RlsPickerClockTick({ onValue, selectionIsHours, value }) {
3839
+ function RlsPickerClockTick({ selectionIsHours, value }) {
3831
3840
  const styleTick = require$$0.useMemo(() => {
3832
3841
  const radian = (value / 6) * Math.PI;
3833
3842
  const x = Math.sin(radian) * RADIUS;
@@ -3837,20 +3846,13 @@ function RlsPickerClockTick({ onValue, selectionIsHours, value }) {
3837
3846
  top: `${DIAL_RADIUS - y - TICK_RADIUS - 1}rem`
3838
3847
  };
3839
3848
  }, []);
3840
- const label = require$$0.useMemo(() => {
3849
+ const tickValue = require$$0.useMemo(() => {
3841
3850
  if (selectionIsHours) {
3842
- return formatTime(value);
3843
- }
3844
- if (value === 12) {
3845
- return formatTime(0);
3851
+ return value;
3846
3852
  }
3847
- return formatTime(value * 5);
3853
+ return value === CLOCK_HOURS ? 0 : value * 5;
3848
3854
  }, [selectionIsHours]);
3849
- const onClick = require$$0.useCallback((event) => {
3850
- event.preventDefault();
3851
- onValue(value);
3852
- }, [onValue]);
3853
- return (jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__tick", style: styleTick, onClick: onClick, children: label }));
3855
+ return (jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__tick", style: styleTick, "data-value": tickValue, children: formatTime(tickValue) }));
3854
3856
  }
3855
3857
  function RlsPickerClockComponent({ formControl, onListener, rlsTheme, time }) {
3856
3858
  const timeInitial = require$$0.useMemo(() => {
@@ -3923,22 +3925,6 @@ function RlsPickerClockComponent({ formControl, onListener, rlsTheme, time }) {
3923
3925
  }
3924
3926
  changeIsInternal.current = false;
3925
3927
  }, [formControl?.value]);
3926
- const refreshComponent = require$$0.useCallback((clientX, clientY) => {
3927
- const rectangle = plateElement.current.getBoundingClientRect();
3928
- const centerX = rectangle.left + rectangle.width / 2;
3929
- const centerY = rectangle.top + rectangle.height / 2;
3930
- const positionX = clientX - centerX;
3931
- const positionY = clientY - centerY;
3932
- const angle = Math.atan2(-positionX, positionY) + Math.PI;
3933
- const value = Math.round(angle / radianUnit);
3934
- refreshClock(value);
3935
- if (selectionIsHours) {
3936
- setHour(value === 0 ? 12 : value);
3937
- }
3938
- else {
3939
- setMinute(value);
3940
- }
3941
- }, [selectionIsHours, radianUnit]);
3942
3928
  const refreshClock = require$$0.useCallback((value) => {
3943
3929
  const angle = value * radianUnit;
3944
3930
  const x2 = Math.sin(angle) * (RADIUS - TICK_RADIUS);
@@ -3954,6 +3940,27 @@ function RlsPickerClockComponent({ formControl, onListener, rlsTheme, time }) {
3954
3940
  pointElement.current.style.visibility =
3955
3941
  selectionIsHours || value % 5 === 0 ? 'hidden' : 'visible';
3956
3942
  }, [selectionIsHours, radianUnit]);
3943
+ const selectValue = require$$0.useCallback((value) => {
3944
+ refreshClock(value);
3945
+ if (selectionIsHours) {
3946
+ setHour(value === 0 ? CLOCK_HOURS : value);
3947
+ }
3948
+ else {
3949
+ setMinute(value);
3950
+ }
3951
+ }, [selectionIsHours, refreshClock]);
3952
+ const selectFromPosition = require$$0.useCallback((clientX, clientY) => {
3953
+ const rectangle = plateElement.current.getBoundingClientRect();
3954
+ const centerX = rectangle.left + rectangle.width / 2;
3955
+ const centerY = rectangle.top + rectangle.height / 2;
3956
+ const positionX = clientX - centerX;
3957
+ const positionY = clientY - centerY;
3958
+ // Angle in [0, 2π) measured clockwise from 12 o'clock
3959
+ const angle = Math.atan2(-positionX, positionY) + Math.PI;
3960
+ const steps = selectionIsHours ? CLOCK_HOURS : CLOCK_MINUTES;
3961
+ // Modulo keeps the last half step before 12 o'clock as 0, not as 60/12
3962
+ selectValue(Math.round(angle / radianUnit) % steps);
3963
+ }, [selectionIsHours, radianUnit, selectValue]);
3957
3964
  const onClickHour = require$$0.useCallback(() => {
3958
3965
  setSelectionIsHours(true);
3959
3966
  }, []);
@@ -3966,49 +3973,56 @@ function RlsPickerClockComponent({ formControl, onListener, rlsTheme, time }) {
3966
3973
  const onClickPM = require$$0.useCallback(() => {
3967
3974
  setZoneIsPM(true);
3968
3975
  }, []);
3969
- const onActiveSelection = require$$0.useCallback(() => {
3976
+ const onPointerDown = require$$0.useCallback((event) => {
3977
+ event.preventDefault();
3978
+ event.currentTarget.setPointerCapture(event.pointerId);
3970
3979
  selectionIsActive.current = true;
3971
- }, []);
3972
- const onMouseSelection = require$$0.useCallback((event) => {
3980
+ const tick = event.target.closest('.rls-picker-clock__tick');
3981
+ // Pressing inside a label circle snaps to its exact value,
3982
+ // anywhere else (and while dragging) the angle decides
3983
+ if (tick?.dataset.value && pointerIsInsideTick(event, tick)) {
3984
+ selectValue(Number(tick.dataset.value));
3985
+ }
3986
+ else {
3987
+ selectFromPosition(event.clientX, event.clientY);
3988
+ }
3989
+ }, [selectValue, selectFromPosition]);
3990
+ const onPointerMove = require$$0.useCallback((event) => {
3973
3991
  if (selectionIsActive.current) {
3974
- event.preventDefault();
3975
- refreshComponent(event.clientX, event.clientY);
3992
+ selectFromPosition(event.clientX, event.clientY);
3976
3993
  }
3977
- }, [refreshComponent]);
3978
- const onTouchSelection = require$$0.useCallback((event) => {
3979
- const touch = event.touches.item(0);
3980
- if (selectionIsActive.current && touch) {
3981
- refreshComponent(touch.clientX, touch.clientY);
3994
+ }, [selectFromPosition]);
3995
+ const onPointerUp = require$$0.useCallback(() => {
3996
+ if (!selectionIsActive.current) {
3997
+ return;
3982
3998
  }
3983
- }, [refreshComponent]);
3984
- const onInactiveSelection = require$$0.useCallback(() => {
3985
3999
  selectionIsActive.current = false;
3986
- }, []);
3987
- const onClickValue = require$$0.useCallback((value) => {
4000
+ // Once the hour is chosen, continue with the minutes
3988
4001
  if (selectionIsHours) {
3989
- setHour(value);
3990
- refreshClock(value);
3991
- }
3992
- else {
3993
- const minute = value === 12 ? 0 : value * 5;
3994
- setMinute(minute);
3995
- refreshClock(minute);
4002
+ setSelectionIsHours(false);
3996
4003
  }
3997
4004
  }, [selectionIsHours]);
4005
+ const onPointerCancel = require$$0.useCallback(() => {
4006
+ selectionIsActive.current = false;
4007
+ }, []);
3998
4008
  const onCancel = require$$0.useCallback(() => {
3999
4009
  onListener?.({ event: components.PickerListenerEvent.Cancel });
4000
4010
  }, [onListener]);
4001
4011
  const onCurrentTime = require$$0.useCallback(() => {
4002
4012
  const currentTime = dates.Time.now();
4013
+ const zoneIsPM = currentTime.hour >= 12;
4014
+ const hour = zoneIsPM ? currentTime.hour - 12 : currentTime.hour;
4003
4015
  changeIsInternal.current = true;
4004
4016
  formControl?.setValue(currentTime);
4005
- setHour(currentTime.hour);
4017
+ setZoneIsPM(zoneIsPM);
4018
+ setHour(hour);
4006
4019
  setMinute(currentTime.minute);
4020
+ refreshClock(selectionIsHours ? hour : currentTime.minute);
4007
4021
  onListener?.({
4008
4022
  event: components.PickerListenerEvent.Select,
4009
4023
  value: currentTime
4010
4024
  });
4011
- }, [formControl, onListener]);
4025
+ }, [formControl, onListener, selectionIsHours, refreshClock]);
4012
4026
  const onSelect = require$$0.useCallback(() => {
4013
4027
  const hourValue = zoneIsPM
4014
4028
  ? hour !== 12
@@ -4025,10 +4039,10 @@ function RlsPickerClockComponent({ formControl, onListener, rlsTheme, time }) {
4025
4039
  value: timeValue
4026
4040
  });
4027
4041
  }, [formControl, hour, minute, zoneIsPM, onListener]);
4028
- return (jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock", "rls-theme": rlsTheme, children: [jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__header", children: [jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__title", children: [jsxRuntimeExports.jsx("span", { className: classNameHour, onClick: onClickHour, children: hourFormat }), jsxRuntimeExports.jsx("span", { className: "rls-picker-clock__title__separator", children: ":" }), jsxRuntimeExports.jsx("span", { className: classNameMinute, onClick: onClickMinute, children: minuteFormat })] }), jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__zone", children: [jsxRuntimeExports.jsx("span", { className: classNameAM, onClick: onClickAM, children: "AM" }), jsxRuntimeExports.jsx("span", { className: classNamePM, onClick: onClickPM, children: "PM" })] })] }), jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__body", children: jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__plate", ref: plateElement, onMouseDown: onActiveSelection, onMouseMove: onMouseSelection, onMouseUp: onInactiveSelection, onMouseLeave: onInactiveSelection, onTouchStart: onActiveSelection, onTouchMove: onTouchSelection, onTouchEnd: onInactiveSelection, children: [jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__canvas", children: jsxRuntimeExports.jsx("svg", { width: "120rem", height: "120rem", children: jsxRuntimeExports.jsxs("g", { style: {
4042
+ return (jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock", "rls-theme": rlsTheme, children: [jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__header", children: [jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__title", children: [jsxRuntimeExports.jsx("span", { className: classNameHour, onClick: onClickHour, children: hourFormat }), jsxRuntimeExports.jsx("span", { className: "rls-picker-clock__title__separator", children: ":" }), jsxRuntimeExports.jsx("span", { className: classNameMinute, onClick: onClickMinute, children: minuteFormat })] }), jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__zone", children: [jsxRuntimeExports.jsx("span", { className: classNameAM, onClick: onClickAM, children: "AM" }), jsxRuntimeExports.jsx("span", { className: classNamePM, onClick: onClickPM, children: "PM" })] })] }), jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__body", children: jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__plate", ref: plateElement, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerCancel, children: [jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__canvas", children: jsxRuntimeExports.jsx("svg", { width: "120rem", height: "120rem", children: jsxRuntimeExports.jsxs("g", { style: {
4029
4043
  transform: `translate(${DIAL_RADIUS}rem, ${DIAL_RADIUS}rem)`
4030
4044
  }, children: [jsxRuntimeExports.jsx("line", { ref: lineElement, className: "rls-picker-clock__canvas__line", x1: "-1", y1: "-1" }), jsxRuntimeExports.jsx("circle", { ref: centerElement, className: "rls-picker-clock__canvas__center", r: "4", cx: "-1", cy: "-1" }), jsxRuntimeExports.jsx("circle", { ref: indicatorElement, className: "rls-picker-clock__canvas__indicator", r: `${TICK_RADIUS}rem` }), jsxRuntimeExports.jsx("circle", { ref: pointElement, className: "rls-picker-clock__canvas__point", r: "3.5" })] }) }) }), jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__hours", children: CLOCK_VALUES.map((value) => {
4031
- return (jsxRuntimeExports.jsx(RlsPickerClockTick, { value: value, selectionIsHours: selectionIsHours, onValue: onClickValue }, value));
4045
+ return (jsxRuntimeExports.jsx(RlsPickerClockTick, { value: value, selectionIsHours: selectionIsHours }, value));
4032
4046
  }) })] }) }), jsxRuntimeExports.jsxs("div", { className: "rls-picker-clock__footer", children: [jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__footer--cancel", children: jsxRuntimeExports.jsx(RlsButton, { type: "flat", onClick: onCancel, children: labels.timeActionCancel }) }), jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__footer--today", children: jsxRuntimeExports.jsx(RlsButtonAction, { icon: "timer", onClick: onCurrentTime }) }), jsxRuntimeExports.jsx("div", { className: "rls-picker-clock__footer--ok", children: jsxRuntimeExports.jsx(RlsButton, { type: "raised", onClick: onSelect, children: labels.timeActionSelect }) })] })] }));
4033
4047
  }
4034
4048
  const RlsPickerClock = require$$0.memo(RlsPickerClockComponent);
@@ -4842,10 +4856,6 @@ function calculateImgDimension(image, dimension) {
4842
4856
  }
4843
4857
  function RlsImageEditorComponent(props) {
4844
4858
  const [selection, setSelection] = require$$0.useState(props.selection ?? 60);
4845
- const [labels, setLabels] = require$$0.useState({
4846
- actionRestore: reactI18n('editorImageActionRestore'),
4847
- actionSelect: reactI18n('editorImageActionSelect')
4848
- });
4849
4859
  const refBody = require$$0.useRef(null);
4850
4860
  const refImage = require$$0.useRef(null);
4851
4861
  const refSelection = require$$0.useRef(null);
@@ -4970,16 +4980,9 @@ function RlsImageEditorComponent(props) {
4970
4980
  refreshImageStyle();
4971
4981
  refreshSelectionStyle(selection);
4972
4982
  };
4973
- const unsubscription = i18n.i18nSubscribe(() => {
4974
- setLabels({
4975
- actionRestore: reactI18n('editorImageActionRestore'),
4976
- actionSelect: reactI18n('editorImageActionSelect')
4977
- });
4978
- });
4979
4983
  window.addEventListener('resize', refreshImageStyle);
4980
4984
  return () => {
4981
4985
  window.removeEventListener('resize', refreshImageStyle);
4982
- unsubscription();
4983
4986
  };
4984
4987
  }, []);
4985
4988
  require$$0.useEffect(() => {
@@ -5042,7 +5045,7 @@ function RlsImageEditorComponent(props) {
5042
5045
  context?.putImageData(originalImage.current, 0, 0);
5043
5046
  }
5044
5047
  }, []);
5045
- return (jsxRuntimeExports.jsxs("div", { className: "rls-image-editor", children: [jsxRuntimeExports.jsx("div", { ref: refBody, className: "rls-image-editor__body", children: jsxRuntimeExports.jsxs("div", { ref: refImage, className: "rls-image-editor__body__image", children: [jsxRuntimeExports.jsx("div", { ref: refSelection, className: "rls-image-editor__body__selection" }), jsxRuntimeExports.jsx("div", { ref: refOverlayTop, className: "rls-image-editor__body__overlay--top" }), jsxRuntimeExports.jsx("div", { ref: refOverlayRight, className: "rls-image-editor__body__overlay--right" }), jsxRuntimeExports.jsx("div", { ref: refOverlayBottom, className: "rls-image-editor__body__overlay--bottom" }), jsxRuntimeExports.jsx("div", { ref: refOverlayLeft, className: "rls-image-editor__body__overlay--left" }), jsxRuntimeExports.jsx("canvas", { ref: refCanvas })] }) }), jsxRuntimeExports.jsxs("div", { className: "rls-image-editor__footer", children: [jsxRuntimeExports.jsx("div", { className: "rls-image-editor__sliders", children: jsxRuntimeExports.jsx(RlsSlider, { prefixIcon: "external-link", value: selection, minValue: MIN_SLIDER_VALUE, maxValue: MAX_SLIDER_VALUE, onValue: setSelection, disabled: props.disabled }) }), jsxRuntimeExports.jsxs("div", { className: "rls-image-editor__actions", children: [props.children, jsxRuntimeExports.jsx(RlsButton, { type: "flat", rlsTheme: "standard", prefixIcon: "refresh", onClick: onRestore, disabled: props.disabled, children: labels.actionRestore }), jsxRuntimeExports.jsx(RlsButton, { type: "raised", rlsTheme: "primary", prefixIcon: "crop", onClick: onCropImage, disabled: props.disabled, children: labels.actionSelect })] })] }), jsxRuntimeExports.jsx("canvas", { ref: refPicture })] }));
5048
+ return (jsxRuntimeExports.jsxs("div", { className: "rls-image-editor", children: [jsxRuntimeExports.jsx("div", { ref: refBody, className: "rls-image-editor__body", children: jsxRuntimeExports.jsxs("div", { ref: refImage, className: "rls-image-editor__body__image", children: [jsxRuntimeExports.jsx("div", { ref: refSelection, className: "rls-image-editor__body__selection" }), jsxRuntimeExports.jsx("div", { ref: refOverlayTop, className: "rls-image-editor__body__overlay--top" }), jsxRuntimeExports.jsx("div", { ref: refOverlayRight, className: "rls-image-editor__body__overlay--right" }), jsxRuntimeExports.jsx("div", { ref: refOverlayBottom, className: "rls-image-editor__body__overlay--bottom" }), jsxRuntimeExports.jsx("div", { ref: refOverlayLeft, className: "rls-image-editor__body__overlay--left" }), jsxRuntimeExports.jsx("canvas", { ref: refCanvas })] }) }), jsxRuntimeExports.jsxs("div", { className: "rls-image-editor__footer", children: [jsxRuntimeExports.jsx("div", { className: "rls-image-editor__sliders", children: jsxRuntimeExports.jsx(RlsSlider, { prefixIcon: "crop", value: selection, minValue: MIN_SLIDER_VALUE, maxValue: MAX_SLIDER_VALUE, onValue: setSelection, disabled: props.disabled }) }), jsxRuntimeExports.jsxs("div", { className: "rls-image-editor__actions", children: [props.children, jsxRuntimeExports.jsx("button", { className: "rls-image-editor__action", "rls-theme": "standard", onClick: onRestore, disabled: props.disabled, children: jsxRuntimeExports.jsx(RlsIcon, { value: "refresh" }) }), jsxRuntimeExports.jsx("button", { className: "rls-image-editor__action", "rls-theme": "success", onClick: onCropImage, disabled: props.disabled, children: jsxRuntimeExports.jsx(RlsIcon, { value: "checkmark-circle-out" }) })] })] }), jsxRuntimeExports.jsx("canvas", { ref: refPicture })] }));
5046
5049
  }
5047
5050
  const RlsImageEditor = require$$0.memo(RlsImageEditorComponent);
5048
5051
 
@@ -5100,7 +5103,7 @@ function useImageEditorController(options) {
5100
5103
  setSrcEditor(undefined);
5101
5104
  }, []);
5102
5105
  const RlsImageEditorChooser = require$$0.useMemo(() => {
5103
- return (srcEditor && (jsxRuntimeExports.jsx(RlsImageEditorModal, { visible: true, src: srcEditor, formControl: options.formControl, maxWidth: options.maxWidth, quality: options.quality, ratio: options.ratio, selection: options.selection, onValue: onEditorValue, children: jsxRuntimeExports.jsx(RlsButton, { type: "flat", rlsTheme: "danger", onClick: onCancel, disabled: options.disabled, children: labels.actionCancel }) })));
5106
+ return (srcEditor && (jsxRuntimeExports.jsx(RlsImageEditorModal, { visible: true, src: srcEditor, formControl: options.formControl, maxWidth: options.maxWidth, quality: options.quality, ratio: options.ratio, selection: options.selection, onValue: onEditorValue, children: jsxRuntimeExports.jsx("button", { className: "rls-image-editor__action", "rls-theme": "danger", onClick: onCancel, disabled: options.disabled, children: jsxRuntimeExports.jsx(RlsIcon, { value: "close" }) }) })));
5104
5107
  }, [
5105
5108
  srcEditor,
5106
5109
  labels,