Skip to content

Commit

Permalink
Add tableCellAlignToStyle option
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Sep 1, 2023
1 parent 478379f commit a439dc9
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 8 deletions.
61 changes: 53 additions & 8 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@
* @property {StylePropertyNameCase | null | undefined} [stylePropertyNameCase='dom']
* Specify casing to use for property names in `style` objects (default:
* `'dom'`).
* @property {boolean | null | undefined} [tableCellAlignToStyle=true]
* Turn obsolete `align` props on `td` and `th` into CSS `style` props
* (default: `true`).
*
* @typedef RuntimeDevelopment
* Runtime fields when development is on.
Expand Down Expand Up @@ -175,6 +178,8 @@
* Current schema.
* @property {StylePropertyNameCase} stylePropertyNameCase
* Casing to use for property names in `style` objects.
* @property {boolean} tableCellAlignToStyle
* Turn obsolete `align` props on `td` and `th` into CSS `style` props.
*
* @typedef {Record<string, string>} Style
* Style map.
Expand Down Expand Up @@ -229,6 +234,8 @@ const dashSomething = /-([a-z])/g
// See: <https://github.com/rehypejs/rehype-react/pull/45>.
const tableElements = new Set(['table', 'tbody', 'thead', 'tfoot', 'tr'])

const tableCellElement = new Set(['td', 'th'])

/**
* Transform a hast tree to preact, react, solid, svelte, vue, etc.,
* with an automatic JSX runtime.
Expand Down Expand Up @@ -281,7 +288,8 @@ export function toJsxRuntime(tree, options) {
passKeys: options.passKeys !== false,
passNode: options.passNode || false,
schema: options.space === 'svg' ? svg : html,
stylePropertyNameCase: options.stylePropertyNameCase || 'dom'
stylePropertyNameCase: options.stylePropertyNameCase || 'dom',
tableCellAlignToStyle: options.tableCellAlignToStyle !== false
}

const result = one(state, tree, undefined)
Expand Down Expand Up @@ -479,6 +487,9 @@ function createProperties(state, ancestors) {
let prop

if ('properties' in node && node.properties) {
/** @type {string | undefined} */
let alignValue

for (prop in node.properties) {
if (prop !== 'children' && own.call(node.properties, prop)) {
const result = createProperty(
Expand All @@ -489,10 +500,34 @@ function createProperties(state, ancestors) {
)

if (result) {
props[result[0]] = result[1]
const [key, value] = result

if (
state.tableCellAlignToStyle &&
key === 'align' &&
typeof value === 'string' &&
tableCellElement.has(node.tagName)
) {
alignValue = value
} else {
props[key] = value
}
}
}
}

if (alignValue) {
// Assume style is an object.
const style = /** @type {Style} */ (props.style || (props.style = {}))
const cssField = 'text-align'
style[
state.stylePropertyNameCase === 'css'
? // Note: test this when Solid doesn’t want to merge my upcoming PR.
/* c8 ignore next */
transformStyleToCssCasing(cssField)
: cssField
] = alignValue
}
}

return props
Expand Down Expand Up @@ -538,7 +573,7 @@ function createProperty(state, ancestors, prop, value) {
: parseStyle(state, ancestors, String(value))

if (state.stylePropertyNameCase === 'css') {
styleObject = transformStyleToCssCasing(styleObject)
styleObject = transformStylesToCssCasing(styleObject)
}

return ['style', styleObject]
Expand Down Expand Up @@ -619,24 +654,34 @@ function parseStyle(state, ancestors, value) {
* @param {Style} domCasing
* @returns {Style}
*/
function transformStyleToCssCasing(domCasing) {
function transformStylesToCssCasing(domCasing) {
/** @type {Style} */
const cssCasing = {}
/** @type {string} */
let from

for (from in domCasing) {
if (own.call(domCasing, from)) {
let to = from.replace(cap, toDash)
// Handle `ms-xxx` -> `-ms-xxx`.
if (to.slice(0, 3) === 'ms-') to = '-' + to
cssCasing[to] = domCasing[from]
cssCasing[transformStyleToCssCasing(from)] = domCasing[from]
}
}

return cssCasing
}

/**
* Transform a DOM casing style field to a CSS casing style field.
*
* @param {string} from
* @returns {string}
*/
function transformStyleToCssCasing(from) {
let to = from.replace(cap, toDash)
// Handle `ms-xxx` -> `-ms-xxx`.
if (to.slice(0, 3) === 'ms-') to = '-' + to
return to
}

/**
* Make `$1` capitalized.
*
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"prettier": true,
"#": "`n` is wrong",
"rules": {
"max-depth": "off",
"n/file-extension-in-import": "off",
"unicorn/prefer-at": "off",
"unicorn/prefer-string-replace-all": "off"
Expand Down
3 changes: 3 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ Configuration (TypeScript type).
([`StylePropertyNameCase`][api-style-property-name-case],
default: `'dom'`)
— specify casing to use for property names in `style` objects
* `tableCellAlignToStyle`
(`boolean`, default: `true`)
— turn obsolete `align` props on `td` and `th` into CSS `style` props

### `Components`

Expand Down
57 changes: 57 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -596,3 +596,60 @@ test('react specific: filter whitespace in tables', async function (t) {
}
)
})

test('react specific: `align` to `style`', async function (t) {
const tree = h(null, [
h('th', {style: 'color:red', align: 'center'}, 'alpha'),
h('td', {style: 'background-color:blue;', align: 'left'}, 'bravo'),
h('td', {align: 'right'}, 'charlie'),
h('td', 'delta')
])

await t.test(
'should not transform `align` w/ `tableCellAlignToStyle: false`',
async function () {
assert.equal(
renderToStaticMarkup(
toJsxRuntime(tree, {...production, tableCellAlignToStyle: false})
),
'<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>'
)
}
)

await t.test(
'should transform `align` w/o `tableCellAlignToStyle`',
async function () {
assert.equal(
renderToStaticMarkup(toJsxRuntime(tree, production)),
'<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>'
)
}
)

await t.test(
"should suppoort `tableCellAlignToStyle` w/ `stylePropertyNameCase: 'css'`",
async function () {
/** @type {unknown} */
let foundProps

assert.equal(
renderToStaticMarkup(
toJsxRuntime(h('td', {align: 'center'}), {
...production,
jsx(type, props) {
foundProps = props
return production.jsx(type, {})
},
stylePropertyNameCase: 'css'
})
),
'<td></td>'
)

assert.deepEqual(foundProps, {
style: {'text-align': 'center'}
})
}
)
})

0 comments on commit a439dc9

Please sign in to comment.