46
46
* @typedef {'html' | 'svg' } Space
47
47
* Namespace.
48
48
*
49
- * @typedef {'react ' | 'html ' } ElementAttributeNameCase
50
- * Specify casing to use for attribute names.
49
+ * @typedef {'html ' | 'react ' } ElementAttributeNameCase
50
+ * Casing to use for attribute names.
51
51
*
52
- * React casing is for example `className`, `strokeLinecap`, `xmlLang`.
53
52
* HTML casing is for example `class`, `stroke-linecap`, `xml:lang`.
53
+ * React casing is for example `className`, `strokeLinecap`, `xmlLang`.
54
+ *
55
+ * @typedef {'css' | 'dom' } StylePropertyNameCase
56
+ * Casing to use for property names in `style` objects.
57
+ *
58
+ * CSS casing is for example `background-color` and `-webkit-line-clamp`.
59
+ * DOM casing is for example `backgroundColor` and `WebkitLineClamp`.
54
60
*
55
61
* @typedef Source
56
62
* Info about source.
99
105
* Pass `node` to components.
100
106
* @property {ElementAttributeNameCase } elementAttributeNameCase
101
107
* Casing to use for attribute names.
108
+ * @property {StylePropertyNameCase } stylePropertyNameCase
109
+ * Casing to use for property names in `style` objects.
102
110
* @property {Schema } schema
103
111
* Current schema.
104
112
* @property {unknown } Fragment
122
130
* Pass the hast element node to components.
123
131
* @property {ElementAttributeNameCase | null | undefined } [elementAttributeNameCase='react']
124
132
* Specify casing to use for attribute names.
133
+ * @property {StylePropertyNameCase | null | undefined } [stylePropertyNameCase='dom']
134
+ * Specify casing to use for property names in `style` objects.
125
135
* @property {Space | null | undefined } [space='html']
126
136
* Whether `tree` is in the `'html'` or `'svg'` space.
127
137
*
@@ -195,6 +205,9 @@ import {whitespace} from 'hast-util-whitespace'
195
205
196
206
const own = { } . hasOwnProperty
197
207
208
+ const cap = / [ A - Z ] / g
209
+ const dashSomething = / - ( [ a - z ] ) / g
210
+
198
211
// `react-dom` triggers a warning for *any* white space in tables.
199
212
// To follow GFM, `mdast-util-to-hast` injects line endings between elements.
200
213
// Other tools might do so too, but they don’t do here, so we remove all of
@@ -255,6 +268,7 @@ export function toJsxRuntime(tree, options) {
255
268
schema : options . space === 'svg' ? svg : html ,
256
269
passNode : options . passNode || false ,
257
270
elementAttributeNameCase : options . elementAttributeNameCase || 'react' ,
271
+ stylePropertyNameCase : options . stylePropertyNameCase || 'dom' ,
258
272
components : options . components || { } ,
259
273
filePath,
260
274
create
@@ -485,8 +499,15 @@ function createProperty(state, node, prop, value) {
485
499
}
486
500
487
501
// React only accepts `style` as object.
488
- if ( info . property === 'style' && typeof value === 'string' ) {
489
- return [ 'style' , parseStyle ( state , node , value ) ]
502
+ if ( info . property === 'style' ) {
503
+ let styleObject =
504
+ typeof value === 'object' ? value : parseStyle ( state , node , String ( value ) )
505
+
506
+ if ( state . stylePropertyNameCase === 'css' ) {
507
+ styleObject = transformStyleToCssCasing ( styleObject )
508
+ }
509
+
510
+ return [ 'style' , styleObject ]
490
511
}
491
512
492
513
return [
@@ -534,8 +555,8 @@ function parseStyle(state, node, value) {
534
555
return result
535
556
536
557
/**
537
- * Add a CSS property (normal, so with dashes) to `result` as a camelcased
538
- * CSS property.
558
+ * Add a CSS property (normal, so with dashes) to `result` as a DOM CSS
559
+ * property.
539
560
*
540
561
* @param {string } name
541
562
* Key.
@@ -545,9 +566,39 @@ function parseStyle(state, node, value) {
545
566
* Nothing.
546
567
*/
547
568
function replacer ( name , value ) {
548
- if ( name . slice ( 0 , 4 ) === '-ms-' ) name = 'ms-' + name . slice ( 4 )
549
- result [ name . replace ( / - ( [ a - z ] ) / g, replace ) ] = value
569
+ let key = name
570
+
571
+ if ( key . slice ( 0 , 2 ) !== '--' ) {
572
+ if ( key . slice ( 0 , 4 ) === '-ms-' ) key = 'ms-' + key . slice ( 4 )
573
+ key = key . replace ( dashSomething , toCamel )
574
+ }
575
+
576
+ result [ key ] = value
577
+ }
578
+ }
579
+
580
+ /**
581
+ * Transform a DOM casing style object to a CSS casing style object.
582
+ *
583
+ * @param {Style } domCasing
584
+ * @returns {Style }
585
+ */
586
+ function transformStyleToCssCasing ( domCasing ) {
587
+ /** @type {Style } */
588
+ const cssCasing = { }
589
+ /** @type {string } */
590
+ let from
591
+
592
+ for ( from in domCasing ) {
593
+ if ( own . call ( domCasing , from ) ) {
594
+ let to = from . replace ( cap , toDash )
595
+ // Handle `ms-xxx` -> `-ms-xxx`.
596
+ if ( to . slice ( 0 , 3 ) === 'ms-' ) to = '-' + to
597
+ cssCasing [ to ] = domCasing [ from ]
598
+ }
550
599
}
600
+
601
+ return cssCasing
551
602
}
552
603
553
604
/**
@@ -560,6 +611,18 @@ function parseStyle(state, node, value) {
560
611
* @returns {string }
561
612
* Capitalized `$1`.
562
613
*/
563
- function replace ( _ , $1 ) {
614
+ function toCamel ( _ , $1 ) {
564
615
return $1 . toUpperCase ( )
565
616
}
617
+
618
+ /**
619
+ * Make `$0` dash cased.
620
+ *
621
+ * @param {string } $0
622
+ * Capitalized ASCII leter.
623
+ * @returns {string }
624
+ * Dash and lower letter.
625
+ */
626
+ function toDash ( $0 ) {
627
+ return '-' + $0 . toLowerCase ( )
628
+ }
0 commit comments