import React from "react"; import * as std from "../../law/std"; import { assertNever } from "../../util"; import type { HTMLComponentProps } from "../common/html"; import { elProps, wrapHTMLComponent } from "../common/html"; import { DOCXSentenceChildrenRun, HTMLSentenceChildrenRun } from "./sentenceChildrenRun"; import type { DOCXComponentProps } from "../common/docx/component"; import { wrapDOCXComponent } from "../common/docx/component"; import { w } from "../common/docx/tags"; import { DOCXParagraphItem, HTMLParagraphItem } from "./paragraphItem"; import { DOCXColumnsOrSentencesRun, HTMLColumnsOrSentencesRun } from "./columnsOrSentencesRun"; import { DOCXArticleGroup, HTMLArticleGroup } from "./articleGroup"; import { DOCXArticle, HTMLArticle } from "./article"; import { newStdEL } from "../../law/std"; import { DOCXRemarks, HTMLRemarks } from "./remarks"; import { DOCXItemStruct, HTMLItemStruct } from "./itemStruct"; import { withKey } from "../common"; export interface TableProps { el: std.Table, indent: number, } export const HTMLTableCSS = /*css*/` .table { border-collapse: collapse; text-indent: 0; table-layout: fixed; width: calc(100% - var(--margin-left)); } .table-column { border: 1px solid black; min-height: 1em; height: 1em; } .table-header-column { border: 1px solid black; min-height: 1em; height: 1em; } `; export const HTMLTable = wrapHTMLComponent("HTMLTable", ((props: HTMLComponentProps & TableProps) => { const { el, htmlOptions, indent } = props; const rows: React.JSX.Element[] = []; for (const child of el.children) { if ( std.isTableRow(child) || std.isTableHeaderRow(child) ) { rows.push(); } else { assertNever(child); } } return ( {withKey(rows)}
); })); export interface TableRowProps { el: std.TableRow | std.TableHeaderRow, } export const HTMLTableRow = wrapHTMLComponent("HTMLTableRow", ((props: HTMLComponentProps & TableRowProps) => { const { el, htmlOptions } = props; const columns: React.JSX.Element[] = []; for (const child of el.children) { if ( std.isTableColumn(child) || std.isTableHeaderColumn(child) ) { columns.push(); } else { assertNever(child); } } return ( {withKey(columns)} ); })); export interface TableColumnProps { el: std.TableColumn | std.TableHeaderColumn, } export const HTMLTableColumn = wrapHTMLComponent("HTMLTableColumn", ((props: HTMLComponentProps & TableColumnProps) => { const { el, htmlOptions } = props; const blocks: React.JSX.Element[] = []; if (std.isTableHeaderColumn(el)) { blocks.push((
)); } else if (std.isTableColumn(el)) { if (el.children.every(std.isColumn)) { blocks.push((
)); } else if (el.children.every(std.isSentence)) { for (const child of el.children) { blocks.push((
)); } } else { for (const child of el.children) { if (child.tag === "Sentence" || child.tag === "Column") { blocks.push((
)); } else if (std.isFigStruct(child)) { blocks.push(); } else if (std.isRemarks(child)) { blocks.push(); } else if (std.isArticleGroup(child)) { blocks.push(( )); } else if (std.isArticle(child)) { blocks.push(( )); } else if (std.isParagraphItem(child)) { blocks.push(( )); } else { assertNever(child); } } } } else { assertNever(el); } const style: React.CSSProperties = {}; if (el.attr.BorderTop) style.borderTopStyle = el.attr.BorderTop; if (el.attr.BorderBottom) style.borderBottomStyle = el.attr.BorderBottom; if (el.attr.BorderLeft) style.borderLeftStyle = el.attr.BorderLeft; if (el.attr.BorderRight) style.borderRightStyle = el.attr.BorderRight; if (el.attr.Align) style.textAlign = el.attr.Align; if (el.attr.Valign) style.verticalAlign = el.attr.Valign; const attr = { style, ...((el.attr.rowspan !== undefined) ? { rowSpan: Number(el.attr.rowspan) } : {}), ...((el.attr.colspan !== undefined) ? { colSpan: Number(el.attr.colspan) } : {}), }; if (std.isTableHeaderColumn(el)) { return ( {withKey(blocks)} ); } else { return ( {withKey(blocks)} ); } })); const restructureTable = (table: std.Table): std.Table => { const newTableChildren: std.Table["children"] = []; const rowspanState: Record = {}; const colspanValue: Record = {}; for (const row of table.children) { const newRowChildren: (typeof row)["children"][number][] = []; let c = 0; let ci = 0; while (true) { const rss = rowspanState[c] || 0; if (rss) { const colspan = colspanValue[c] || 0; newRowChildren.push(std.newStdEL( std.isTableHeaderRow(row) ? "TableHeaderColumn" : "TableColumn", { __merged: "__merged", ...( colspan ? { colspan: `${colspan}`, } : {} ), }, [], )); rowspanState[c] = rss - 1; if (colspan) { c += colspan - 1; } c += 1; continue; } if (ci >= row.children.length) { break; } const column = row.children[ci]; newRowChildren.push(column.copy(true) as typeof column); { const colspan = Number(column.attr.colspan || 0); if (column.attr.rowspan !== undefined) { const rowspan = Number(column.attr.rowspan); rowspanState[c] = rowspan - 1; colspanValue[c] = colspan; if (colspan) { c += colspan - 1; } } c += 1; ci += 1; } } newTableChildren.push(newStdEL( row.tag, { ...row.attr }, newRowChildren, )); } const ret = newStdEL( table.tag, { ...table.attr }, newTableChildren, ); return ret; }; export const DOCXTable = wrapDOCXComponent("DOCXTable", ((props: DOCXComponentProps & TableProps) => { const { el: origEL, docxOptions, indent } = props; const rows: React.JSX.Element[] = []; const el = restructureTable(origEL); for (const child of el.children) { if ( std.isTableRow(child) || std.isTableHeaderRow(child) ) { rows.push(); } else { assertNever(child); } } return ( {withKey(rows)} ); })); export interface TableRowProps { el: std.TableRow | std.TableHeaderRow, } export const DOCXTableRow = wrapDOCXComponent("DOCXTableRow", ((props: DOCXComponentProps & TableRowProps) => { const { el, docxOptions } = props; const columns: React.JSX.Element[] = []; for (const child of el.children) { if ( std.isTableColumn(child) || std.isTableHeaderColumn(child) ) { columns.push(); } else { assertNever(child); } } return ( {withKey(columns)} ); })); export interface TableColumnProps { el: std.TableColumn | std.TableHeaderColumn, } const valignDict = { top: "top", middle: "center", bottom: "bottom", }; const borderDict = { none: "nil", solid: "single", dotted: "dotted", double: "double", }; export const DOCXTableColumn = wrapDOCXComponent("DOCXTableColumn", ((props: DOCXComponentProps & TableColumnProps) => { const { el, docxOptions } = props; const blocks: React.JSX.Element[] = []; if (std.isTableHeaderColumn(el)) { blocks.push(( )); } else if (std.isTableColumn(el)) { if (el.children.every(std.isColumn)) { blocks.push(( )); } else if (el.children.every(std.isSentence)) { for (const child of el.children) { blocks.push(( )); } } else { for (const child of el.children) { if (child.tag === "Sentence" || child.tag === "Column") { blocks.push(( )); } else if (std.isFigStruct(child)) { blocks.push(); } else if (std.isRemarks(child)) { blocks.push(); } else if (std.isArticleGroup(child)) { blocks.push(( )); } else if (std.isArticle(child)) { blocks.push(( )); } else if (std.isParagraphItem(child)) { blocks.push(( )); } else { assertNever(child); } } } } else { assertNever(el); } if ((el.attr as Record).__merged !== undefined) { return ( {(el.attr.colspan !== undefined) && } ); } else { return ( {(el.attr.colspan !== undefined) && } {(el.attr.rowspan !== undefined) && } {(el.attr.Align !== undefined) && } {(el.attr.Valign !== undefined) && } {((el.attr.BorderTop ?? el.attr.BorderBottom ?? el.attr.BorderLeft ?? el.attr.BorderRight) !== undefined) && ( {(el.attr.BorderTop !== undefined) && } {(el.attr.BorderBottom !== undefined) && } {(el.attr.BorderLeft !== undefined) && } {(el.attr.BorderRight !== undefined) && } )} {withKey(blocks)} ); } }));