@@ -745,6 +745,27 @@ export default async function ({ addon, msg, console }) {
745745 // Pool grows as needed; excess handles are hidden when extraStops shrinks.
746746 const extraHandlePool = [ ] ;
747747
748+ // Cleanly remove extra stop at idx: rebuild all selected-item gradients without it
749+ // (so the WeakSet warm-up count stays consistent), then splice and re-sync.
750+ const removeExtraStop = ( idx ) => {
751+ const previewExtra = extraStops . filter ( ( _ , i ) => i !== idx ) ;
752+ const cp = colorProp ( ) ;
753+ for ( const item of selectedLayers ( ) ) {
754+ if ( ! item [ cp ] ?. gradient ) continue ;
755+ const liveStops = item [ cp ] . gradient . stops ;
756+ const c0 = liveStops [ 0 ] . color ;
757+ const c1 = liveStops [ liveStops . length - 1 ] . color ;
758+ item [ cp ] . gradient = { stops : [ c0 , ...previewExtra . map ( ( s ) => s . color ) , c1 ] , radial : item [ cp ] . gradient . radial } ;
759+ const g2 = item [ cp ] . gradient ;
760+ g2 . stops [ 0 ] . offset = stops . p0 ;
761+ for ( let i = 0 ; i < previewExtra . length ; i ++ ) g2 . stops [ i + 1 ] . offset = previewExtra [ i ] . offset ;
762+ g2 . stops [ g2 . stops . length - 1 ] . offset = stops . p1 ;
763+ }
764+ extraStops . splice ( idx , 1 ) ;
765+ applyAllStops ( ) ;
766+ syncOverlay ( ) ;
767+ } ;
768+
748769 const makeExtraStopHandle = ( poolIndex ) => {
749770 const g = document . createElementNS ( NS , "g" ) ;
750771 g . _ringR = 9 ;
@@ -762,6 +783,15 @@ export default async function ({ addon, msg, console }) {
762783 openExtraColorPicker ( poolIndex , e . clientX , e . clientY , g ) ;
763784 } ) ;
764785
786+ // Double-click deletes this stop.
787+ g . addEventListener ( "dblclick" , ( e ) => {
788+ if ( addon . self . disabled || attachDragMoved ) return ;
789+ e . stopPropagation ( ) ;
790+ picker . close ( ) ;
791+ removeExtraStop ( poolIndex ) ;
792+ triggerUndo ( ) ;
793+ } ) ;
794+
765795 // Drag: constrained to axis between neighbours.
766796 // If dragged > 25px perpendicular to the axis, enter "pending delete" state.
767797 // Visual: handle is hidden and the gradient previews without this stop.
@@ -856,9 +886,7 @@ export default async function ({ addon, msg, console }) {
856886 pendingDeleteSuppressedRing = false ;
857887 picker . close ( ) ;
858888 }
859- extraStops . splice ( poolIndex , 1 ) ;
860- applyAllStops ( ) ;
861- syncOverlay ( ) ;
889+ removeExtraStop ( poolIndex ) ;
862890 } else {
863891 // Restore visibility in case we entered pending-delete then moved back.
864892 g . style . visibility = "" ;
@@ -907,9 +935,9 @@ export default async function ({ addon, msg, console }) {
907935 setPickerHighlight ( groupEl ) ;
908936 picker . open (
909937 extraStops [ idx ] . color ,
910- ( css ) => {
938+ ( color ) => {
911939 if ( extraStops [ idx ] ) {
912- extraStops [ idx ] . color = css ;
940+ extraStops [ idx ] . color = color ;
913941 applyAllStops ( ) ;
914942 syncOverlay ( ) ;
915943 }
@@ -978,6 +1006,18 @@ export default async function ({ addon, msg, console }) {
9781006 const op = toSVG ( fc . origin ) ;
9791007 const dp = toSVG ( fc . destination ) ;
9801008 const axisLenPx = Math . hypot ( dp . x - op . x , dp . y - op . y ) ;
1009+ // Clicking before p0 in a radial gradient: promote the click position as the new p0,
1010+ // pushing the current p0 into extra stops so the rest of the gradient is preserved.
1011+ if ( isRadial && t < stops . p0 ) {
1012+ extraStops . unshift ( { color : c0css , offset : stops . p0 } ) ;
1013+ stops . p0 = clamp ( crampedToOffset ( 0 , extraStops . length + 2 , t , axisLenPx ) , 0 , stops . p0 - 0.01 ) ;
1014+ applyAllStops ( ) ;
1015+ syncOverlay ( ) ;
1016+ triggerUndo ( ) ;
1017+ attachDragMoved = false ;
1018+ p0Handle . g . dispatchEvent ( new MouseEvent ( "click" , { bubbles : true , clientX : e . clientX , clientY : e . clientY } ) ) ;
1019+ return ;
1020+ }
9811021 const newInnerIdx = extraStops . filter ( ( s ) => s . offset < t ) . length ;
9821022 const newInnerCount = isRadial ? extraStops . length + 2 : extraStops . length + 1 ;
9831023 const innerIdxForNew = isRadial ? newInnerIdx + 1 : newInnerIdx ;
0 commit comments