Add the Monolith and Cobalt Stripe templates

Standalone layouts for Canva templates 3 and 8, with the user's logo sized to the
placeholder box, a CapRule decor primitive, optional TableRows rule/heading options,
and a separate 1..45-row sweep test file.
This commit is contained in:
2026-10-04 11:25:19 +05:30
parent 5ea62a9be8
commit 385d7974cb
26 changed files with 2795 additions and 37 deletions
+21 -5
View File
@@ -141,6 +141,8 @@ export interface TableRowsProps extends TableLook {
roles: TableRoles;
/** Per column; default left. */
align?: Array<"left" | "right" | "center">;
/** Header alignment per column when it differs from the body's; default `align`. */
headAlign?: Array<"left" | "right" | "center">;
/** Passed as minPresenceAhead on the last row so the totals never start a page without an item row. */
tailH?: number;
/** Content after the last row, inside the table container (the totals). */
@@ -178,6 +180,12 @@ export interface TableRowsProps extends TableLook {
* of the container's left edge. Plan with planItemsTable at width - 2 * rowInset.
*/
pill?: { indent: number; inset: number };
/**
* Vertical rules between the columns only (no outer edges, no rule above the header): `width` after every column but
* the last, in `color` on body rows and `headerColor` in the header (default `color`). The cells stretch to the row's
* height. Plan with `innerRulePadRight(...)` added to the padding so wrapping uses the real inner width.
*/
innerRules?: { width: number; color: string; headerColor?: string };
}
/** Extra right padding per column that stands in for a grid's vertical rules, for planItemsTable's `padRight`. */
@@ -185,12 +193,17 @@ export function gridPadRight(columns: number, ruleWidth: number): number[] {
return Array.from({ length: columns }, (_, i) => (i === 0 ? 2 : 1) * ruleWidth);
}
/** Extra right padding per column that stands in for the inner rules of `innerRules`, for planItemsTable's `padRight`. */
export function innerRulePadRight(columns: number, ruleWidth: number): number[] {
return Array.from({ length: columns }, (_, i) => (i < columns - 1 ? ruleWidth : 0));
}
/**
* Header (a `fixed` first child, so it repeats on every page the table spans) followed by one
* `wrap={false}` row per item. The container has no padding or border; those go on the rows, because
* the repeated header is positioned against the container's top.
*/
export function TableRows({ columns, gap, width, header, rows, roles, align = [], tailH, tail, headerStyle, rowStyle, headCellStyle, borderColor, headColor, headerTail, grid, bleed, pill, ...look }: TableRowsProps) {
export function TableRows({ columns, gap, width, header, rows, roles, align = [], tailH, tail, headerStyle, rowStyle, headCellStyle, borderColor, headColor, headerTail, grid, bleed, pill, innerRules, headAlign, ...look }: TableRowsProps) {
const padX = look.padX ?? 0;
const padY = look.padY ?? 4;
const headPadY = look.headPadY ?? padY;
@@ -208,14 +221,17 @@ export function TableRows({ columns, gap, width, header, rows, roles, align = []
const last = i === values.length - 1;
const inner = isHeader ? (grid?.headerColor ?? grid?.color) : grid?.color;
const outer = isHeader ? (grid?.headerEdge ?? grid?.color) : grid?.color;
const ruleW = edge * (i === 0 ? 2 : 1);
const inner2 = innerRules && !last ? innerRules.width : 0;
const ruleW = grid ? edge * (i === 0 ? 2 : 1) : inner2;
const alignOf = isHeader ? (headAlign?.[i] ?? align[i]) : align[i];
return (
<Cell
key={i}
padding={{ top: isHeader ? headPadY : padY, bottom: isHeader ? headPadY : padY, left: padX + (look.padLeft?.[i] ?? 0), right: padX + (look.padRight?.[i] ?? 0) }}
borderLeft={grid && i === 0 ? edge : 0}
borderRight={edge}
borderRight={grid ? edge : inner2}
style={{
...(innerRules ? { flexGrow: 1, flexBasis: "auto", ...(inner2 ? { borderRightColor: isHeader ? (innerRules.headerColor ?? innerRules.color) : innerRules.color } : {}) } : {}),
...(grid
? {
flexGrow: 1,
@@ -229,14 +245,14 @@ export function TableRows({ columns, gap, width, header, rows, roles, align = []
}}
>
{cellParts(v).map((part, li) => (
<Txt key={li} role={partRole(part, role)} color={color} width={Math.max(0, widths[i] - 2 * padX - (look.padRight?.[i] ?? 0) - (look.padLeft?.[i] ?? 0) - ruleW)} align={align[i]} faceOverrides={look.faceOverrides}>
<Txt key={li} role={partRole(part, role)} color={color} width={Math.max(0, widths[i] - 2 * padX - (look.padRight?.[i] ?? 0) - (look.padLeft?.[i] ?? 0) - ruleW)} align={alignOf} faceOverrides={look.faceOverrides}>
{partText(part)}
</Txt>
))}
</Cell>
);
});
const rowAlign = grid ? ("stretch" as const) : undefined;
const rowAlign = grid || innerRules ? ("stretch" as const) : undefined;
const inset = pill?.inset ?? 0;
const cellsWidth = width - 2 * inset;
/** One table line: a plain Row, or for pills an outer box (the fill) around a Row of the inner width. */