Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table Formatting #43

Open
generalleger opened this issue Oct 25, 2023 · 5 comments
Open

Table Formatting #43

generalleger opened this issue Oct 25, 2023 · 5 comments
Labels
help wanted Extra attention is needed

Comments

@generalleger
Copy link

Hi - Thanks for making this library. It's great! I have a question. I am trying to format a table where the conversion to docx format occurs on the server (node). I am using remark-gfm to create the table, but it has no style. Is it possible to pass docx table styles into remark-docx?

So far, I think docx doesn't provide the ability to edit, outside of the patcher which only lets you add things. However, I have a table in the middle of the markdown. Also, it doesn't look like docx style options like paragraphStyles, default , or document styles accept options formatting tables. As far as I can tell, it seems like table styles must be passed into docx when the table is created new Table, new Row, and new Cell. So, if I understand everything correctly, if there were to be table styles, they'd have to be applied when the table is created within remark-docx.

Any ideas on how that might work? Thanks!

  const processor = unified()
    .use(remarkParse)
    .use(markdown)
    .use(remarkBreaks)
    .use(remarkGfm)
    .use(docx, { output: 'buffer', styles });
@inokawa
Copy link
Owner

inokawa commented Oct 25, 2023

Hello,
I'm not familiar to table options of docx however it looks like that some options are not existed in global as you mentioned.
https://docx.js.org/#/usage/tables

I have no time to implement them as an option of remark-docx but any contributions are welcome!

@inokawa inokawa added the help wanted Extra attention is needed label Oct 25, 2023
@generalleger
Copy link
Author

Thanks for responding so quickly. I'm going to put a little time into seeing if there is a workable solution. Thanks again!!

@generalleger
Copy link
Author

generalleger commented Oct 25, 2023

Okay, I got something working that will suit my needs in the short term. It's not amazing, but it works! Thankfully your code is easy to read and understand! I wanted to leave the changes here in case this is helpful to anyone else.

I added a tableStyles object to the options. It is structured so that it provides for table options, a header row, and body rows. This is really all I need for now.

That object looks like this and I added it to the DocxOptions interface:

export type TableStyle = {
  options: Omit<ITableOptions, 'rows'>,
  header: {
    row: ITableRowPropertiesOptions,
    cell: ITableCellPropertiesOptions,
    paragraph: IParagraphPropertiesOptions
  },
  body: {
    row: ITableRowPropertiesOptions,
    cell: ITableCellPropertiesOptions,
    paragraph: IParagraphPropertiesOptions
  },
}

It is passed in like so:

  const processor = unified()
    .use(remarkParse)
    .use(remarkGfm)
    .use(docx, { output: 'buffer', tableStyle });

That object is then passed into the context.

const mdastToDocx = async (node, { output = 'buffer', title, subject, creator, keywords, description, lastModifiedBy, revision, styles, background, tableStyle }, images) => {

  const { nodes, footnotes } = convertNodes(node.children, {
    deco: {},
    images,
    indent: 0,
    tableStyle
  },);

...

The Table, Row, Cell, and Paragraph constructors then apply the options and styles.

const buildTable = ({ children, align }, ctx) => {
  const cellAligns = align === null || align === void 0 ? void 0 : align.map((a) => {
    switch (a) {
      case 'left':
        return docx.AlignmentType.LEFT;
      case 'right':
        return docx.AlignmentType.RIGHT;
      case 'center':
        return docx.AlignmentType.CENTER;
      default:
        return docx.AlignmentType.LEFT;
    }
  });
  return new docx.Table({
    ...ctx.tableStyle.options,
    rows: children.map((r, i) => {
      const style = i === 0 ? ctx.tableStyle.header : ctx.tableStyle.body;
      return buildTableRow(r, ctx, cellAligns, style);
    }),
  });
};
const buildTableRow = ({ children }, ctx, cellAligns, style) => {
  return new docx.TableRow({
    ...style.row,
    children: children.map((c, i) => {
      return buildTableCell(c, ctx, cellAligns === null || cellAligns === void 0 ? void 0 : cellAligns[i], style);
    }),
  });
};
const buildTableCell = ({ children }, ctx, align, style) => {
  const { nodes } = convertNodes(children, ctx);
  return new docx.TableCell({
    ...style.cell,
    children: [
      new docx.Paragraph({
        ...style.paragraph,
        alignment: align,
        children: nodes,
      }),
    ],
  });
};

@PauloJSGG
Copy link

PauloJSGG commented Jun 26, 2024

Hi all, I need @generalleger 's code as well. Don't you think a PR is needed? I think it's actually an important addition to the package. Without it the table becomes pretty much unusable.

Thank you

@generalleger
Copy link
Author

Hi all, I need @generalleger 's code as well. Don't you think a PR is needed? I think it's actually an important addition to the package. Without it the table becomes pretty much unusable.

Thank you

Paulo - my code is pretty hacky - and I've since modified again to add a title page based on other data internal to my application. So, the code quality is not good enough for a PR. The code mods I described above should work though. If you can't get it to work, let me know and I'll try to post it to my public GH.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants