From d0c4c92397bd229e8f515234fcf782778d7a5e5a Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 1 Jun 2025 18:56:43 +1000 Subject: [PATCH 1/4] feature: allow modal to be resized in width --- src/components/Modal/Modal.react.js | 49 +++++++++++++++++++++++++++-- src/components/Modal/Modal.scss | 15 +++++++++ 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/components/Modal/Modal.react.js b/src/components/Modal/Modal.react.js index 9ffe0e47ab..569852a1b9 100644 --- a/src/components/Modal/Modal.react.js +++ b/src/components/Modal/Modal.react.js @@ -13,6 +13,7 @@ import Position from 'lib/Position'; import React from 'react'; import PropTypes from 'lib/PropTypes'; import styles from 'components/Modal/Modal.scss'; +import { useState, useEffect, useRef } from 'react'; const origin = new Position(0, 0); const buttonColors = { @@ -38,12 +39,55 @@ const Modal = ({ progress = false, customFooter, textModal = false, - width, + width: initialWidth = 500, continueText, onContinue, showContinue, buttonsInCenter = React.Children.count(children) === 0, }) => { + + const modalRef = useRef(null); + + const [currentWidth, setCurrentWidth] = useState(initialWidth); + const resizing = useRef(false); + + const handleMouseDown = (e) => { + e.preventDefault(); + resizing.current = true; + if (modalRef.current) { + modalRef.current.classList.add(styles.noTransition); + } +}; + +const handleMouseMove = (e) => { + if (!resizing.current || !modalRef.current) { + return; + } + + const modalLeft = modalRef.current.getBoundingClientRect().left; + const newWidth = e.clientX - modalLeft; + + const clampedWidth = Math.min(window.innerWidth, Math.max(initialWidth, newWidth)); + setCurrentWidth(clampedWidth); +}; + +const handleMouseUp = () => { + resizing.current = false; + if (modalRef.current) { + modalRef.current.classList.remove(styles.noTransition); + } +}; + +useEffect(() => { + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + + return () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; +}, []); + if (children) { children = React.Children.map(children, c => { if (c && c.type === Field && c.props.label) { @@ -81,7 +125,7 @@ const Modal = ({ return ( -
+
{wrappedChildren} {footer} +
); diff --git a/src/components/Modal/Modal.scss b/src/components/Modal/Modal.scss index 171c32e4cf..46d2c12855 100644 --- a/src/components/Modal/Modal.scss +++ b/src/components/Modal/Modal.scss @@ -99,3 +99,18 @@ } @include modalKeyframes(); + +.resizeHandle { + width: 16px; + height: 16px; + position: absolute; + bottom: 0; + right: 0; + cursor: se-resize; + background: rgba(255, 255, 255, 0.5); + z-index: 10; +} + +.noTransition { + transition: none !important; +} From 85c9cc73d7a1b8a8314557abab42f8942de3e0a4 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 1 Jun 2025 19:33:50 +1000 Subject: [PATCH 2/4] Update Modal.react.js --- src/components/Modal/Modal.react.js | 80 ++++++++++++++++------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/src/components/Modal/Modal.react.js b/src/components/Modal/Modal.react.js index 569852a1b9..324d1a6b5c 100644 --- a/src/components/Modal/Modal.react.js +++ b/src/components/Modal/Modal.react.js @@ -10,10 +10,9 @@ import Field from 'components/Field/Field.react'; import Icon from 'components/Icon/Icon.react'; import Popover from 'components/Popover/Popover.react'; import Position from 'lib/Position'; -import React from 'react'; +import React, { useState, useEffect, useRef, useCallback } from 'react'; import PropTypes from 'lib/PropTypes'; import styles from 'components/Modal/Modal.scss'; -import { useState, useEffect, useRef } from 'react'; const origin = new Position(0, 0); const buttonColors = { @@ -39,54 +38,56 @@ const Modal = ({ progress = false, customFooter, textModal = false, - width: initialWidth = 500, + width, + initialWidth = width ?? 500, continueText, onContinue, showContinue, buttonsInCenter = React.Children.count(children) === 0, }) => { - const modalRef = useRef(null); - const [currentWidth, setCurrentWidth] = useState(initialWidth); const resizing = useRef(false); - const handleMouseDown = (e) => { - e.preventDefault(); - resizing.current = true; - if (modalRef.current) { - modalRef.current.classList.add(styles.noTransition); - } -}; + const handleMouseDown = e => { + e.preventDefault(); + resizing.current = true; + if (modalRef.current) { + modalRef.current.classList.add(styles.noTransition); + } + }; -const handleMouseMove = (e) => { - if (!resizing.current || !modalRef.current) { - return; - } + const handleMouseMove = useCallback( + e => { + if (!resizing.current || !modalRef.current) { + return; + } - const modalLeft = modalRef.current.getBoundingClientRect().left; - const newWidth = e.clientX - modalLeft; + const modalLeft = modalRef.current.getBoundingClientRect().left; + const newWidth = e.clientX - modalLeft; - const clampedWidth = Math.min(window.innerWidth, Math.max(initialWidth, newWidth)); - setCurrentWidth(clampedWidth); -}; + const clampedWidth = Math.min(window.innerWidth, Math.max(initialWidth, newWidth)); + setCurrentWidth(clampedWidth); + }, + [initialWidth] + ); -const handleMouseUp = () => { - resizing.current = false; - if (modalRef.current) { - modalRef.current.classList.remove(styles.noTransition); - } -}; + const handleMouseUp = useCallback(() => { + resizing.current = false; + if (modalRef.current) { + modalRef.current.classList.remove(styles.noTransition); + } + }, []); -useEffect(() => { - document.addEventListener('mousemove', handleMouseMove); - document.addEventListener('mouseup', handleMouseUp); + useEffect(() => { + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); - return () => { - document.removeEventListener('mousemove', handleMouseMove); - document.removeEventListener('mouseup', handleMouseUp); - }; -}, []); + return () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + }, [handleMouseMove, handleMouseUp]); if (children) { children = React.Children.map(children, c => { @@ -125,7 +126,11 @@ useEffect(() => { return ( -
+
Date: Thu, 5 Jun 2025 21:36:12 +1000 Subject: [PATCH 3/4] Update Modal.react.js --- src/components/Modal/Modal.react.js | 61 +++++++++++++++++++---------- 1 file changed, 41 insertions(+), 20 deletions(-) diff --git a/src/components/Modal/Modal.react.js b/src/components/Modal/Modal.react.js index 324d1a6b5c..474e91cde4 100644 --- a/src/components/Modal/Modal.react.js +++ b/src/components/Modal/Modal.react.js @@ -47,33 +47,42 @@ const Modal = ({ }) => { const modalRef = useRef(null); const [currentWidth, setCurrentWidth] = useState(initialWidth); - const resizing = useRef(false); + const resizing = useRef({ active: false, side: null, startX: 0, startWidth: 0 }); - const handleMouseDown = e => { + // Helper to get min width + const minWidth = initialWidth; + + const handleMouseDown = (side) => (e) => { e.preventDefault(); - resizing.current = true; - if (modalRef.current) { - modalRef.current.classList.add(styles.noTransition); - } + if (!modalRef.current) return; + resizing.current = { + active: true, + side, + startX: e.clientX, + startWidth: currentWidth, + }; + modalRef.current.classList.add(styles.noTransition); }; const handleMouseMove = useCallback( - e => { - if (!resizing.current || !modalRef.current) { - return; + (e) => { + if (!resizing.current.active || !modalRef.current) return; + const { side, startX, startWidth } = resizing.current; + if (side === 'right') { + let newWidth = startWidth + 2 * (e.clientX - startX); + newWidth = Math.max(minWidth, newWidth); + setCurrentWidth(newWidth); + } else if (side === 'left') { + let newWidth = startWidth - 2 * (e.clientX - startX); + newWidth = Math.max(minWidth, newWidth); + setCurrentWidth(newWidth); } - - const modalLeft = modalRef.current.getBoundingClientRect().left; - const newWidth = e.clientX - modalLeft; - - const clampedWidth = Math.min(window.innerWidth, Math.max(initialWidth, newWidth)); - setCurrentWidth(clampedWidth); }, - [initialWidth] + [minWidth] ); const handleMouseUp = useCallback(() => { - resizing.current = false; + resizing.current = { active: false, side: null, startX: 0, startWidth: 0 }; if (modalRef.current) { modalRef.current.classList.remove(styles.noTransition); } @@ -82,7 +91,6 @@ const Modal = ({ useEffect(() => { document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); - return () => { document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); @@ -129,8 +137,22 @@ const Modal = ({
+ {/* Left resize handle */} +
+ {/* Right resize handle */} +
{wrappedChildren} {footer} -
); From 549d1775ad5a94ebaf36376e4f323dcf3e7aef6f Mon Sep 17 00:00:00 2001 From: Daniel Date: Sun, 22 Jun 2025 20:02:36 +1000 Subject: [PATCH 4/4] Update Modal.react.js --- src/components/Modal/Modal.react.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/Modal/Modal.react.js b/src/components/Modal/Modal.react.js index 474e91cde4..73502c1e9e 100644 --- a/src/components/Modal/Modal.react.js +++ b/src/components/Modal/Modal.react.js @@ -54,7 +54,9 @@ const Modal = ({ const handleMouseDown = (side) => (e) => { e.preventDefault(); - if (!modalRef.current) return; + if (!modalRef.current) { + return; + } resizing.current = { active: true, side, @@ -66,7 +68,9 @@ const Modal = ({ const handleMouseMove = useCallback( (e) => { - if (!resizing.current.active || !modalRef.current) return; + if (!resizing.current.active || !modalRef.current) { + return; + } const { side, startX, startWidth } = resizing.current; if (side === 'right') { let newWidth = startWidth + 2 * (e.clientX - startX);