@ganttloom/gantt-export 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/paginate.ts","../src/geom.ts","../src/layout.ts","../src/color.ts"],"sourcesContent":["import type { GanttRenderModel } from \"@ganttloom/gantt-core\";\n\n/**\n * Shared pagination math used by both the PDF and PPTX writers.\n *\n * A GanttRenderModel can be far taller (many rows) and wider (long date\n * range) than a single printed page/slide. We tile the full model into a\n * grid of (rowBand, colBand) pages: the grid panel (task list columns) is\n * repeated on every page, while the timeline (bars/links/ticks) is sliced\n * into vertical/horizontal bands so nothing is dropped or duplicated.\n */\n\nexport type PageSizeName = \"A4\" | \"Letter\" | \"A3\";\nexport type Orientation = \"portrait\" | \"landscape\";\n\nconst PAGE_SIZES_PT: Record<PageSizeName, { width: number; height: number }> = {\n // Values are the portrait (short-edge width x long-edge height) dimensions\n // in PDF/typographic points (72pt = 1in).\n A4: { width: 595.28, height: 841.89 },\n Letter: { width: 612, height: 792 },\n A3: { width: 841.89, height: 1190.55 },\n};\n\nexport interface Margins {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nexport interface PageSizeOption {\n name?: PageSizeName;\n orientation?: Orientation;\n /** escape hatch: exact page dimensions in points, overrides name/orientation */\n custom?: { widthPt: number; heightPt: number };\n}\n\nexport interface PaginationOptions {\n pageSize?: PageSizeOption;\n margins?: Partial<Margins>;\n /** px -> pt scale factor. Default 0.75 (96 CSS px/in -> 72pt/in). */\n scale?: number;\n /** override the auto-computed (sum of column widths) grid panel width, in px */\n gridPanelWidthPx?: number;\n}\n\nexport interface Band {\n start: number;\n end: number;\n}\n\nexport interface PageBand {\n rowBand: number;\n colBand: number;\n /** row slice bounds, in model px coordinates (model.rows[].y space) */\n rowStartY: number;\n rowEndY: number;\n /** timeline slice bounds, in model px coordinates (model.bars[].x space) */\n colStartX: number;\n colEndX: number;\n}\n\nexport interface PaginationLayout {\n pageWidthPt: number;\n pageHeightPt: number;\n margins: Margins;\n /** px -> pt scale factor in effect */\n scale: number;\n gridPanelWidthPx: number;\n gridPanelWidthPt: number;\n headerHeightPx: number;\n headerHeightPt: number;\n /** width of the timeline area available per page, in px (model space) */\n timelineWidthPxPerPage: number;\n /** height of the rows area available per page, in px (model space) */\n rowsHeightPxPerPage: number;\n rowBands: Band[];\n colBands: Band[];\n pages: PageBand[];\n rowCount: number;\n colCount: number;\n}\n\nconst DEFAULT_MARGIN_PT = 36; // 0.5in\nconst DEFAULT_SCALE = 0.75; // 96 css px/in -> 72pt/in\nconst MIN_TIMELINE_WIDTH_PT = 50;\nconst MIN_ROWS_HEIGHT_PT = 20;\n\nexport function resolvePageSize(opt?: PageSizeOption): { width: number; height: number } {\n if (opt?.custom) {\n return { width: opt.custom.widthPt, height: opt.custom.heightPt };\n }\n const name = opt?.name ?? \"A4\";\n const base = PAGE_SIZES_PT[name];\n const orientation = opt?.orientation ?? \"landscape\";\n const short = Math.min(base.width, base.height);\n const long = Math.max(base.width, base.height);\n return orientation === \"landscape\" ? { width: long, height: short } : { width: short, height: long };\n}\n\nfunction defaultGridPanelWidthPx(model: GanttRenderModel): number {\n const cols = model.columns ?? [];\n if (cols.length === 0) return 160; // fallback single \"task name\" column\n return cols.reduce((sum, c) => sum + (c.width ?? 120), 0);\n}\n\nexport function computePagination(\n model: GanttRenderModel,\n options: PaginationOptions = {},\n): PaginationLayout {\n const { width: pageWidthPt, height: pageHeightPt } = resolvePageSize(options.pageSize);\n const margins: Margins = {\n top: options.margins?.top ?? DEFAULT_MARGIN_PT,\n right: options.margins?.right ?? DEFAULT_MARGIN_PT,\n bottom: options.margins?.bottom ?? DEFAULT_MARGIN_PT,\n left: options.margins?.left ?? DEFAULT_MARGIN_PT,\n };\n const scale = options.scale ?? DEFAULT_SCALE;\n const gridPanelWidthPx = options.gridPanelWidthPx ?? defaultGridPanelWidthPx(model);\n const gridPanelWidthPt = gridPanelWidthPx * scale;\n const headerHeightPx = model.headerHeight;\n const headerHeightPt = headerHeightPx * scale;\n\n const contentWidthPt = pageWidthPt - margins.left - margins.right;\n const contentHeightPt = pageHeightPt - margins.top - margins.bottom;\n\n const timelineWidthPtPerPage = Math.max(contentWidthPt - gridPanelWidthPt, MIN_TIMELINE_WIDTH_PT);\n const rowsHeightPtPerPage = Math.max(contentHeightPt - headerHeightPt, MIN_ROWS_HEIGHT_PT);\n\n const timelineWidthPxPerPage = timelineWidthPtPerPage / scale;\n const rowsHeightPxPerPage = rowsHeightPtPerPage / scale;\n\n const totalHeightPx = Math.max(model.height, 1);\n const totalWidthPx = Math.max(model.width, 1);\n\n const rowCount = Math.max(1, Math.ceil(totalHeightPx / rowsHeightPxPerPage));\n const colCount = Math.max(1, Math.ceil(totalWidthPx / timelineWidthPxPerPage));\n\n const rowBands: Band[] = [];\n for (let i = 0; i < rowCount; i++) {\n rowBands.push({\n start: i * rowsHeightPxPerPage,\n end: Math.min(totalHeightPx, (i + 1) * rowsHeightPxPerPage),\n });\n }\n const colBands: Band[] = [];\n for (let i = 0; i < colCount; i++) {\n colBands.push({\n start: i * timelineWidthPxPerPage,\n end: Math.min(totalWidthPx, (i + 1) * timelineWidthPxPerPage),\n });\n }\n\n const pages: PageBand[] = [];\n for (let r = 0; r < rowCount; r++) {\n const rowBand = rowBands[r]!;\n for (let c = 0; c < colCount; c++) {\n const colBand = colBands[c]!;\n pages.push({\n rowBand: r,\n colBand: c,\n rowStartY: rowBand.start,\n rowEndY: rowBand.end,\n colStartX: colBand.start,\n colEndX: colBand.end,\n });\n }\n }\n\n return {\n pageWidthPt,\n pageHeightPt,\n margins,\n scale,\n gridPanelWidthPx,\n gridPanelWidthPt,\n headerHeightPx,\n headerHeightPt,\n timelineWidthPxPerPage,\n rowsHeightPxPerPage,\n rowBands,\n colBands,\n pages,\n rowCount,\n colCount,\n };\n}\n\nexport interface ClipRect {\n x0: number;\n y0: number;\n x1: number;\n y1: number;\n}\n\n/** Liang-Barsky line-segment clipping against an axis-aligned rectangle. */\nexport function clipSegment(\n x0: number,\n y0: number,\n x1: number,\n y1: number,\n rect: ClipRect,\n): { x0: number; y0: number; x1: number; y1: number } | null {\n let t0 = 0;\n let t1 = 1;\n const dx = x1 - x0;\n const dy = y1 - y0;\n const checks: Array<[number, number]> = [\n [-dx, x0 - rect.x0],\n [dx, rect.x1 - x0],\n [-dy, y0 - rect.y0],\n [dy, rect.y1 - y0],\n ];\n for (const [p, q] of checks) {\n if (p === 0) {\n if (q < 0) return null;\n } else {\n const r = q / p;\n if (p < 0) {\n if (r > t1) return null;\n if (r > t0) t0 = r;\n } else {\n if (r < t0) return null;\n if (r < t1) t1 = r;\n }\n }\n }\n return { x0: x0 + t0 * dx, y0: y0 + t0 * dy, x1: x0 + t1 * dx, y1: y0 + t1 * dy };\n}\n\n/** Clip an axis-aligned rectangle against a band; null if fully outside. */\nexport function clipRect(\n x: number,\n y: number,\n w: number,\n h: number,\n rect: ClipRect,\n): { x: number; y: number; w: number; h: number } | null {\n const x0 = Math.max(x, rect.x0);\n const y0 = Math.max(y, rect.y0);\n const x1 = Math.min(x + w, rect.x1);\n const y1 = Math.min(y + h, rect.y1);\n if (x1 <= x0 || y1 <= y0) return null;\n return { x: x0, y: y0, w: x1 - x0, h: y1 - y0 };\n}\n","import type { GanttRenderBar } from \"@ganttloom/gantt-core\";\nimport { clipSegment, type ClipRect } from \"./paginate.js\";\n\n/**\n * Dependency-link geometry.\n *\n * NOTE on design choice: GanttRenderLink.path is an SVG path \"d\" string\n * produced by gantt-core for on-screen rendering. Rather than writing an SVG\n * path parser (and a bezier-vs-page-boundary clipper) we recompute a simple\n * orthogonal \"elbow\" polyline directly from the two bars' resolved geometry\n * (GanttRenderBar.x/y/width/height, looked up by taskId). This is simpler,\n * avoids a dependency-free SVG parser, and is trivial to clip correctly at\n * page/slide boundaries using straight-line (Liang-Barsky) clipping.\n */\n\nexport interface Point {\n x: number;\n y: number;\n}\n\nexport function computeLinkPolyline(fromBar: GanttRenderBar, toBar: GanttRenderBar): Point[] {\n const x0 = fromBar.x + fromBar.width;\n const y0 = fromBar.y + fromBar.height / 2;\n const x1 = toBar.x;\n const y1 = toBar.y + toBar.height / 2;\n if (Math.abs(y1 - y0) < 0.01) {\n return [{ x: x0, y: y0 }, { x: x1, y: y1 }];\n }\n const midX = x0 + (x1 - x0) / 2;\n return [\n { x: x0, y: y0 },\n { x: midX, y: y0 },\n { x: midX, y: y1 },\n { x: x1, y: y1 },\n ];\n}\n\n/**\n * Clip a polyline against a rectangle, returning zero or more visible\n * sub-polylines (a link that dips outside the band and back in produces\n * multiple disjoint pieces; a fully-outside link produces none).\n */\nexport function clipPolylineToRect(points: Point[], rect: ClipRect): Point[][] {\n const segments: Point[][] = [];\n let current: Point[] = [];\n for (let i = 0; i < points.length - 1; i++) {\n const a = points[i]!;\n const b = points[i + 1]!;\n const clipped = clipSegment(a.x, a.y, b.x, b.y, rect);\n if (!clipped) {\n if (current.length > 1) segments.push(current);\n current = [];\n continue;\n }\n if (current.length === 0) {\n current.push({ x: clipped.x0, y: clipped.y0 });\n } else {\n const last = current[current.length - 1]!;\n if (Math.abs(last.x - clipped.x0) > 0.01 || Math.abs(last.y - clipped.y0) > 0.01) {\n if (current.length > 1) segments.push(current);\n current = [{ x: clipped.x0, y: clipped.y0 }];\n }\n }\n current.push({ x: clipped.x1, y: clipped.y1 });\n }\n if (current.length > 1) segments.push(current);\n return segments;\n}\n","import type { GanttColumn, GanttRenderModel, GanttTask } from \"@ganttloom/gantt-core\";\nimport type { PageBand, PaginationLayout } from \"./paginate.js\";\nimport { clipRect, type ClipRect } from \"./paginate.js\";\nimport { computeLinkPolyline, clipPolylineToRect, type Point } from \"./geom.js\";\n\n/**\n * Format-agnostic draw commands for one page/slide, in top-down point\n * coordinates relative to the full page (origin at the page's top-left\n * corner, y increasing downward — margins already baked in). Both the PDF\n * writer (which flips y to PDF's bottom-up space) and the PPTX writer\n * (which uses top-down EMUs natively) consume the same list, so the\n * row/column/link walking and clipping logic is written exactly once.\n */\n\nexport interface DrawRect {\n kind: \"rect\";\n x: number;\n y: number;\n w: number;\n h: number;\n fill?: string;\n stroke?: string;\n}\n\nexport interface DrawDiamond {\n kind: \"diamond\";\n cx: number;\n cy: number;\n r: number;\n fill?: string;\n stroke?: string;\n}\n\nexport interface DrawLine {\n kind: \"line\";\n points: Point[];\n stroke: string;\n}\n\nexport interface DrawText {\n kind: \"text\";\n x: number;\n y: number;\n w?: number;\n text: string;\n size: number;\n color: string;\n bold?: boolean;\n align?: \"left\" | \"center\" | \"right\";\n}\n\nexport type DrawCommand = DrawRect | DrawDiamond | DrawLine | DrawText;\n\nexport interface PageContent {\n widthPt: number;\n heightPt: number;\n commands: DrawCommand[];\n}\n\nfunction columnWidthsPt(model: GanttRenderModel, layout: PaginationLayout): { column: GanttColumn; widthPt: number }[] {\n const columns: GanttColumn[] =\n model.columns.length > 0 ? model.columns : [{ id: \"name\", title: \"Task\" }];\n const naturalTotal = columns.reduce((sum, c) => sum + (c.width ?? 120), 0) || 1;\n return columns.map((column) => ({\n column,\n widthPt: ((column.width ?? 120) / naturalTotal) * layout.gridPanelWidthPt,\n }));\n}\n\nfunction cellText(column: GanttColumn, task: GanttTask | undefined, depth: number): string {\n if (!task) return \"\";\n if (column.accessor) {\n const v = column.accessor(task);\n return v === null || v === undefined ? \"\" : String(v);\n }\n const indent = \" \".repeat(Math.max(0, depth));\n return `${indent}${task.name}`;\n}\n\nexport function buildPageContent(\n model: GanttRenderModel,\n tasks: GanttTask[],\n layout: PaginationLayout,\n page: PageBand,\n): PageContent {\n const { scale, gridPanelWidthPt, headerHeightPt, pageWidthPt, pageHeightPt, margins } = layout;\n const theme = model.theme;\n const tasksById = new Map(tasks.map((t) => [t.id, t]));\n const barsByTaskId = new Map(model.bars.map((b) => [b.taskId, b]));\n const rowsByTaskId = new Map(model.rows.map((r) => [r.taskId, r]));\n\n const commands: DrawCommand[] = [];\n const contentX0 = margins.left;\n const contentY0 = margins.top;\n\n const timelineRect: ClipRect = {\n x0: page.colStartX,\n y0: page.rowStartY,\n x1: page.colEndX,\n y1: page.rowEndY,\n };\n\n // page background\n commands.push({ kind: \"rect\", x: 0, y: 0, w: pageWidthPt, h: pageHeightPt, fill: theme.backgroundColor });\n\n const cols = columnWidthsPt(model, layout);\n\n // -- header row: grid panel column titles + timeline ticks --\n let colCursor = contentX0;\n for (const { column, widthPt } of cols) {\n commands.push({\n kind: \"text\",\n x: colCursor + 4,\n y: contentY0 + headerHeightPt / 2 - 5,\n w: widthPt - 8,\n text: column.title,\n size: 9,\n color: theme.textColor,\n bold: true,\n align: column.align ?? \"left\",\n });\n colCursor += widthPt;\n }\n commands.push({\n kind: \"rect\",\n x: contentX0,\n y: contentY0,\n w: gridPanelWidthPt + (page.colEndX - page.colStartX) * scale,\n h: headerHeightPt,\n stroke: theme.gridColor,\n });\n\n const timelineOriginX = contentX0 + gridPanelWidthPt;\n for (const tick of model.ticks) {\n if (tick.x < page.colStartX || tick.x > page.colEndX) continue;\n const px = timelineOriginX + (tick.x - page.colStartX) * scale;\n if (tick.isWeekend) {\n // faint full-height band is drawn by the caller per-row below; header tick line only here\n }\n commands.push({\n kind: \"line\",\n points: [\n { x: px, y: contentY0 },\n { x: px, y: pageHeightPt - margins.bottom },\n ],\n stroke: tick.isToday ? theme.todayColor : theme.gridColor,\n });\n commands.push({\n kind: \"text\",\n x: px + 2,\n y: contentY0 + headerHeightPt / 2 - 5,\n text: tick.label,\n size: 7,\n color: theme.textColor,\n align: \"left\",\n });\n }\n\n // -- rows: grid panel cells + timeline bars, clipped to this page's row band --\n const rowTop = (y: number) => contentY0 + headerHeightPt + (y - page.rowStartY) * scale;\n\n for (const row of model.rows) {\n if (row.y + row.height <= page.rowStartY || row.y >= page.rowEndY) continue;\n // clip the row's [y, y+height) span to this page's row band (1-D clip)\n const clippedRowY0 = Math.max(row.y, page.rowStartY);\n const clippedRowY1 = Math.min(row.y + row.height, page.rowEndY);\n const rowYTop = rowTop(clippedRowY0);\n const rowHPt = (clippedRowY1 - clippedRowY0) * scale;\n const task = tasksById.get(row.taskId);\n\n // grid panel row cells\n let cx = contentX0;\n for (const { column, widthPt } of cols) {\n commands.push({\n kind: \"text\",\n x: cx + 4,\n y: rowYTop + rowHPt / 2 - 4,\n w: widthPt - 8,\n text: cellText(column, task, row.depth),\n size: 8,\n color: theme.textColor,\n align: column.align ?? \"left\",\n });\n cx += widthPt;\n }\n commands.push({\n kind: \"rect\",\n x: contentX0,\n y: rowYTop,\n w: gridPanelWidthPt + (page.colEndX - page.colStartX) * scale,\n h: rowHPt,\n stroke: theme.gridColor,\n });\n\n // timeline bar for this row\n const bar = barsByTaskId.get(row.taskId);\n if (bar) {\n const clippedBar = clipRect(bar.x, bar.y, bar.width, bar.height, timelineRect);\n if (clippedBar) {\n const bx = timelineOriginX + (clippedBar.x - page.colStartX) * scale;\n const by = rowTop(clippedBar.y);\n const bw = clippedBar.w * scale;\n const bh = clippedBar.h * scale;\n\n if (bar.baseline) {\n const clippedBaseline = clipRect(bar.baseline.x, bar.y, bar.baseline.width, bar.height, timelineRect);\n if (clippedBaseline) {\n commands.push({\n kind: \"rect\",\n x: timelineOriginX + (clippedBaseline.x - page.colStartX) * scale,\n y: rowTop(clippedBaseline.y),\n w: clippedBaseline.w * scale,\n h: clippedBaseline.h * scale,\n fill: theme.baselineColor,\n });\n }\n }\n\n if (bar.isMilestone) {\n const r = bh / 2;\n commands.push({\n kind: \"diamond\",\n cx: bx + r,\n cy: by + r,\n r,\n fill: bar.isCritical ? theme.criticalColor : bar.color,\n stroke: theme.textColor,\n });\n if (bar.label) {\n commands.push({\n kind: \"text\",\n x: bx + bh + 4,\n y: by + bh / 2 - 4,\n text: bar.label,\n size: 8,\n color: theme.textColor,\n });\n }\n } else {\n commands.push({\n kind: \"rect\",\n x: bx,\n y: by,\n w: bw,\n h: bh,\n fill: bar.isCritical ? theme.criticalColor : bar.color,\n });\n if (bar.progressWidth > 0) {\n const clippedProgress = clipRect(bar.x, bar.y, bar.progressWidth, bar.height, timelineRect);\n if (clippedProgress) {\n commands.push({\n kind: \"rect\",\n x: timelineOriginX + (clippedProgress.x - page.colStartX) * scale,\n y: rowTop(clippedProgress.y),\n w: clippedProgress.w * scale,\n h: clippedProgress.h * scale,\n fill: bar.progressColor,\n });\n }\n }\n commands.push({\n kind: \"text\",\n x: bx + 3,\n y: by + bh / 2 - 4,\n text: bar.label,\n size: 8,\n color: theme.textColor,\n });\n }\n }\n }\n }\n\n // -- dependency links, recomputed & clipped per band --\n for (const link of model.links) {\n const fromBar = barsByTaskId.get(link.fromId);\n const toBar = barsByTaskId.get(link.toId);\n if (!fromBar || !toBar) continue;\n // skip entirely if neither endpoint's row is visible on this page at all\n const fromRow = rowsByTaskId.get(link.fromId);\n const toRow = rowsByTaskId.get(link.toId);\n if (!fromRow || !toRow) continue;\n const polyline = computeLinkPolyline(fromBar, toBar);\n const pieces = clipPolylineToRect(polyline, timelineRect);\n for (const piece of pieces) {\n commands.push({\n kind: \"line\",\n points: piece.map((p) => ({\n x: timelineOriginX + (p.x - page.colStartX) * scale,\n y: rowTop(p.y),\n })),\n stroke: link.isCritical ? theme.criticalColor : theme.linkColor,\n });\n }\n }\n\n return { widthPt: pageWidthPt, heightPt: pageHeightPt, commands };\n}\n","/** Parse a CSS-ish color string into 0-1 RGB components. Falls back to black. */\nexport function parseColor(input: string | undefined | null): [number, number, number] {\n if (!input) return [0, 0, 0];\n const s = input.trim();\n const hex = s.match(/^#?([0-9a-fA-F]{6})$/) ?? s.match(/^#?([0-9a-fA-F]{3})$/);\n if (hex) {\n let h = hex[1]!;\n if (h.length === 3) {\n h = h\n .split(\"\")\n .map((c) => c + c)\n .join(\"\");\n }\n const r = parseInt(h.slice(0, 2), 16) / 255;\n const g = parseInt(h.slice(2, 4), 16) / 255;\n const b = parseInt(h.slice(4, 6), 16) / 255;\n return [r, g, b];\n }\n const rgb = s.match(/^rgba?\\(\\s*([\\d.]+)\\s*,\\s*([\\d.]+)\\s*,\\s*([\\d.]+)/i);\n if (rgb) {\n return [Number(rgb[1]) / 255, Number(rgb[2]) / 255, Number(rgb[3]) / 255];\n }\n const named: Record<string, [number, number, number]> = {\n black: [0, 0, 0],\n white: [1, 1, 1],\n red: [1, 0, 0],\n green: [0, 0.5, 0],\n blue: [0, 0, 1],\n gray: [0.5, 0.5, 0.5],\n grey: [0.5, 0.5, 0.5],\n transparent: [1, 1, 1],\n };\n return named[s.toLowerCase()] ?? [0, 0, 0];\n}\n\nfunction toHexByte(v: number): string {\n return Math.round(Math.max(0, Math.min(1, v)) * 255)\n .toString(16)\n .padStart(2, \"0\");\n}\n\n/** Normalize any supported CSS-ish color string to a bare \"RRGGBB\" hex (for OOXML srgbClr). */\nexport function toHexRRGGBB(input: string | undefined | null): string {\n const [r, g, b] = parseColor(input);\n return `${toHexByte(r)}${toHexByte(g)}${toHexByte(b)}`.toUpperCase();\n}\n"],"mappings":";AAeA,IAAM,gBAAyE;AAAA;AAAA;AAAA,EAG7E,IAAI,EAAE,OAAO,QAAQ,QAAQ,OAAO;AAAA,EACpC,QAAQ,EAAE,OAAO,KAAK,QAAQ,IAAI;AAAA,EAClC,IAAI,EAAE,OAAO,QAAQ,QAAQ,QAAQ;AACvC;AA8DA,IAAM,oBAAoB;AAC1B,IAAM,gBAAgB;AACtB,IAAM,wBAAwB;AAC9B,IAAM,qBAAqB;AAEpB,SAAS,gBAAgB,KAAyD;AACvF,MAAI,KAAK,QAAQ;AACf,WAAO,EAAE,OAAO,IAAI,OAAO,SAAS,QAAQ,IAAI,OAAO,SAAS;AAAA,EAClE;AACA,QAAM,OAAO,KAAK,QAAQ;AAC1B,QAAM,OAAO,cAAc,IAAI;AAC/B,QAAM,cAAc,KAAK,eAAe;AACxC,QAAM,QAAQ,KAAK,IAAI,KAAK,OAAO,KAAK,MAAM;AAC9C,QAAM,OAAO,KAAK,IAAI,KAAK,OAAO,KAAK,MAAM;AAC7C,SAAO,gBAAgB,cAAc,EAAE,OAAO,MAAM,QAAQ,MAAM,IAAI,EAAE,OAAO,OAAO,QAAQ,KAAK;AACrG;AAEA,SAAS,wBAAwB,OAAiC;AAChE,QAAM,OAAO,MAAM,WAAW,CAAC;AAC/B,MAAI,KAAK,WAAW,EAAG,QAAO;AAC9B,SAAO,KAAK,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,SAAS,MAAM,CAAC;AAC1D;AAEO,SAAS,kBACd,OACA,UAA6B,CAAC,GACZ;AAClB,QAAM,EAAE,OAAO,aAAa,QAAQ,aAAa,IAAI,gBAAgB,QAAQ,QAAQ;AACrF,QAAM,UAAmB;AAAA,IACvB,KAAK,QAAQ,SAAS,OAAO;AAAA,IAC7B,OAAO,QAAQ,SAAS,SAAS;AAAA,IACjC,QAAQ,QAAQ,SAAS,UAAU;AAAA,IACnC,MAAM,QAAQ,SAAS,QAAQ;AAAA,EACjC;AACA,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,mBAAmB,QAAQ,oBAAoB,wBAAwB,KAAK;AAClF,QAAM,mBAAmB,mBAAmB;AAC5C,QAAM,iBAAiB,MAAM;AAC7B,QAAM,iBAAiB,iBAAiB;AAExC,QAAM,iBAAiB,cAAc,QAAQ,OAAO,QAAQ;AAC5D,QAAM,kBAAkB,eAAe,QAAQ,MAAM,QAAQ;AAE7D,QAAM,yBAAyB,KAAK,IAAI,iBAAiB,kBAAkB,qBAAqB;AAChG,QAAM,sBAAsB,KAAK,IAAI,kBAAkB,gBAAgB,kBAAkB;AAEzF,QAAM,yBAAyB,yBAAyB;AACxD,QAAM,sBAAsB,sBAAsB;AAElD,QAAM,gBAAgB,KAAK,IAAI,MAAM,QAAQ,CAAC;AAC9C,QAAM,eAAe,KAAK,IAAI,MAAM,OAAO,CAAC;AAE5C,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,KAAK,gBAAgB,mBAAmB,CAAC;AAC3E,QAAM,WAAW,KAAK,IAAI,GAAG,KAAK,KAAK,eAAe,sBAAsB,CAAC;AAE7E,QAAM,WAAmB,CAAC;AAC1B,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,aAAS,KAAK;AAAA,MACZ,OAAO,IAAI;AAAA,MACX,KAAK,KAAK,IAAI,gBAAgB,IAAI,KAAK,mBAAmB;AAAA,IAC5D,CAAC;AAAA,EACH;AACA,QAAM,WAAmB,CAAC;AAC1B,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,aAAS,KAAK;AAAA,MACZ,OAAO,IAAI;AAAA,MACX,KAAK,KAAK,IAAI,eAAe,IAAI,KAAK,sBAAsB;AAAA,IAC9D,CAAC;AAAA,EACH;AAEA,QAAM,QAAoB,CAAC;AAC3B,WAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,UAAM,UAAU,SAAS,CAAC;AAC1B,aAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,YAAM,UAAU,SAAS,CAAC;AAC1B,YAAM,KAAK;AAAA,QACT,SAAS;AAAA,QACT,SAAS;AAAA,QACT,WAAW,QAAQ;AAAA,QACnB,SAAS,QAAQ;AAAA,QACjB,WAAW,QAAQ;AAAA,QACnB,SAAS,QAAQ;AAAA,MACnB,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAUO,SAAS,YACd,IACA,IACA,IACA,IACA,MAC2D;AAC3D,MAAI,KAAK;AACT,MAAI,KAAK;AACT,QAAM,KAAK,KAAK;AAChB,QAAM,KAAK,KAAK;AAChB,QAAM,SAAkC;AAAA,IACtC,CAAC,CAAC,IAAI,KAAK,KAAK,EAAE;AAAA,IAClB,CAAC,IAAI,KAAK,KAAK,EAAE;AAAA,IACjB,CAAC,CAAC,IAAI,KAAK,KAAK,EAAE;AAAA,IAClB,CAAC,IAAI,KAAK,KAAK,EAAE;AAAA,EACnB;AACA,aAAW,CAAC,GAAG,CAAC,KAAK,QAAQ;AAC3B,QAAI,MAAM,GAAG;AACX,UAAI,IAAI,EAAG,QAAO;AAAA,IACpB,OAAO;AACL,YAAM,IAAI,IAAI;AACd,UAAI,IAAI,GAAG;AACT,YAAI,IAAI,GAAI,QAAO;AACnB,YAAI,IAAI,GAAI,MAAK;AAAA,MACnB,OAAO;AACL,YAAI,IAAI,GAAI,QAAO;AACnB,YAAI,IAAI,GAAI,MAAK;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AACA,SAAO,EAAE,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG;AAClF;AAGO,SAAS,SACd,GACA,GACA,GACA,GACA,MACuD;AACvD,QAAM,KAAK,KAAK,IAAI,GAAG,KAAK,EAAE;AAC9B,QAAM,KAAK,KAAK,IAAI,GAAG,KAAK,EAAE;AAC9B,QAAM,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE;AAClC,QAAM,KAAK,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE;AAClC,MAAI,MAAM,MAAM,MAAM,GAAI,QAAO;AACjC,SAAO,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,GAAG;AAChD;;;AChOO,SAAS,oBAAoB,SAAyB,OAAgC;AAC3F,QAAM,KAAK,QAAQ,IAAI,QAAQ;AAC/B,QAAM,KAAK,QAAQ,IAAI,QAAQ,SAAS;AACxC,QAAM,KAAK,MAAM;AACjB,QAAM,KAAK,MAAM,IAAI,MAAM,SAAS;AACpC,MAAI,KAAK,IAAI,KAAK,EAAE,IAAI,MAAM;AAC5B,WAAO,CAAC,EAAE,GAAG,IAAI,GAAG,GAAG,GAAG,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA,EAC5C;AACA,QAAM,OAAO,MAAM,KAAK,MAAM;AAC9B,SAAO;AAAA,IACL,EAAE,GAAG,IAAI,GAAG,GAAG;AAAA,IACf,EAAE,GAAG,MAAM,GAAG,GAAG;AAAA,IACjB,EAAE,GAAG,MAAM,GAAG,GAAG;AAAA,IACjB,EAAE,GAAG,IAAI,GAAG,GAAG;AAAA,EACjB;AACF;AAOO,SAAS,mBAAmB,QAAiB,MAA2B;AAC7E,QAAM,WAAsB,CAAC;AAC7B,MAAI,UAAmB,CAAC;AACxB,WAAS,IAAI,GAAG,IAAI,OAAO,SAAS,GAAG,KAAK;AAC1C,UAAM,IAAI,OAAO,CAAC;AAClB,UAAM,IAAI,OAAO,IAAI,CAAC;AACtB,UAAM,UAAU,YAAY,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI;AACpD,QAAI,CAAC,SAAS;AACZ,UAAI,QAAQ,SAAS,EAAG,UAAS,KAAK,OAAO;AAC7C,gBAAU,CAAC;AACX;AAAA,IACF;AACA,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,KAAK,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG,CAAC;AAAA,IAC/C,OAAO;AACL,YAAM,OAAO,QAAQ,QAAQ,SAAS,CAAC;AACvC,UAAI,KAAK,IAAI,KAAK,IAAI,QAAQ,EAAE,IAAI,QAAQ,KAAK,IAAI,KAAK,IAAI,QAAQ,EAAE,IAAI,MAAM;AAChF,YAAI,QAAQ,SAAS,EAAG,UAAS,KAAK,OAAO;AAC7C,kBAAU,CAAC,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG,CAAC;AAAA,MAC7C;AAAA,IACF;AACA,YAAQ,KAAK,EAAE,GAAG,QAAQ,IAAI,GAAG,QAAQ,GAAG,CAAC;AAAA,EAC/C;AACA,MAAI,QAAQ,SAAS,EAAG,UAAS,KAAK,OAAO;AAC7C,SAAO;AACT;;;ACRA,SAAS,eAAe,OAAyB,QAAsE;AACrH,QAAM,UACJ,MAAM,QAAQ,SAAS,IAAI,MAAM,UAAU,CAAC,EAAE,IAAI,QAAQ,OAAO,OAAO,CAAC;AAC3E,QAAM,eAAe,QAAQ,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,SAAS,MAAM,CAAC,KAAK;AAC9E,SAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,IAC9B;AAAA,IACA,UAAW,OAAO,SAAS,OAAO,eAAgB,OAAO;AAAA,EAC3D,EAAE;AACJ;AAEA,SAAS,SAAS,QAAqB,MAA6B,OAAuB;AACzF,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,OAAO,UAAU;AACnB,UAAM,IAAI,OAAO,SAAS,IAAI;AAC9B,WAAO,MAAM,QAAQ,MAAM,SAAY,KAAK,OAAO,CAAC;AAAA,EACtD;AACA,QAAM,SAAS,KAAK,OAAO,KAAK,IAAI,GAAG,KAAK,CAAC;AAC7C,SAAO,GAAG,MAAM,GAAG,KAAK,IAAI;AAC9B;AAEO,SAAS,iBACd,OACA,OACA,QACA,MACa;AACb,QAAM,EAAE,OAAO,kBAAkB,gBAAgB,aAAa,cAAc,QAAQ,IAAI;AACxF,QAAM,QAAQ,MAAM;AACpB,QAAM,YAAY,IAAI,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AACrD,QAAM,eAAe,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjE,QAAM,eAAe,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;AAEjE,QAAM,WAA0B,CAAC;AACjC,QAAM,YAAY,QAAQ;AAC1B,QAAM,YAAY,QAAQ;AAE1B,QAAM,eAAyB;AAAA,IAC7B,IAAI,KAAK;AAAA,IACT,IAAI,KAAK;AAAA,IACT,IAAI,KAAK;AAAA,IACT,IAAI,KAAK;AAAA,EACX;AAGA,WAAS,KAAK,EAAE,MAAM,QAAQ,GAAG,GAAG,GAAG,GAAG,GAAG,aAAa,GAAG,cAAc,MAAM,MAAM,gBAAgB,CAAC;AAExG,QAAM,OAAO,eAAe,OAAO,MAAM;AAGzC,MAAI,YAAY;AAChB,aAAW,EAAE,QAAQ,QAAQ,KAAK,MAAM;AACtC,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,GAAG,YAAY;AAAA,MACf,GAAG,YAAY,iBAAiB,IAAI;AAAA,MACpC,GAAG,UAAU;AAAA,MACb,MAAM,OAAO;AAAA,MACb,MAAM;AAAA,MACN,OAAO,MAAM;AAAA,MACb,MAAM;AAAA,MACN,OAAO,OAAO,SAAS;AAAA,IACzB,CAAC;AACD,iBAAa;AAAA,EACf;AACA,WAAS,KAAK;AAAA,IACZ,MAAM;AAAA,IACN,GAAG;AAAA,IACH,GAAG;AAAA,IACH,GAAG,oBAAoB,KAAK,UAAU,KAAK,aAAa;AAAA,IACxD,GAAG;AAAA,IACH,QAAQ,MAAM;AAAA,EAChB,CAAC;AAED,QAAM,kBAAkB,YAAY;AACpC,aAAW,QAAQ,MAAM,OAAO;AAC9B,QAAI,KAAK,IAAI,KAAK,aAAa,KAAK,IAAI,KAAK,QAAS;AACtD,UAAM,KAAK,mBAAmB,KAAK,IAAI,KAAK,aAAa;AACzD,QAAI,KAAK,WAAW;AAAA,IAEpB;AACA,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,QAAQ;AAAA,QACN,EAAE,GAAG,IAAI,GAAG,UAAU;AAAA,QACtB,EAAE,GAAG,IAAI,GAAG,eAAe,QAAQ,OAAO;AAAA,MAC5C;AAAA,MACA,QAAQ,KAAK,UAAU,MAAM,aAAa,MAAM;AAAA,IAClD,CAAC;AACD,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,GAAG,KAAK;AAAA,MACR,GAAG,YAAY,iBAAiB,IAAI;AAAA,MACpC,MAAM,KAAK;AAAA,MACX,MAAM;AAAA,MACN,OAAO,MAAM;AAAA,MACb,OAAO;AAAA,IACT,CAAC;AAAA,EACH;AAGA,QAAM,SAAS,CAAC,MAAc,YAAY,kBAAkB,IAAI,KAAK,aAAa;AAElF,aAAW,OAAO,MAAM,MAAM;AAC5B,QAAI,IAAI,IAAI,IAAI,UAAU,KAAK,aAAa,IAAI,KAAK,KAAK,QAAS;AAEnE,UAAM,eAAe,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;AACnD,UAAM,eAAe,KAAK,IAAI,IAAI,IAAI,IAAI,QAAQ,KAAK,OAAO;AAC9D,UAAM,UAAU,OAAO,YAAY;AACnC,UAAM,UAAU,eAAe,gBAAgB;AAC/C,UAAM,OAAO,UAAU,IAAI,IAAI,MAAM;AAGrC,QAAI,KAAK;AACT,eAAW,EAAE,QAAQ,QAAQ,KAAK,MAAM;AACtC,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,GAAG,KAAK;AAAA,QACR,GAAG,UAAU,SAAS,IAAI;AAAA,QAC1B,GAAG,UAAU;AAAA,QACb,MAAM,SAAS,QAAQ,MAAM,IAAI,KAAK;AAAA,QACtC,MAAM;AAAA,QACN,OAAO,MAAM;AAAA,QACb,OAAO,OAAO,SAAS;AAAA,MACzB,CAAC;AACD,YAAM;AAAA,IACR;AACA,aAAS,KAAK;AAAA,MACZ,MAAM;AAAA,MACN,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG,oBAAoB,KAAK,UAAU,KAAK,aAAa;AAAA,MACxD,GAAG;AAAA,MACH,QAAQ,MAAM;AAAA,IAChB,CAAC;AAGD,UAAM,MAAM,aAAa,IAAI,IAAI,MAAM;AACvC,QAAI,KAAK;AACP,YAAM,aAAa,SAAS,IAAI,GAAG,IAAI,GAAG,IAAI,OAAO,IAAI,QAAQ,YAAY;AAC7E,UAAI,YAAY;AACd,cAAM,KAAK,mBAAmB,WAAW,IAAI,KAAK,aAAa;AAC/D,cAAM,KAAK,OAAO,WAAW,CAAC;AAC9B,cAAM,KAAK,WAAW,IAAI;AAC1B,cAAM,KAAK,WAAW,IAAI;AAE1B,YAAI,IAAI,UAAU;AAChB,gBAAM,kBAAkB,SAAS,IAAI,SAAS,GAAG,IAAI,GAAG,IAAI,SAAS,OAAO,IAAI,QAAQ,YAAY;AACpG,cAAI,iBAAiB;AACnB,qBAAS,KAAK;AAAA,cACZ,MAAM;AAAA,cACN,GAAG,mBAAmB,gBAAgB,IAAI,KAAK,aAAa;AAAA,cAC5D,GAAG,OAAO,gBAAgB,CAAC;AAAA,cAC3B,GAAG,gBAAgB,IAAI;AAAA,cACvB,GAAG,gBAAgB,IAAI;AAAA,cACvB,MAAM,MAAM;AAAA,YACd,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,IAAI,aAAa;AACnB,gBAAM,IAAI,KAAK;AACf,mBAAS,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,IAAI,KAAK;AAAA,YACT,IAAI,KAAK;AAAA,YACT;AAAA,YACA,MAAM,IAAI,aAAa,MAAM,gBAAgB,IAAI;AAAA,YACjD,QAAQ,MAAM;AAAA,UAChB,CAAC;AACD,cAAI,IAAI,OAAO;AACb,qBAAS,KAAK;AAAA,cACZ,MAAM;AAAA,cACN,GAAG,KAAK,KAAK;AAAA,cACb,GAAG,KAAK,KAAK,IAAI;AAAA,cACjB,MAAM,IAAI;AAAA,cACV,MAAM;AAAA,cACN,OAAO,MAAM;AAAA,YACf,CAAC;AAAA,UACH;AAAA,QACF,OAAO;AACL,mBAAS,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,GAAG;AAAA,YACH,GAAG;AAAA,YACH,GAAG;AAAA,YACH,GAAG;AAAA,YACH,MAAM,IAAI,aAAa,MAAM,gBAAgB,IAAI;AAAA,UACnD,CAAC;AACD,cAAI,IAAI,gBAAgB,GAAG;AACzB,kBAAM,kBAAkB,SAAS,IAAI,GAAG,IAAI,GAAG,IAAI,eAAe,IAAI,QAAQ,YAAY;AAC1F,gBAAI,iBAAiB;AACnB,uBAAS,KAAK;AAAA,gBACZ,MAAM;AAAA,gBACN,GAAG,mBAAmB,gBAAgB,IAAI,KAAK,aAAa;AAAA,gBAC5D,GAAG,OAAO,gBAAgB,CAAC;AAAA,gBAC3B,GAAG,gBAAgB,IAAI;AAAA,gBACvB,GAAG,gBAAgB,IAAI;AAAA,gBACvB,MAAM,IAAI;AAAA,cACZ,CAAC;AAAA,YACH;AAAA,UACF;AACA,mBAAS,KAAK;AAAA,YACZ,MAAM;AAAA,YACN,GAAG,KAAK;AAAA,YACR,GAAG,KAAK,KAAK,IAAI;AAAA,YACjB,MAAM,IAAI;AAAA,YACV,MAAM;AAAA,YACN,OAAO,MAAM;AAAA,UACf,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,aAAW,QAAQ,MAAM,OAAO;AAC9B,UAAM,UAAU,aAAa,IAAI,KAAK,MAAM;AAC5C,UAAM,QAAQ,aAAa,IAAI,KAAK,IAAI;AACxC,QAAI,CAAC,WAAW,CAAC,MAAO;AAExB,UAAM,UAAU,aAAa,IAAI,KAAK,MAAM;AAC5C,UAAM,QAAQ,aAAa,IAAI,KAAK,IAAI;AACxC,QAAI,CAAC,WAAW,CAAC,MAAO;AACxB,UAAM,WAAW,oBAAoB,SAAS,KAAK;AACnD,UAAM,SAAS,mBAAmB,UAAU,YAAY;AACxD,eAAW,SAAS,QAAQ;AAC1B,eAAS,KAAK;AAAA,QACZ,MAAM;AAAA,QACN,QAAQ,MAAM,IAAI,CAAC,OAAO;AAAA,UACxB,GAAG,mBAAmB,EAAE,IAAI,KAAK,aAAa;AAAA,UAC9C,GAAG,OAAO,EAAE,CAAC;AAAA,QACf,EAAE;AAAA,QACF,QAAQ,KAAK,aAAa,MAAM,gBAAgB,MAAM;AAAA,MACxD,CAAC;AAAA,IACH;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,aAAa,UAAU,cAAc,SAAS;AAClE;;;ACxSO,SAAS,WAAW,OAA4D;AACrF,MAAI,CAAC,MAAO,QAAO,CAAC,GAAG,GAAG,CAAC;AAC3B,QAAM,IAAI,MAAM,KAAK;AACrB,QAAM,MAAM,EAAE,MAAM,sBAAsB,KAAK,EAAE,MAAM,sBAAsB;AAC7E,MAAI,KAAK;AACP,QAAI,IAAI,IAAI,CAAC;AACb,QAAI,EAAE,WAAW,GAAG;AAClB,UAAI,EACD,MAAM,EAAE,EACR,IAAI,CAAC,MAAM,IAAI,CAAC,EAChB,KAAK,EAAE;AAAA,IACZ;AACA,UAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AACxC,UAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AACxC,UAAM,IAAI,SAAS,EAAE,MAAM,GAAG,CAAC,GAAG,EAAE,IAAI;AACxC,WAAO,CAAC,GAAG,GAAG,CAAC;AAAA,EACjB;AACA,QAAM,MAAM,EAAE,MAAM,oDAAoD;AACxE,MAAI,KAAK;AACP,WAAO,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,GAAG;AAAA,EAC1E;AACA,QAAM,QAAkD;AAAA,IACtD,OAAO,CAAC,GAAG,GAAG,CAAC;AAAA,IACf,OAAO,CAAC,GAAG,GAAG,CAAC;AAAA,IACf,KAAK,CAAC,GAAG,GAAG,CAAC;AAAA,IACb,OAAO,CAAC,GAAG,KAAK,CAAC;AAAA,IACjB,MAAM,CAAC,GAAG,GAAG,CAAC;AAAA,IACd,MAAM,CAAC,KAAK,KAAK,GAAG;AAAA,IACpB,MAAM,CAAC,KAAK,KAAK,GAAG;AAAA,IACpB,aAAa,CAAC,GAAG,GAAG,CAAC;AAAA,EACvB;AACA,SAAO,MAAM,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC;AAC3C;AAEA,SAAS,UAAU,GAAmB;AACpC,SAAO,KAAK,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,EAChD,SAAS,EAAE,EACX,SAAS,GAAG,GAAG;AACpB;AAGO,SAAS,YAAY,OAA0C;AACpE,QAAM,CAAC,GAAG,GAAG,CAAC,IAAI,WAAW,KAAK;AAClC,SAAO,GAAG,UAAU,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,YAAY;AACrE;","names":[]}
@@ -0,0 +1,125 @@
1
+ import {
2
+ buildZip
3
+ } from "./chunk-JB7HLLAI.js";
4
+
5
+ // src/xlsx/parts.ts
6
+ function contentTypesXml() {
7
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
8
+ <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
9
+ <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
10
+ <Default Extension="xml" ContentType="application/xml"/>
11
+ <Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
12
+ <Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
13
+ <Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
14
+ </Types>`;
15
+ }
16
+ function rootRelsXml() {
17
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
18
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
19
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>
20
+ </Relationships>`;
21
+ }
22
+ function workbookXml(sheetName) {
23
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
24
+ <workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
25
+ <sheets>
26
+ <sheet name="${escapeXmlAttr(sheetName)}" sheetId="1" r:id="rId1"/>
27
+ </sheets>
28
+ </workbook>`;
29
+ }
30
+ function workbookRelsXml() {
31
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
32
+ <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
33
+ <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/sheet1.xml"/>
34
+ <Relationship Id="rId2" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
35
+ </Relationships>`;
36
+ }
37
+ function stylesXml() {
38
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
39
+ <styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
40
+ <fonts count="2">
41
+ <font><sz val="11"/><name val="Calibri"/></font>
42
+ <font><sz val="11"/><name val="Calibri"/><b/></font>
43
+ </fonts>
44
+ <fills count="1"><fill><patternFill patternType="none"/></fill></fills>
45
+ <borders count="1"><border/></borders>
46
+ <cellStyleXfs count="1"><xf numFmtId="0" fontId="0"/></cellStyleXfs>
47
+ <cellXfs count="2">
48
+ <xf numFmtId="0" fontId="0" xfId="0"/>
49
+ <xf numFmtId="0" fontId="1" xfId="0" applyFont="1"/>
50
+ </cellXfs>
51
+ </styleSheet>`;
52
+ }
53
+ function escapeXmlText(text) {
54
+ return text.replace(/[&<>]/g, (c) => c === "&" ? "&amp;" : c === "<" ? "&lt;" : "&gt;");
55
+ }
56
+ function escapeXmlAttr(text) {
57
+ return escapeXmlText(text).replace(/"/g, "&quot;");
58
+ }
59
+
60
+ // src/xlsx/worksheet.ts
61
+ function colLetter(index) {
62
+ let n = index;
63
+ let s = "";
64
+ do {
65
+ s = String.fromCharCode(65 + n % 26) + s;
66
+ n = Math.floor(n / 26) - 1;
67
+ } while (n >= 0);
68
+ return s;
69
+ }
70
+ function buildSheetXml(headerRow, rows) {
71
+ const allRows = [headerRow, ...rows];
72
+ let rowsXml = "";
73
+ allRows.forEach((row, rIdx) => {
74
+ const rowNum = rIdx + 1;
75
+ const styleAttr = rIdx === 0 ? ' s="1"' : "";
76
+ const cellsXml = row.map((val, cIdx) => {
77
+ const ref = `${colLetter(cIdx)}${rowNum}`;
78
+ if (typeof val === "number" && Number.isFinite(val)) {
79
+ return `<c r="${ref}"${styleAttr}><v>${val}</v></c>`;
80
+ }
81
+ const text = escapeXmlText(String(val ?? ""));
82
+ return `<c r="${ref}"${styleAttr} t="inlineStr"><is><t xml:space="preserve">${text}</t></is></c>`;
83
+ }).join("");
84
+ rowsXml += `<row r="${rowNum}">${cellsXml}</row>`;
85
+ });
86
+ return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
87
+ <worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheetData>${rowsXml}</sheetData></worksheet>`;
88
+ }
89
+
90
+ // src/xlsx/index.ts
91
+ var encoder = new TextEncoder();
92
+ function textEntry(name, xml) {
93
+ return { name, data: encoder.encode(xml) };
94
+ }
95
+ var DEFAULT_COLUMNS = [
96
+ { id: "name", title: "Name" },
97
+ { id: "start", title: "Start", accessor: (t) => t.start.toISOString().slice(0, 10) },
98
+ { id: "end", title: "End", accessor: (t) => t.end.toISOString().slice(0, 10) },
99
+ { id: "progress", title: "Progress %", accessor: (t) => t.progress ?? 0 }
100
+ ];
101
+ function renderToXLSX(tasks, options = {}) {
102
+ const columns = options.columns ?? DEFAULT_COLUMNS;
103
+ const headerRow = columns.map((c) => c.title);
104
+ const rows = tasks.map(
105
+ (task) => columns.map((col, colIndex) => {
106
+ const raw = col.accessor ? col.accessor(task) : colIndex === 0 ? task.name : "";
107
+ return raw === null || raw === void 0 ? "" : raw;
108
+ })
109
+ );
110
+ const sheetName = (options.sheetName ?? "Tasks").slice(0, 31);
111
+ const entries = [
112
+ textEntry("[Content_Types].xml", contentTypesXml()),
113
+ textEntry("_rels/.rels", rootRelsXml()),
114
+ textEntry("xl/workbook.xml", workbookXml(sheetName)),
115
+ textEntry("xl/_rels/workbook.xml.rels", workbookRelsXml()),
116
+ textEntry("xl/styles.xml", stylesXml()),
117
+ textEntry("xl/worksheets/sheet1.xml", buildSheetXml(headerRow, rows))
118
+ ];
119
+ return buildZip(entries);
120
+ }
121
+
122
+ export {
123
+ renderToXLSX
124
+ };
125
+ //# sourceMappingURL=chunk-X5RULSWH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/xlsx/parts.ts","../src/xlsx/worksheet.ts","../src/xlsx/index.ts"],"sourcesContent":["/** Hand-written OOXML parts for a minimal single-sheet .xlsx workbook. */\n\nexport function contentTypesXml(): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n <Default Extension=\"xml\" ContentType=\"application/xml\"/>\n <Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\"/>\n <Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\"/>\n <Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\"/>\n</Types>`;\n}\n\nexport function rootRelsXml(): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"xl/workbook.xml\"/>\n</Relationships>`;\n}\n\nexport function workbookXml(sheetName: string): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<workbook xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\n <sheets>\n <sheet name=\"${escapeXmlAttr(sheetName)}\" sheetId=\"1\" r:id=\"rId1\"/>\n </sheets>\n</workbook>`;\n}\n\nexport function workbookRelsXml(): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet\" Target=\"worksheets/sheet1.xml\"/>\n <Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>\n</Relationships>`;\n}\n\n/** Style index 0 = default; index 1 = bold (used for the header row). */\nexport function stylesXml(): string {\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">\n <fonts count=\"2\">\n <font><sz val=\"11\"/><name val=\"Calibri\"/></font>\n <font><sz val=\"11\"/><name val=\"Calibri\"/><b/></font>\n </fonts>\n <fills count=\"1\"><fill><patternFill patternType=\"none\"/></fill></fills>\n <borders count=\"1\"><border/></borders>\n <cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\"/></cellStyleXfs>\n <cellXfs count=\"2\">\n <xf numFmtId=\"0\" fontId=\"0\" xfId=\"0\"/>\n <xf numFmtId=\"0\" fontId=\"1\" xfId=\"0\" applyFont=\"1\"/>\n </cellXfs>\n</styleSheet>`;\n}\n\nexport function escapeXmlText(text: string): string {\n return text.replace(/[&<>]/g, (c) => (c === \"&\" ? \"&amp;\" : c === \"<\" ? \"&lt;\" : \"&gt;\"));\n}\n\nfunction escapeXmlAttr(text: string): string {\n return escapeXmlText(text).replace(/\"/g, \"&quot;\");\n}\n","import { escapeXmlText } from \"./parts.js\";\n\nfunction colLetter(index: number): string {\n let n = index;\n let s = \"\";\n do {\n s = String.fromCharCode(65 + (n % 26)) + s;\n n = Math.floor(n / 26) - 1;\n } while (n >= 0);\n return s;\n}\n\n/** Builds a minimal sheetData: inline strings for text cells, plain <v> for finite numbers, header row styled bold. */\nexport function buildSheetXml(headerRow: string[], rows: (string | number)[][]): string {\n const allRows = [headerRow as (string | number)[], ...rows];\n let rowsXml = \"\";\n allRows.forEach((row, rIdx) => {\n const rowNum = rIdx + 1;\n const styleAttr = rIdx === 0 ? ' s=\"1\"' : \"\";\n const cellsXml = row\n .map((val, cIdx) => {\n const ref = `${colLetter(cIdx)}${rowNum}`;\n if (typeof val === \"number\" && Number.isFinite(val)) {\n return `<c r=\"${ref}\"${styleAttr}><v>${val}</v></c>`;\n }\n const text = escapeXmlText(String(val ?? \"\"));\n return `<c r=\"${ref}\"${styleAttr} t=\"inlineStr\"><is><t xml:space=\"preserve\">${text}</t></is></c>`;\n })\n .join(\"\");\n rowsXml += `<row r=\"${rowNum}\">${cellsXml}</row>`;\n });\n return `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><sheetData>${rowsXml}</sheetData></worksheet>`;\n}\n","import type { GanttColumn, GanttTask } from \"@ganttloom/gantt-core\";\nimport { buildZip, type ZipEntryInput } from \"../zip.js\";\nimport { buildSheetXml } from \"./worksheet.js\";\nimport { contentTypesXml, rootRelsXml, stylesXml, workbookRelsXml, workbookXml } from \"./parts.js\";\n\nexport interface XlsxExportOptions {\n /** defaults to Name / Start / End / Progress %, using each column's `accessor` like the grid panel does */\n columns?: GanttColumn[];\n /** truncated to 31 chars - the xlsx sheet-name limit. Default \"Tasks\". */\n sheetName?: string;\n}\n\nconst encoder = new TextEncoder();\nfunction textEntry(name: string, xml: string): ZipEntryInput {\n return { name, data: encoder.encode(xml) };\n}\n\nconst DEFAULT_COLUMNS: GanttColumn[] = [\n { id: \"name\", title: \"Name\" },\n { id: \"start\", title: \"Start\", accessor: (t) => t.start.toISOString().slice(0, 10) },\n { id: \"end\", title: \"End\", accessor: (t) => t.end.toISOString().slice(0, 10) },\n { id: \"progress\", title: \"Progress %\", accessor: (t) => t.progress ?? 0 },\n];\n\n/**\n * Export a task list to a native .xlsx spreadsheet, built from scratch: a\n * hand-rolled ZIP container (shared with the PPTX writer) around\n * hand-written OOXML spreadsheet parts. No external xlsx/OOXML library.\n *\n * Unlike renderToPDF/renderToPPTX, this exports the plain task data (via\n * `columns`, same accessor pattern as the grid panel) rather than the\n * rendered chart geometry - a spreadsheet has no use for bar/link\n * coordinates. Dates are written as \"YYYY-MM-DD\" text, not Excel's serial\n * date numbers, to avoid needing number-format/date-system bookkeeping.\n */\nexport function renderToXLSX(tasks: GanttTask[], options: XlsxExportOptions = {}): Uint8Array {\n const columns = options.columns ?? DEFAULT_COLUMNS;\n const headerRow = columns.map((c) => c.title);\n const rows = tasks.map((task) =>\n columns.map((col, colIndex) => {\n const raw = col.accessor ? col.accessor(task) : colIndex === 0 ? task.name : \"\";\n return raw === null || raw === undefined ? \"\" : raw;\n })\n );\n\n const sheetName = (options.sheetName ?? \"Tasks\").slice(0, 31);\n const entries: ZipEntryInput[] = [\n textEntry(\"[Content_Types].xml\", contentTypesXml()),\n textEntry(\"_rels/.rels\", rootRelsXml()),\n textEntry(\"xl/workbook.xml\", workbookXml(sheetName)),\n textEntry(\"xl/_rels/workbook.xml.rels\", workbookRelsXml()),\n textEntry(\"xl/styles.xml\", stylesXml()),\n textEntry(\"xl/worksheets/sheet1.xml\", buildSheetXml(headerRow, rows)),\n ];\n return buildZip(entries);\n}\n"],"mappings":"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","names":[]}