Fixed numbered/bulleted lists
X-Lovable-Edit-ID: edt-4aee7814-50ef-4eaa-b6fd-cf25b979decb Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
@@ -395,6 +395,7 @@ export function CustomFormBuilder() {
|
||||
indent: number;
|
||||
caption?: boolean;
|
||||
heading?: 0 | 1 | 2 | 3;
|
||||
marker?: string; // list marker prefix like "1." or "•"
|
||||
}
|
||||
| { kind: "table"; rows: TableCellSeg[][] };
|
||||
|
||||
@@ -472,6 +473,44 @@ export function CustomFormBuilder() {
|
||||
tmp.innerHTML = html;
|
||||
const out: Segment[] = [];
|
||||
|
||||
const LIST_INDENT = 24; // px per nesting level
|
||||
|
||||
const pushListItems = (
|
||||
listEl: HTMLElement,
|
||||
ordered: boolean,
|
||||
depth: number,
|
||||
) => {
|
||||
const items = Array.from(listEl.children).filter(
|
||||
(c) => (c as HTMLElement).tagName.toLowerCase() === "li",
|
||||
) as HTMLElement[];
|
||||
let n = 1;
|
||||
for (const li of items) {
|
||||
// Collect inline runs from this li, excluding nested lists.
|
||||
const inlineNodes = Array.from(li.childNodes).filter((c) => {
|
||||
if (c.nodeType !== Node.ELEMENT_NODE) return true;
|
||||
const t = (c as HTMLElement).tagName.toLowerCase();
|
||||
return t !== "ol" && t !== "ul";
|
||||
});
|
||||
const runs: InlineRun[] = [];
|
||||
inlineNodes.forEach((n) => runs.push(...collectRuns(n)));
|
||||
const merged = mergeRuns(runs);
|
||||
out.push({
|
||||
kind: "text",
|
||||
runs: merged,
|
||||
align: "left",
|
||||
indent: depth * LIST_INDENT,
|
||||
marker: ordered ? `${n}.` : "•",
|
||||
});
|
||||
n += 1;
|
||||
// Recurse into any nested lists.
|
||||
Array.from(li.children).forEach((child) => {
|
||||
const tag = (child as HTMLElement).tagName.toLowerCase();
|
||||
if (tag === "ol") pushListItems(child as HTMLElement, true, depth + 1);
|
||||
else if (tag === "ul") pushListItems(child as HTMLElement, false, depth + 1);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const pushBlock = (el: HTMLElement) => {
|
||||
const tag = el.tagName.toLowerCase();
|
||||
if (tag === "table") {
|
||||
@@ -489,7 +528,9 @@ export function CustomFormBuilder() {
|
||||
out.push({ kind: "table", rows });
|
||||
return;
|
||||
}
|
||||
if (["p", "h1", "h2", "h3", "li"].includes(tag)) {
|
||||
if (tag === "ol") return pushListItems(el, true, 0);
|
||||
if (tag === "ul") return pushListItems(el, false, 0);
|
||||
if (["p", "h1", "h2", "h3"].includes(tag)) {
|
||||
const align = (el.style.textAlign as any) || "left";
|
||||
const indentPx = parseInt(el.style.paddingLeft || "0", 10) || 0;
|
||||
const caption = el.getAttribute("data-caption") === "true";
|
||||
@@ -504,7 +545,7 @@ export function CustomFormBuilder() {
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Recurse into wrappers (lists, etc.)
|
||||
// Recurse into wrappers we don't recognize.
|
||||
Array.from(el.children).forEach((child) => pushBlock(child as HTMLElement));
|
||||
};
|
||||
|
||||
@@ -717,7 +758,10 @@ export function CustomFormBuilder() {
|
||||
const indentPt = indentPx * 0.75; // px → pt
|
||||
const segMaxW = maxW - indentPt;
|
||||
const startX = margin + indentPt;
|
||||
const visualLines = runsToLines(seg.runs);
|
||||
const runsForLayout: InlineRun[] = seg.marker
|
||||
? [{ text: `${seg.marker} ` }, ...seg.runs]
|
||||
: seg.runs;
|
||||
const visualLines = runsToLines(runsForLayout);
|
||||
if (visualLines.length === 0 || (visualLines.length === 1 && visualLines[0].length === 0)) {
|
||||
y += lineH;
|
||||
} else {
|
||||
@@ -858,12 +902,19 @@ export function CustomFormBuilder() {
|
||||
? AlignmentType.JUSTIFIED
|
||||
: AlignmentType.LEFT;
|
||||
const indentTwips = Math.round((seg.indent || 0) * 15); // ~px → twips (1px≈15twip)
|
||||
const baseRuns = buildDocxRuns(seg.runs, { italic: seg.caption });
|
||||
const runsWithMarker = seg.marker
|
||||
? [
|
||||
new TextRun({ text: `${seg.marker}\t`, font: fontFamily, size: fontSize * 2 }),
|
||||
...baseRuns,
|
||||
]
|
||||
: baseRuns;
|
||||
children.push(
|
||||
new DocxParagraph({
|
||||
alignment: align,
|
||||
spacing: docxLineSpacing,
|
||||
indent: indentTwips ? { left: indentTwips } : undefined,
|
||||
children: buildDocxRuns(seg.runs, { italic: seg.caption }),
|
||||
indent: indentTwips ? { left: indentTwips, hanging: seg.marker ? 360 : undefined } : seg.marker ? { left: 360, hanging: 360 } : undefined,
|
||||
children: runsWithMarker,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user