Design system.
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

74 lines
2.2 KiB

  1. import * as React from 'react';
  2. import { getFormValues } from '@theoryofnekomata/formxtra';
  3. export interface UseImageControlsOptions {
  4. actionFormKey?: string;
  5. forwardedRef?: React.Ref<HTMLImageElement>;
  6. }
  7. export const useImageControls = (options = {} as UseImageControlsOptions) => {
  8. const { actionFormKey = 'action' as const, forwardedRef } = options;
  9. const [fullScreen, setFullScreen] = React.useState(false);
  10. const defaultRef = React.useRef<HTMLImageElement>(null);
  11. const imageRef = forwardedRef ?? defaultRef;
  12. const filenameRef = React.useRef<HTMLElement>(null);
  13. React.useEffect(() => {
  14. if (fullScreen) {
  15. window.document.body.style.overflow = 'hidden';
  16. }
  17. if (!fullScreen) {
  18. window.document.body.style.overflow = '';
  19. }
  20. }, [fullScreen]);
  21. const toggleFullScreen = React.useCallback(() => {
  22. setFullScreen((b) => !b);
  23. }, []);
  24. const download = React.useCallback(() => {
  25. if (!(typeof imageRef === 'object' && imageRef?.current !== null)) {
  26. return;
  27. }
  28. if (!(typeof filenameRef === 'object' && filenameRef?.current !== null)) {
  29. return;
  30. }
  31. const downloadLink = window.document.createElement('a');
  32. downloadLink.download = filenameRef.current.textContent ?? 'image';
  33. downloadLink.href = imageRef.current.currentSrc;
  34. downloadLink.addEventListener('click', () => {
  35. downloadLink.remove();
  36. });
  37. downloadLink.click();
  38. }, [imageRef, filenameRef]);
  39. const actions = React.useMemo(() => ({
  40. toggleFullScreen,
  41. download,
  42. }), [toggleFullScreen, download]);
  43. const handleAction: React.FormEventHandler<HTMLFormElement> = React.useCallback((e) => {
  44. e.preventDefault();
  45. const nativeEvent = e.nativeEvent as unknown as { submitter: HTMLElement };
  46. const formData = getFormValues(
  47. e.currentTarget,
  48. {
  49. submitter: nativeEvent.submitter,
  50. }
  51. );
  52. const actionName = formData[actionFormKey] as keyof typeof actions;
  53. const { [actionName]: actionFunction } = actions;
  54. actionFunction?.();
  55. }, [actions, actionFormKey]);
  56. return React.useMemo(() => ({
  57. fullScreen,
  58. handleAction,
  59. imageRef,
  60. filenameRef,
  61. }), [fullScreen, handleAction, imageRef, filenameRef]);
  62. };