Skip to content

Commit ab40948

Browse files
committed
fix: _jsxSplit event name convertion
1 parent 86ac7e5 commit ab40948

File tree

3 files changed

+600
-21
lines changed

3 files changed

+600
-21
lines changed

packages/qwik/src/core/shared/jsx/jsx-internal.ts

Lines changed: 111 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { untrack } from '../../use/use-core';
22
import type { OnRenderFn } from '../component.public';
33
import { createQRL } from '../qrl/qrl-class';
44
import type { QRLInternal } from '../qrl/qrl-class';
5-
import { jsxEventToHtmlAttribute } from '../utils/event-names';
5+
import { jsxEventToHtmlAttribute, isHtmlAttributeAnEventName } from '../utils/event-names';
66
import { logOnceWarn } from '../utils/log';
77
import type { OnRenderProp, QSlot, QSlotS, QScopedStyle, ELEMENT_ID } from '../utils/markers';
88
import { 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

Comments
 (0)