@@ -2,7 +2,7 @@ import { untrack } from '../../use/use-core';
22import type { OnRenderFn } from '../component.public' ;
33import { createQRL } from '../qrl/qrl-class' ;
44import type { QRLInternal } from '../qrl/qrl-class' ;
5- import { jsxEventToHtmlAttribute } from '../utils/event-names' ;
5+ import { jsxEventToHtmlAttribute , isHtmlAttributeAnEventName } from '../utils/event-names' ;
66import { logOnceWarn } from '../utils/log' ;
77import type { OnRenderProp , QSlot , QSlotS , QScopedStyle , ELEMENT_ID } from '../utils/markers' ;
88import { qDev } from '../utils/qdev' ;
@@ -72,6 +72,8 @@ export const _jsxSplit = <T extends string | FunctionComponent<any>>(
7272) : JSXNodeInternal < T > => {
7373 return untrack ( ( ) => {
7474 let toSort = false ;
75+ let constPropsCopied = false ;
76+ let varPropsCopied = false ;
7577
7678 // Apply transformations for native HTML elements only
7779 if ( typeof type === 'string' ) {
@@ -80,6 +82,10 @@ export const _jsxSplit = <T extends string | FunctionComponent<any>>(
8082 for ( const k in constProps ) {
8183 const attr = jsxEventToHtmlAttribute ( k ) ;
8284 if ( attr ) {
85+ if ( ! constPropsCopied ) {
86+ constProps = { ...constProps } ;
87+ constPropsCopied = true ;
88+ }
8389 mergeHandlers ( constProps , attr , constProps [ k ] as any ) ;
8490 delete constProps [ k ] ;
8591 }
@@ -89,54 +95,128 @@ export const _jsxSplit = <T extends string | FunctionComponent<any>>(
8995 for ( const k in varProps ) {
9096 const attr = jsxEventToHtmlAttribute ( k ) ;
9197 if ( attr ) {
92- if ( ! constProps || ! _hasOwnProperty . call ( constProps , k ) ) {
98+ if ( ! varPropsCopied ) {
99+ varProps = { ...varProps } ;
100+ varPropsCopied = true ;
101+ }
102+ // Check if the converted attribute already exists in constProps
103+ if ( constProps && _hasOwnProperty . call ( constProps , attr ) ) {
104+ // Merge into constProps since it already has this event
105+ if ( ! constPropsCopied ) {
106+ constProps = { ...constProps } ;
107+ constPropsCopied = true ;
108+ }
109+ mergeHandlers ( constProps , attr , varProps [ k ] as any ) ;
110+ } else {
111+ // Add to varProps
93112 toSort = mergeHandlers ( varProps , attr , varProps [ k ] as any ) || toSort ;
94113 }
95114 delete varProps [ k ] ;
115+ } else if ( isHtmlAttributeAnEventName ( k ) ) {
116+ // Already in on:* format, check if it exists in constProps
117+ if ( constProps && _hasOwnProperty . call ( constProps , k ) ) {
118+ if ( ! varPropsCopied ) {
119+ varProps = { ...varProps } ;
120+ varPropsCopied = true ;
121+ }
122+ if ( ! constPropsCopied ) {
123+ constProps = { ...constProps } ;
124+ constPropsCopied = true ;
125+ }
126+ // Merge into constProps
127+ mergeHandlers ( constProps , k , varProps [ k ] as any ) ;
128+ delete varProps [ k ] ;
129+ }
96130 }
97131 }
98132 }
99133
100134 // Handle bind:*
101135 if ( varProps ) {
102136 if ( _hasOwnProperty . call ( varProps , BIND_CHECKED ) ) {
137+ if ( ! varPropsCopied ) {
138+ varProps = { ...varProps } ;
139+ varPropsCopied = true ;
140+ }
103141 const value = varProps [ BIND_CHECKED ] ;
104142 delete varProps [ BIND_CHECKED ] ;
105143 if ( value ) {
106144 varProps . checked = value ;
107- varProps [ 'on:input' ] = createQRL ( null , '_chk' , _chk , null , null , [ value ] ) ;
108- toSort = true ;
145+ const handler = createQRL ( null , '_chk' , _chk , null , null , [ value ] ) ;
146+ // Check if on:input already exists in constProps
147+ if ( constProps && _hasOwnProperty . call ( constProps , 'on:input' ) ) {
148+ if ( ! constPropsCopied ) {
149+ constProps = { ...constProps } ;
150+ constPropsCopied = true ;
151+ }
152+ mergeHandlers ( constProps , 'on:input' , handler ) ;
153+ } else {
154+ toSort = mergeHandlers ( varProps , 'on:input' , handler ) || toSort ;
155+ }
109156 }
110157 } else if ( _hasOwnProperty . call ( varProps , BIND_VALUE ) ) {
158+ if ( ! varPropsCopied ) {
159+ varProps = { ...varProps } ;
160+ varPropsCopied = true ;
161+ }
111162 const value = varProps [ BIND_VALUE ] ;
112163 delete varProps [ BIND_VALUE ] ;
113164 if ( value ) {
114165 varProps . value = value ;
115- varProps [ 'on:input' ] = createQRL ( null , '_val' , _val , null , null , [ value ] ) ;
116- toSort = true ;
166+ const handler = createQRL ( null , '_val' , _val , null , null , [ value ] ) ;
167+ // Check if on:input already exists in constProps
168+ if ( constProps && _hasOwnProperty . call ( constProps , 'on:input' ) ) {
169+ if ( ! constPropsCopied ) {
170+ constProps = { ...constProps } ;
171+ constPropsCopied = true ;
172+ }
173+ mergeHandlers ( constProps , 'on:input' , handler ) ;
174+ } else {
175+ toSort = mergeHandlers ( varProps , 'on:input' , handler ) || toSort ;
176+ }
117177 }
118178 }
119179 }
120180 if ( constProps ) {
121181 if ( _hasOwnProperty . call ( constProps , BIND_CHECKED ) ) {
182+ if ( ! constPropsCopied ) {
183+ constProps = { ...constProps } ;
184+ constPropsCopied = true ;
185+ }
122186 const value = constProps [ BIND_CHECKED ] ;
123187 delete constProps [ BIND_CHECKED ] ;
124188 if ( value ) {
125189 constProps . checked = value ;
126- constProps [ 'on:input' ] = createQRL ( null , '_chk' , _chk , null , null , [ value ] ) ;
190+ mergeHandlers (
191+ constProps ,
192+ 'on:input' ,
193+ createQRL ( null , '_chk' , _chk , null , null , [ value ] )
194+ ) ;
127195 }
128196 } else if ( _hasOwnProperty . call ( constProps , BIND_VALUE ) ) {
197+ if ( ! constPropsCopied ) {
198+ constProps = { ...constProps } ;
199+ constPropsCopied = true ;
200+ }
129201 const value = constProps [ BIND_VALUE ] ;
130202 delete constProps [ BIND_VALUE ] ;
131203 if ( value ) {
132204 constProps . value = value ;
133- constProps [ 'on:input' ] = createQRL ( null , '_val' , _val , null , null , [ value ] ) ;
205+ mergeHandlers (
206+ constProps ,
207+ 'on:input' ,
208+ createQRL ( null , '_val' , _val , null , null , [ value ] )
209+ ) ;
134210 }
135211 }
136212 }
137213
138214 // Transform className -> class
139215 if ( varProps && _hasOwnProperty . call ( varProps , 'className' ) ) {
216+ if ( ! varPropsCopied ) {
217+ varProps = { ...varProps } ;
218+ varPropsCopied = true ;
219+ }
140220 varProps . class = varProps . className ;
141221 varProps . className = undefined ;
142222 toSort = true ;
@@ -149,6 +229,10 @@ export const _jsxSplit = <T extends string | FunctionComponent<any>>(
149229 }
150230 }
151231 if ( constProps && _hasOwnProperty . call ( constProps , 'className' ) ) {
232+ if ( ! constPropsCopied ) {
233+ constProps = { ...constProps } ;
234+ constPropsCopied = true ;
235+ }
152236 constProps . class = constProps . className ;
153237 constProps . className = undefined ;
154238 if ( qDev ) {
@@ -164,12 +248,31 @@ export const _jsxSplit = <T extends string | FunctionComponent<any>>(
164248 if ( varProps ) {
165249 for ( const k in varProps ) {
166250 if ( k === 'children' ) {
251+ if ( ! varPropsCopied ) {
252+ varProps = { ...varProps } ;
253+ varPropsCopied = true ;
254+ }
167255 children ||= varProps . children as JSXChildren ;
168256 delete varProps . children ;
169257 } else if ( k === 'key' ) {
258+ if ( ! varPropsCopied ) {
259+ varProps = { ...varProps } ;
260+ varPropsCopied = true ;
261+ }
170262 key ||= varProps . key as string ;
171263 delete varProps . key ;
172264 } else if ( constProps && k in constProps ) {
265+ if ( ! varPropsCopied ) {
266+ varProps = { ...varProps } ;
267+ varPropsCopied = true ;
268+ }
269+ delete varProps [ k ] ;
270+ } else if ( varProps [ k ] === null ) {
271+ if ( ! varPropsCopied ) {
272+ varProps = { ...varProps } ;
273+ varPropsCopied = true ;
274+ }
275+ // Clean up null markers (from event conversions)
173276 delete varProps [ k ] ;
174277 }
175278 }
0 commit comments