Skip to content

Commit a439dc9

Browse files
committed
Add tableCellAlignToStyle option
1 parent 478379f commit a439dc9

File tree

4 files changed

+114
-8
lines changed

4 files changed

+114
-8
lines changed

lib/index.js

+53-8
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,9 @@
9595
* @property {StylePropertyNameCase | null | undefined} [stylePropertyNameCase='dom']
9696
* Specify casing to use for property names in `style` objects (default:
9797
* `'dom'`).
98+
* @property {boolean | null | undefined} [tableCellAlignToStyle=true]
99+
* Turn obsolete `align` props on `td` and `th` into CSS `style` props
100+
* (default: `true`).
98101
*
99102
* @typedef RuntimeDevelopment
100103
* Runtime fields when development is on.
@@ -175,6 +178,8 @@
175178
* Current schema.
176179
* @property {StylePropertyNameCase} stylePropertyNameCase
177180
* Casing to use for property names in `style` objects.
181+
* @property {boolean} tableCellAlignToStyle
182+
* Turn obsolete `align` props on `td` and `th` into CSS `style` props.
178183
*
179184
* @typedef {Record<string, string>} Style
180185
* Style map.
@@ -229,6 +234,8 @@ const dashSomething = /-([a-z])/g
229234
// See: <https://github.com/rehypejs/rehype-react/pull/45>.
230235
const tableElements = new Set(['table', 'tbody', 'thead', 'tfoot', 'tr'])
231236

237+
const tableCellElement = new Set(['td', 'th'])
238+
232239
/**
233240
* Transform a hast tree to preact, react, solid, svelte, vue, etc.,
234241
* with an automatic JSX runtime.
@@ -281,7 +288,8 @@ export function toJsxRuntime(tree, options) {
281288
passKeys: options.passKeys !== false,
282289
passNode: options.passNode || false,
283290
schema: options.space === 'svg' ? svg : html,
284-
stylePropertyNameCase: options.stylePropertyNameCase || 'dom'
291+
stylePropertyNameCase: options.stylePropertyNameCase || 'dom',
292+
tableCellAlignToStyle: options.tableCellAlignToStyle !== false
285293
}
286294

287295
const result = one(state, tree, undefined)
@@ -479,6 +487,9 @@ function createProperties(state, ancestors) {
479487
let prop
480488

481489
if ('properties' in node && node.properties) {
490+
/** @type {string | undefined} */
491+
let alignValue
492+
482493
for (prop in node.properties) {
483494
if (prop !== 'children' && own.call(node.properties, prop)) {
484495
const result = createProperty(
@@ -489,10 +500,34 @@ function createProperties(state, ancestors) {
489500
)
490501

491502
if (result) {
492-
props[result[0]] = result[1]
503+
const [key, value] = result
504+
505+
if (
506+
state.tableCellAlignToStyle &&
507+
key === 'align' &&
508+
typeof value === 'string' &&
509+
tableCellElement.has(node.tagName)
510+
) {
511+
alignValue = value
512+
} else {
513+
props[key] = value
514+
}
493515
}
494516
}
495517
}
518+
519+
if (alignValue) {
520+
// Assume style is an object.
521+
const style = /** @type {Style} */ (props.style || (props.style = {}))
522+
const cssField = 'text-align'
523+
style[
524+
state.stylePropertyNameCase === 'css'
525+
? // Note: test this when Solid doesn’t want to merge my upcoming PR.
526+
/* c8 ignore next */
527+
transformStyleToCssCasing(cssField)
528+
: cssField
529+
] = alignValue
530+
}
496531
}
497532

