@@ -56,8 +56,8 @@ export type Tag = string | symbol | Component;
56
56
export type TagProps < TTag extends Tag > = TTag extends string
57
57
? JSX . IntrinsicElements [ TTag ]
58
58
: TTag extends Component < infer TProps >
59
- ? TProps
60
- : Record < string , unknown > ;
59
+ ? TProps & JSX . IntrinsicAttributes
60
+ : Record < string , unknown > & JSX . IntrinsicAttributes ;
61
61
62
62
/***
63
63
* SPECIAL TAGS
@@ -190,29 +190,6 @@ export interface Element<TTag extends Tag = Tag> {
190
190
* the attribute syntax from JSX.
191
191
*/
192
192
props : TagProps < TTag > ;
193
-
194
- /**
195
- * A value which uniquely identifies an element from its siblings so that it
196
- * can be added/updated/moved/removed by key rather than position.
197
- *
198
- * Passed in createElement() as the prop "c-key".
199
- */
200
- key : Key ;
201
-
202
- /**
203
- * A callback which is called with the element’s result when it is committed.
204
- *
205
- * Passed in createElement() as the prop "c-ref".
206
- */
207
- ref : ( ( value : unknown ) => unknown ) | undefined ;
208
-
209
- /**
210
- * A possible boolean which indicates that element should NOT be rerendered.
211
- * If the element has never been rendered, this property has no effect.
212
- *
213
- * Passed in createElement() as the prop "c-static".
214
- */
215
- static_ : boolean | undefined ;
216
193
}
217
194
218
195
/**
@@ -236,18 +213,21 @@ export interface Element<TTag extends Tag = Tag> {
236
213
* rather than instatiating this class directly.
237
214
*/
238
215
export class Element < TTag extends Tag = Tag > {
239
- constructor (
240
- tag : TTag ,
241
- props : TagProps < TTag > ,
242
- key : Key ,
243
- ref ?: ( ( value : unknown ) => unknown ) | undefined ,
244
- static_ ?: boolean | undefined ,
245
- ) {
216
+ constructor ( tag : TTag , props : TagProps < TTag > ) {
246
217
this . tag = tag ;
247
218
this . props = props ;
248
- this . key = key ;
249
- this . ref = ref ;
250
- this . static_ = static_ ;
219
+ }
220
+
221
+ get key ( ) : Key {
222
+ return this . props . key ;
223
+ }
224
+
225
+ get ref ( ) : unknown {
226
+ return this . props . ref ;
227
+ }
228
+
229
+ get static_ ( ) : boolean {
230
+ return ! ! this . props [ "static" ] ;
251
231
}
252
232
}
253
233
@@ -258,6 +238,17 @@ export function isElement(value: any): value is Element {
258
238
return value != null && value . $$typeof === ElementSymbol ;
259
239
}
260
240
241
+ const DEPRECATED_PROP_PREFIXES = [ "crank-" , "c-" , "$" ] ;
242
+
243
+ const SPECIAL_PROP_BASES = [ "key" , "ref" , "static" ] ;
244
+
245
+ const SPECIAL_PROPS = new Set ( [ "children" , ...SPECIAL_PROP_BASES ] ) ;
246
+ for ( const propPrefix of DEPRECATED_PROP_PREFIXES ) {
247
+ for ( const propBase of SPECIAL_PROP_BASES ) {
248
+ SPECIAL_PROPS . add ( propPrefix + propBase ) ;
249
+ }
250
+ }
251
+
261
252
/**
262
253
* Creates an element with the specified tag, props and children.
263
254
*
@@ -271,47 +262,32 @@ export function createElement<TTag extends Tag>(
271
262
props ?: TagProps < TTag > | null | undefined ,
272
263
...children : Array < unknown >
273
264
) : Element < TTag > {
274
- let key : Key ;
275
- let ref : ( ( value : unknown ) => unknown ) | undefined ;
276
- let static_ = false ;
277
- const props1 = { } as TagProps < TTag > ;
278
- if ( props != null ) {
279
- for ( const name in props ) {
280
- switch ( name ) {
281
- case "crank-key" :
282
- case "c-key" :
283
- case "$key" :
284
- // We have to make sure we don’t assign null to the key because we
285
- // don’t check for null keys in the diffing functions.
286
- if ( props [ name ] != null ) {
287
- key = props [ name ] ;
288
- }
289
- break ;
290
- case "crank-ref" :
291
- case "c-ref" :
292
- case "$ref" :
293
- if ( typeof props [ name ] === "function" ) {
294
- ref = props [ name ] ;
295
- }
296
- break ;
297
- case "crank-static" :
298
- case "c-static" :
299
- case "$static" :
300
- static_ = ! ! props [ name ] ;
301
- break ;
302
- default :
303
- props1 [ name ] = props [ name ] ;
265
+ if ( props == null ) {
266
+ props = { } as TagProps < TTag > ;
267
+ }
268
+
269
+ for ( const propPrefix of DEPRECATED_PROP_PREFIXES ) {
270
+ for ( const propName of SPECIAL_PROP_BASES ) {
271
+ const deprecatedPropName = propPrefix + propName ;
272
+ if ( deprecatedPropName in ( props as TagProps < TTag > ) ) {
273
+ // eslint-disable-next-line no-console
274
+ console . warn (
275
+ `The \`${ deprecatedPropName } \` prop is deprecated. Use \`${ propName } \` instead.` ,
276
+ ) ;
277
+ ( props as TagProps < TTag > ) [ propName ] = ( props as TagProps < TTag > ) [
278
+ deprecatedPropName
279
+ ] ;
304
280
}
305
281
}
306
282
}
307
283
308
284
if ( children . length > 1 ) {
309
- props1 . children = children ;
285
+ ( props as TagProps < TTag > ) . children = children ;
310
286
} else if ( children . length === 1 ) {
311
- props1 . children = children [ 0 ] ;
287
+ ( props as TagProps < TTag > ) . children = children [ 0 ] ;
312
288
}
313
289
314
- return new Element ( tag , props1 , key , ref , static_ ) ;
290
+ return new Element ( tag , props as TagProps < TTag > ) ;
315
291
}
316
292
317
293
/** Clones a given element, shallowly copying the props object. */
@@ -322,7 +298,7 @@ export function cloneElement<TTag extends Tag>(
322
298
throw new TypeError ( "Cannot clone non-element" ) ;
323
299
}
324
300
325
- return new Element ( el . tag , { ...el . props } , el . key , el . ref ) ;
301
+ return new Element ( el . tag , { ...el . props } ) ;
326
302
}
327
303
328
304
/*** ELEMENT UTILITIES ***/
@@ -354,9 +330,10 @@ function narrow(value: Children): NarrowedChild {
354
330
* When asking the question, what is the "value" of a specific element, the
355
331
* answer varies depending on the tag:
356
332
*
357
- * For host elements, the value is the nodes created for the element.
333
+ * For host elements, the value is the nodes created for the element, e.g. the
334
+ * DOM node in the case of the DOMRenderer.
358
335
*
359
- * For fragments, the value is usually an array of nodes.
336
+ * For fragments, the value is the value of the
360
337
*
361
338
* For portals, the value is undefined, because a Portal element’s root and
362
339
* children are opaque to its parent.
@@ -616,24 +593,24 @@ export interface RendererImpl<
616
593
tag : TTag ,
617
594
node : TNode ,
618
595
name : TName ,
619
- value : TagProps < TTag > [ TName ] ,
620
- oldValue : TagProps < TTag > [ TName ] | undefined ,
596
+ value : unknown ,
597
+ oldValue : unknown ,
621
598
scope : TScope ,
622
599
) : unknown ;
623
600
624
601
arrange < TTag extends string | symbol > (
625
602
tag : TTag ,
626
603
node : TNode ,
627
- props : TagProps < TTag > ,
604
+ props : Record < string , unknown > ,
628
605
children : Array < TNode | string > ,
629
- oldProps : TagProps < TTag > | undefined ,
606
+ oldProps : Record < string , unknown > | undefined ,
630
607
oldChildren : Array < TNode | string > | undefined ,
631
608
) : unknown ;
632
609
633
610
dispose < TTag extends string | symbol > (
634
611
tag : TTag ,
635
612
node : TNode ,
636
- props : TagProps < TTag > ,
613
+ props : Record < string , unknown > ,
637
614
) : unknown ;
638
615
639
616
flush ( root : TRoot ) : unknown ;
@@ -659,7 +636,8 @@ const defaultRendererImpl: RendererImpl<unknown, unknown, unknown, unknown> = {
659
636
const _RendererImpl = Symbol . for ( "crank.RendererImpl" ) ;
660
637
/**
661
638
* An abstract class which is subclassed to render to different target
662
- * environments. This class is responsible for kicking off the rendering
639
+ * environments. Subclasses will typically call super() with a custom
640
+ * RendererImpl. This class is responsible for kicking off the rendering
663
641
* process and caching previous trees by root.
664
642
*
665
643
* @template TNode - The type of the node for a rendering environment.
@@ -1140,7 +1118,7 @@ function updateRaw<TNode, TScope>(
1140
1118
) : ElementValue < TNode > {
1141
1119
const props = ret . el . props ;
1142
1120
if ( ! oldProps || oldProps . value !== props . value ) {
1143
- ret . value = renderer . raw ( props . value , scope , hydrationData ) ;
1121
+ ret . value = renderer . raw ( props . value as any , scope , hydrationData ) ;
1144
1122
}
1145
1123
1146
1124
return ret . value ;
@@ -1162,7 +1140,7 @@ function updateFragment<TNode, TScope, TRoot extends TNode>(
1162
1140
ctx ,
1163
1141
scope ,
1164
1142
ret ,
1165
- ret . el . props . children ,
1143
+ ret . el . props . children as any ,
1166
1144
hydrationData ,
1167
1145
) ;
1168
1146
@@ -1187,7 +1165,7 @@ function updateHost<TNode, TScope, TRoot extends TNode>(
1187
1165
const tag = el . tag as string | symbol ;
1188
1166
let hydrationValue : TNode | string | undefined ;
1189
1167
if ( el . tag === Portal ) {
1190
- root = ret . value = el . props . root ;
1168
+ root = ret . value = el . props . root as any ;
1191
1169
} else {
1192
1170
if ( hydrationData !== undefined ) {
1193
1171
const value = hydrationData . children . shift ( ) ;
@@ -1211,7 +1189,7 @@ function updateHost<TNode, TScope, TRoot extends TNode>(
1211
1189
ctx ,
1212
1190
scope ,
1213
1191
ret ,
1214
- ret . el . props . children ,
1192
+ ret . el . props . children as any ,
1215
1193
childHydrationData ,
1216
1194
) ;
1217
1195
@@ -1261,7 +1239,7 @@ function commitHost<TNode, TScope>(
1261
1239
// TODO: The Copy tag doubles as a way to skip the patching of a prop.
1262
1240
// Not sure about this feature. Should probably be removed.
1263
1241
( copied = copied || new Set ( ) ) . add ( propName ) ;
1264
- } else if ( propName !== "children" ) {
1242
+ } else if ( ! SPECIAL_PROPS . has ( propName ) ) {
1265
1243
renderer . patch (
1266
1244
tag ,
1267
1245
value ,
@@ -1280,7 +1258,7 @@ function commitHost<TNode, TScope>(
1280
1258
props [ name ] = oldProps && oldProps [ name ] ;
1281
1259
}
1282
1260
1283
- ret . el = new Element ( tag , props , ret . el . key , ret . el . ref ) ;
1261
+ ret . el = new Element ( tag , props ) ;
1284
1262
}
1285
1263
1286
1264
renderer . arrange (
@@ -1535,7 +1513,9 @@ class ContextImpl<
1535
1513
| AsyncIterator < Children , Children | void , unknown >
1536
1514
| undefined ;
1537
1515
1538
- // The following properties are used to implement the
1516
+ // A "block" is a promise which represents the duration during which new
1517
+ // updates are queued, whereas "value" is a promise which represents the
1518
+ // actual pending result of rendering.
1539
1519
declare inflightBlock : Promise < unknown > | undefined ;
1540
1520
declare inflightValue : Promise < ElementValue < TNode > > | undefined ;
1541
1521
declare enqueuedBlock : Promise < unknown > | undefined ;
@@ -1611,7 +1591,7 @@ export class Context<T = any, TResult = any> implements EventTarget {
1611
1591
* plugins or utilities which wrap contexts.
1612
1592
*/
1613
1593
get props ( ) : ComponentProps < T > {
1614
- return this [ _ContextImpl ] . ret . el . props ;
1594
+ return this [ _ContextImpl ] . ret . el . props as ComponentProps < T > ;
1615
1595
}
1616
1596
1617
1597
// TODO: Should we rename this???
@@ -1637,7 +1617,7 @@ export class Context<T = any, TResult = any> implements EventTarget {
1637
1617
ctx . f |= NeedsToYield ;
1638
1618
}
1639
1619
1640
- yield ctx . ret . el . props ! ;
1620
+ yield ctx . ret . el . props as ComponentProps < T > ;
1641
1621
}
1642
1622
} finally {
1643
1623
ctx . f &= ~ IsInForOfLoop ;
@@ -1661,7 +1641,7 @@ export class Context<T = any, TResult = any> implements EventTarget {
1661
1641
1662
1642
if ( ctx . f & PropsAvailable ) {
1663
1643
ctx . f &= ~ PropsAvailable ;
1664
- yield ctx . ret . el . props ;
1644
+ yield ctx . ret . el . props as ComponentProps < T > ;
1665
1645
} else {
1666
1646
const props = await new Promise ( ( resolve ) => ( ctx . onProps = resolve ) ) ;
1667
1647
if ( ctx . f & IsUnmounted ) {
@@ -1962,8 +1942,8 @@ export class Context<T = any, TResult = any> implements EventTarget {
1962
1942
{
1963
1943
setEventProperty ( ev , "eventPhase" , AT_TARGET ) ;
1964
1944
setEventProperty ( ev , "currentTarget" , ctx . owner ) ;
1965
- const propCallback = ctx . ret . el . props [ "on" + ev . type ] ;
1966
- if ( propCallback != null ) {
1945
+ const propCallback = ctx . ret . el . props [ "on" + ev . type ] as unknown ;
1946
+ if ( typeof propCallback === "function" ) {
1967
1947
propCallback ( ev ) ;
1968
1948
if ( immediateCancelBubble || ev . cancelBubble ) {
1969
1949
return true ;
@@ -2991,6 +2971,31 @@ declare global {
2991
2971
[ tag : string ] : any ;
2992
2972
}
2993
2973
2974
+ export interface IntrinsicAttributes {
2975
+ children ?: unknown ;
2976
+ key ?: unknown ;
2977
+ ref ?: unknown ;
2978
+ [ "static" ] ?: unknown ;
2979
+ /** @deprecated */
2980
+ [ "crank-key" ] ?: unknown ;
2981
+ /** @deprecated */
2982
+ [ "crank-ref" ] ?: unknown ;
2983
+ /** @deprecated */
2984
+ [ "crank-static" ] ?: unknown ;
2985
+ /** @deprecated */
2986
+ [ "c-key" ] ?: unknown ;
2987
+ /** @deprecated */
2988
+ [ "c-ref" ] ?: unknown ;
2989
+ /** @deprecated */
2990
+ [ "c-static" ] ?: unknown ;
2991
+ /** @deprecated */
2992
+ $key ?: unknown ;
2993
+ /** @deprecated */
2994
+ $ref ?: unknown ;
2995
+ /** @deprecated */
2996
+ $static ?: unknown ;
2997
+ }
2998
+
2994
2999
export interface ElementChildrenAttribute {
2995
3000
children : { } ;
2996
3001
}
0 commit comments