498533
return props
@@ -538,7 +573,7 @@ function createProperty(state, ancestors, prop, value) {
538573
: parseStyle(state, ancestors, String(value))
539574

540575
if (state.stylePropertyNameCase === 'css') {
541-
styleObject = transformStyleToCssCasing(styleObject)
576+
styleObject = transformStylesToCssCasing(styleObject)
542577
}
543578

544579
return ['style', styleObject]
@@ -619,24 +654,34 @@ function parseStyle(state, ancestors, value) {
619654
* @param {Style} domCasing
620655
* @returns {Style}
621656
*/
622-
function transformStyleToCssCasing(domCasing) {
657+
function transformStylesToCssCasing(domCasing) {
623658
/** @type {Style} */
624659
const cssCasing = {}
625660
/** @type {string} */
626661
let from
627662

628663
for (from in domCasing) {
629664
if (own.call(domCasing, from)) {
630-
let to = from.replace(cap, toDash)
631-
// Handle `ms-xxx` -> `-ms-xxx`.
632-
if (to.slice(0, 3) === 'ms-') to = '-' + to
633-
cssCasing[to] = domCasing[from]
665+
cssCasing[transformStyleToCssCasing(from)] = domCasing[from]
634666
}
635667
}
636668

637669
return cssCasing
638670
}
639671

672+
/**
673+
* Transform a DOM casing style field to a CSS casing style field.
674+
*
675+
* @param {string} from
676+
* @returns {string}
677+
*/
678+
function transformStyleToCssCasing(from) {
679+
let to = from.replace(cap, toDash)
680+
// Handle `ms-xxx` -> `-ms-xxx`.
681+
if (to.slice(0, 3) === 'ms-') to = '-' + to
682+
return to
683+
}
684+
640685
/**
641686
* Make `$1` capitalized.
642687
*

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
"prettier": true,
105105
"#": "`n` is wrong",
106106
"rules": {
107+
"max-depth": "off",
107108
"n/file-extension-in-import": "off",
108109
"unicorn/prefer-at": "off",
109110
"unicorn/prefer-string-replace-all": "off"

readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ Configuration (TypeScript type).
206206
([`StylePropertyNameCase`][api-style-property-name-case],
207207
default: `'dom'`)
208208
— specify casing to use for property names in `style` objects
209+
* `tableCellAlignToStyle`
210+
(`boolean`, default: `true`)
211+
— turn obsolete `align` props on `td` and `th` into CSS `style` props
209212

210213
### `Components`
211214

test/index.js

+57
Original file line numberDiff line numberDiff line change
@@ -596,3 +596,60 @@ test('react specific: filter whitespace in tables', async function (t) {
596596
}
597597
)
598598
})
599+
600+
test('react specific: `align` to `style`', async function (t) {
601+
const tree = h(null, [
602+
h('th', {style: 'color:red', align: 'center'}, 'alpha'),
603+
h('td', {style: 'background-color:blue;', align: 'left'}, 'bravo'),
604+
h('td', {align: 'right'}, 'charlie'),
605+
h('td', 'delta')
606+
])
607+
608+
await t.test(
609+
'should not transform `align` w/ `tableCellAlignToStyle: false`',
610+
async function () {
611+
assert.equal(
612+
renderToStaticMarkup(
613+
toJsxRuntime(tree, {...production, tableCellAlignToStyle: false})
614+
),
615+
'<th style="color:red" align="center">alpha</th><td style="background-color:blue" align="left">bravo</td><td align="right">charlie</td><td>delta</td>'
616+
)
617+
}
618+
)
619+
620+
await t.test(
621+
'should transform `align` w/o `tableCellAlignToStyle`',
622+
async function () {
623+
assert.equal(
624+
renderToStaticMarkup(toJsxRuntime(tree, production)),
625+
'<th style="color:red;text-align:center">alpha</th><td style="background-color:blue;text-align:left">bravo</td><td style="text-align:right">charlie</td><td>delta</td>'
626+
)
627+
}
628+
)
629+
630+
await t.test(
631+
"should suppoort `tableCellAlignToStyle` w/ `stylePropertyNameCase: 'css'`",
632+
async function () {
633+
/** @type {unknown} */
634+
let foundProps
635+
636+
assert.equal(
637+
renderToStaticMarkup(
638+
toJsxRuntime(h('td', {align: 'center'}), {
639+
...production,
640+
jsx(type, props) {
641+
foundProps = props
642+
return production.jsx(type, {})
643+
},
644+
stylePropertyNameCase: 'css'
645+
})
646+
),
647+
'<td></td>'
648+
)
649+
650+
assert.deepEqual(foundProps, {
651+
style: {'text-align': 'center'}
652+
})
653+
}
654+
)
655+
})

0 commit comments

Comments
 (0)