@hirokisakabe/pom 8.3.0 → 8.5.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.
- package/README.md +35 -23
- package/dist/autoFit/autoFit.js +1 -1
- package/dist/autoFit/autoFit.js.map +1 -1
- package/dist/autoFit/strategies/reduceFontSize.js +16 -14
- package/dist/autoFit/strategies/reduceFontSize.js.map +1 -1
- package/dist/autoFit/strategies/reduceGapAndPadding.js +13 -20
- package/dist/autoFit/strategies/reduceGapAndPadding.js.map +1 -1
- package/dist/autoFit/strategies/reduceTableRowHeight.js +8 -2
- package/dist/autoFit/strategies/reduceTableRowHeight.js.map +1 -1
- package/dist/autoFit/strategies/uniformScale.js +19 -20
- package/dist/autoFit/strategies/uniformScale.js.map +1 -1
- package/dist/autoFit/strategyResult.js +15 -0
- package/dist/autoFit/strategyResult.js.map +1 -0
- package/dist/buildPptx.d.ts.map +1 -1
- package/dist/buildPptx.js +4 -2
- package/dist/buildPptx.js.map +1 -1
- package/dist/calcYogaLayout/calcYogaLayout.js +16 -27
- package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
- package/dist/diagnostics.d.ts +1 -1
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js.map +1 -1
- package/dist/parseXml/coercionRules.js +43 -8
- package/dist/parseXml/coercionRules.js.map +1 -1
- package/dist/parseXml/parseXml.d.ts +8 -3
- package/dist/parseXml/parseXml.d.ts.map +1 -1
- package/dist/parseXml/parseXml.js +192 -212
- package/dist/parseXml/parseXml.js.map +1 -1
- package/dist/parseXml/serializeXml.d.ts.map +1 -1
- package/dist/parseXml/serializeXml.js +12 -17
- package/dist/parseXml/serializeXml.js.map +1 -1
- package/dist/registry/definitions/arrow.js +2 -2
- package/dist/registry/definitions/arrow.js.map +1 -1
- package/dist/registry/definitions/chart.js +2 -2
- package/dist/registry/definitions/chart.js.map +1 -1
- package/dist/registry/definitions/compositeNodes.js +7 -12
- package/dist/registry/definitions/compositeNodes.js.map +1 -1
- package/dist/registry/definitions/icon.js +2 -2
- package/dist/registry/definitions/icon.js.map +1 -1
- package/dist/registry/definitions/image.js +2 -2
- package/dist/registry/definitions/image.js.map +1 -1
- package/dist/registry/definitions/layer.js +4 -5
- package/dist/registry/definitions/layer.js.map +1 -1
- package/dist/registry/definitions/line.js +2 -2
- package/dist/registry/definitions/line.js.map +1 -1
- package/dist/registry/definitions/list.js +3 -4
- package/dist/registry/definitions/list.js.map +1 -1
- package/dist/registry/definitions/shape.js +2 -2
- package/dist/registry/definitions/shape.js.map +1 -1
- package/dist/registry/definitions/stack.js +3 -4
- package/dist/registry/definitions/stack.js.map +1 -1
- package/dist/registry/definitions/svg.js +2 -2
- package/dist/registry/definitions/svg.js.map +1 -1
- package/dist/registry/definitions/table.js +2 -2
- package/dist/registry/definitions/table.js.map +1 -1
- package/dist/registry/definitions/text.js +2 -2
- package/dist/registry/definitions/text.js.map +1 -1
- package/dist/registry/index.js.map +1 -1
- package/dist/registry/nodeMetadata.js +208 -0
- package/dist/registry/nodeMetadata.js.map +1 -0
- package/dist/registry/nodeRegistry.js +3 -0
- package/dist/registry/nodeRegistry.js.map +1 -1
- package/dist/registry/xmlChildRules.js +55 -0
- package/dist/registry/xmlChildRules.js.map +1 -0
- package/dist/renderPptx/nodes/arrow.js +7 -28
- package/dist/renderPptx/nodes/arrow.js.map +1 -1
- package/dist/renderPptx/nodes/chart.js +2 -7
- package/dist/renderPptx/nodes/chart.js.map +1 -1
- package/dist/renderPptx/nodes/flow.js +6 -13
- package/dist/renderPptx/nodes/flow.js.map +1 -1
- package/dist/renderPptx/nodes/icon.js +4 -2
- package/dist/renderPptx/nodes/icon.js.map +1 -1
- package/dist/renderPptx/nodes/image.js +5 -13
- package/dist/renderPptx/nodes/image.js.map +1 -1
- package/dist/renderPptx/nodes/line.js +9 -33
- package/dist/renderPptx/nodes/line.js.map +1 -1
- package/dist/renderPptx/nodes/list.js +8 -20
- package/dist/renderPptx/nodes/list.js.map +1 -1
- package/dist/renderPptx/nodes/matrix.js +10 -11
- package/dist/renderPptx/nodes/matrix.js.map +1 -1
- package/dist/renderPptx/nodes/processArrow.js +9 -16
- package/dist/renderPptx/nodes/processArrow.js.map +1 -1
- package/dist/renderPptx/nodes/pyramid.js +5 -7
- package/dist/renderPptx/nodes/pyramid.js.map +1 -1
- package/dist/renderPptx/nodes/shape.js +7 -20
- package/dist/renderPptx/nodes/shape.js.map +1 -1
- package/dist/renderPptx/nodes/svg.js +2 -5
- package/dist/renderPptx/nodes/svg.js.map +1 -1
- package/dist/renderPptx/nodes/table.js +2 -5
- package/dist/renderPptx/nodes/table.js.map +1 -1
- package/dist/renderPptx/nodes/text.js +4 -1
- package/dist/renderPptx/nodes/text.js.map +1 -1
- package/dist/renderPptx/nodes/timeline.js +20 -22
- package/dist/renderPptx/nodes/timeline.js.map +1 -1
- package/dist/renderPptx/nodes/tree.js +5 -5
- package/dist/renderPptx/nodes/tree.js.map +1 -1
- package/dist/renderPptx/renderPptx.js +13 -29
- package/dist/renderPptx/renderPptx.js.map +1 -1
- package/dist/renderPptx/textOptions.js +32 -8
- package/dist/renderPptx/textOptions.js.map +1 -1
- package/dist/renderPptx/units.js +11 -1
- package/dist/renderPptx/units.js.map +1 -1
- package/dist/renderPptx/utils/backgroundBorder.js +103 -57
- package/dist/renderPptx/utils/backgroundBorder.js.map +1 -1
- package/dist/renderPptx/utils/contentArea.js +26 -9
- package/dist/renderPptx/utils/contentArea.js.map +1 -1
- package/dist/renderPptx/utils/scaleToFit.js +17 -1
- package/dist/renderPptx/utils/scaleToFit.js.map +1 -1
- package/dist/renderPptx/utils/straightLine.js +41 -0
- package/dist/renderPptx/utils/straightLine.js.map +1 -0
- package/dist/renderPptx/utils/visualStyle.js +113 -0
- package/dist/renderPptx/utils/visualStyle.js.map +1 -0
- package/dist/shared/boxSpacing.js +63 -0
- package/dist/shared/boxSpacing.js.map +1 -0
- package/dist/shared/walkTree.js +1 -7
- package/dist/shared/walkTree.js.map +1 -1
- package/dist/toPositioned/toPositioned.js +1 -1
- package/dist/toPositioned/toPositioned.js.map +1 -1
- package/dist/types.d.ts +1127 -95
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +47 -17
- package/dist/types.js.map +1 -1
- package/dist/validatePositioned/validatePositioned.js +92 -0
- package/dist/validatePositioned/validatePositioned.js.map +1 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -39,9 +39,12 @@
|
|
|
39
39
|
- **Declarative** — Describe slides as XML. No imperative API calls needed — just data in, PPTX out.
|
|
40
40
|
- **Flexible Layout** — Flexbox-style layout with VStack / HStack, powered by yoga-layout. Ratio-based layouts (e.g., 2:1 columns) via the `grow` attribute (CSS `flex-grow`).
|
|
41
41
|
- **Shorthand + Dot Notation** — Layout/style attributes (e.g. `padding`, `margin`, `border`, `fill`, `shadow`) can mix shorthand and dot notation on the same node. Shorthand sets defaults and dot notation overrides specific keys.
|
|
42
|
+
- **Per-Side Borders** — `borderTop` / `borderRight` / `borderBottom` / `borderLeft` style each edge independently (e.g. `borderLeft.width="6"` for an accent bar, `borderBottom.width="3"` for an underlined heading), merging field-by-field with the uniform `border`. See [Nodes — Common Properties](./docs/nodes.md#common-properties).
|
|
42
43
|
- **Rich Nodes** — 18 built-in node types: charts, flowcharts, tables, timelines, org trees, and more.
|
|
44
|
+
- **Design Tokens** — Declare a color palette once with a top-level `<Theme>` element and reference tokens as `$name` from any color attribute. See [Nodes — Top-Level `<Theme>`](./docs/nodes.md#top-level-theme-design-tokens).
|
|
43
45
|
- **Schema-validated** — XML input is validated with Zod schemas at runtime with clear error messages.
|
|
44
46
|
- **PowerPoint Native** — Generates real editable PowerPoint shapes — not images. Recipients can modify everything. Linear gradient backgrounds (`backgroundGradient="linear-gradient(135deg, #667EEA 0%, #764BA2 100%)"`) are exported as native gradient fills.
|
|
47
|
+
- **Leaf Rotation** — `Text`, `Shape`, `Image`, and `Icon` support `rotate` in clockwise degrees at render time without affecting flex layout.
|
|
45
48
|
- **Pixel Units** — Intuitive pixel-based sizing (internally converted to inches at 96 DPI).
|
|
46
49
|
- **Master Slide** — Define headers, footers, and page numbers once — applied to all slides automatically.
|
|
47
50
|
- **Accurate Text Measurement** — Text width measured with opentype.js and bundled Noto Sans JP fonts for consistent layout.
|
|
@@ -70,32 +73,41 @@ const { pptx } = await buildPptx(xml, { w: 1280, h: 720 });
|
|
|
70
73
|
await pptx.writeFile({ fileName: "presentation.pptx" });
|
|
71
74
|
```
|
|
72
75
|
|
|
73
|
-
Each slide must be wrapped in a `<Slide>` element. To produce multiple slides, list multiple `<Slide>` elements at the top level.
|
|
76
|
+
Each slide must be wrapped in a `<Slide>` element. To produce multiple slides, list multiple `<Slide>` elements at the top level. A single top-level `<Theme>` element may precede the slides to declare color tokens (referenced as `$name` from color attributes):
|
|
77
|
+
|
|
78
|
+
```xml
|
|
79
|
+
<Theme surface="0F172A" accent="38BDF8" textMain="F8FAFC" />
|
|
80
|
+
<Slide>
|
|
81
|
+
<VStack w="100%" h="max" padding="48" backgroundColor="$surface">
|
|
82
|
+
<Text fontSize="48" bold="true" color="$textMain">Dark Theme</Text>
|
|
83
|
+
</VStack>
|
|
84
|
+
</Slide>
|
|
85
|
+
```
|
|
74
86
|
|
|
75
87
|
## Available Nodes
|
|
76
88
|
|
|
77
|
-
| Node | Description
|
|
78
|
-
| ------------ |
|
|
79
|
-
| Text | Text with font styling, decoration, letter spacing, inline bold/italic/underline/strike/highlight/color, and hyperlinks |
|
|
80
|
-
| Ul | Unordered (bullet) list with Li items
|
|
81
|
-
| Ol | Ordered (numbered) list with Li items
|
|
82
|
-
| Image | Images from file path, URL, or base64
|
|
83
|
-
| Table | Tables with customizable columns and rows
|
|
84
|
-
| Shape | PowerPoint shapes (roundRect, ellipse, etc.)
|
|
85
|
-
| Chart | Charts (bar, line, pie, area, doughnut, radar)
|
|
86
|
-
| Timeline | Timeline / roadmap visualizations
|
|
87
|
-
| Matrix | 2x2 positioning maps
|
|
88
|
-
| Tree | Organization charts and decision trees
|
|
89
|
-
| Flow | Flowcharts with nodes and edges
|
|
90
|
-
| ProcessArrow | Chevron-style process diagrams
|
|
91
|
-
| Pyramid | Pyramid diagrams for hierarchies
|
|
92
|
-
| Line | Horizontal / vertical lines
|
|
93
|
-
| Arrow | Connectors between nodes referenced by ID
|
|
94
|
-
| Layer | Absolute-positioned overlay container
|
|
95
|
-
| VStack | Vertical stack layout
|
|
96
|
-
| HStack | Horizontal stack layout
|
|
97
|
-
| Icon | Lucide icons
|
|
98
|
-
| Svg | Inline SVG graphics
|
|
89
|
+
| Node | Description |
|
|
90
|
+
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
91
|
+
| Text | Text with font styling, decoration, rotation, letter spacing, glow / outline effects, inline bold/italic/underline/strike/highlight/color, and hyperlinks |
|
|
92
|
+
| Ul | Unordered (bullet) list with Li items |
|
|
93
|
+
| Ol | Ordered (numbered) list with Li items |
|
|
94
|
+
| Image | Images from file path, URL, or base64, with optional rotation |
|
|
95
|
+
| Table | Tables with customizable columns and rows |
|
|
96
|
+
| Shape | PowerPoint shapes (roundRect, ellipse, etc.) with optional rotation |
|
|
97
|
+
| Chart | Charts (bar, line, pie, area, doughnut, radar) |
|
|
98
|
+
| Timeline | Timeline / roadmap visualizations |
|
|
99
|
+
| Matrix | 2x2 positioning maps |
|
|
100
|
+
| Tree | Organization charts and decision trees |
|
|
101
|
+
| Flow | Flowcharts with nodes and edges |
|
|
102
|
+
| ProcessArrow | Chevron-style process diagrams |
|
|
103
|
+
| Pyramid | Pyramid diagrams for hierarchies |
|
|
104
|
+
| Line | Horizontal / vertical lines |
|
|
105
|
+
| Arrow | Connectors between nodes referenced by ID |
|
|
106
|
+
| Layer | Absolute-positioned overlay container |
|
|
107
|
+
| VStack | Vertical stack layout |
|
|
108
|
+
| HStack | Horizontal stack layout |
|
|
109
|
+
| Icon | Lucide icons with optional rotation |
|
|
110
|
+
| Svg | Inline SVG graphics |
|
|
99
111
|
|
|
100
112
|
For detailed node documentation, see [Nodes](./docs/nodes.md).
|
|
101
113
|
|
package/dist/autoFit/autoFit.js
CHANGED
|
@@ -62,7 +62,7 @@ async function autoFitSlide(node, slideSize, ctx) {
|
|
|
62
62
|
const result = await measureOverflow(node, slideSize, ctx);
|
|
63
63
|
freeYogaTree(result.map);
|
|
64
64
|
if (!result.isOverflowing) break;
|
|
65
|
-
if (!strategy(node, result.targetRatio)) continue;
|
|
65
|
+
if (!strategy(node, result.targetRatio).changed) continue;
|
|
66
66
|
}
|
|
67
67
|
return finalizeLayout(node, slideSize, ctx);
|
|
68
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"autoFit.js","names":[],"sources":["../../src/autoFit/autoFit.ts"],"sourcesContent":["import type { POMNode } from \"../types.ts\";\nimport type { BuildContext } from \"../buildContext.ts\";\nimport type { YogaNodeMap } from \"../calcYogaLayout/types.ts\";\nimport { calcYogaLayout } from \"../calcYogaLayout/calcYogaLayout.ts\";\nimport { freeYogaTree } from \"../shared/freeYogaTree.ts\";\nimport { reduceTableRowHeight } from \"./strategies/reduceTableRowHeight.ts\";\nimport { reduceFontSize } from \"./strategies/reduceFontSize.ts\";\nimport { reduceGapAndPadding } from \"./strategies/reduceGapAndPadding.ts\";\nimport { uniformScale } from \"./strategies/uniformScale.ts\";\n\n/** オーバーフロー判定の許容マージン(0.5%) */\nconst OVERFLOW_TOLERANCE = 1.005;\n\ntype Strategy = (node: POMNode, targetRatio: number) =>
|
|
1
|
+
{"version":3,"file":"autoFit.js","names":[],"sources":["../../src/autoFit/autoFit.ts"],"sourcesContent":["import type { POMNode } from \"../types.ts\";\nimport type { BuildContext } from \"../buildContext.ts\";\nimport type { YogaNodeMap } from \"../calcYogaLayout/types.ts\";\nimport { calcYogaLayout } from \"../calcYogaLayout/calcYogaLayout.ts\";\nimport { freeYogaTree } from \"../shared/freeYogaTree.ts\";\nimport { reduceTableRowHeight } from \"./strategies/reduceTableRowHeight.ts\";\nimport { reduceFontSize } from \"./strategies/reduceFontSize.ts\";\nimport { reduceGapAndPadding } from \"./strategies/reduceGapAndPadding.ts\";\nimport { uniformScale } from \"./strategies/uniformScale.ts\";\nimport type { AutoFitStrategyResult } from \"./strategyResult.ts\";\n\n/** オーバーフロー判定の許容マージン(0.5%) */\nconst OVERFLOW_TOLERANCE = 1.005;\n\ntype Strategy = (node: POMNode, targetRatio: number) => AutoFitStrategyResult;\n\nconst strategies: Strategy[] = [\n reduceTableRowHeight,\n reduceFontSize,\n reduceGapAndPadding,\n uniformScale,\n];\n\n/** オーバーフロー測定結果 */\ninterface OverflowResult {\n contentHeight: number;\n isOverflowing: boolean;\n /** スライド高さ / コンテンツ高さ(オーバーフロー時 < 1) */\n targetRatio: number;\n map: YogaNodeMap;\n}\n\n/**\n * レイアウト計算を実行し、コンテンツのオーバーフロー状態を測定する。\n */\nasync function measureOverflow(\n node: POMNode,\n slideSize: { w: number; h: number },\n ctx: BuildContext,\n): Promise<OverflowResult> {\n const map = await calcYogaLayout(node, slideSize, ctx);\n const contentHeight = calcContentHeight(map, node);\n const isOverflowing = contentHeight > slideSize.h * OVERFLOW_TOLERANCE;\n const targetRatio = isOverflowing ? slideSize.h / contentHeight : 1;\n return { contentHeight, isOverflowing, targetRatio, map };\n}\n\n/**\n * Yoga レイアウト結果からコンテンツの占有高さを算出する。\n *\n * ルートの yogaNode の子要素の (top + height) の最大値を計算し、\n * ルートの padding.bottom を加算してコンテンツの占有高さとする。\n * h=\"max\" や flexGrow の影響を受けず、正確なコンテンツ高さを返す。\n */\nfunction calcContentHeight(map: YogaNodeMap, node: POMNode): number {\n const rootYoga = map.get(node);\n if (!rootYoga) {\n throw new Error(\"YogaNode not found in map for root node\");\n }\n\n const childCount = rootYoga.getChildCount();\n if (childCount === 0) {\n return rootYoga.getComputedHeight();\n }\n\n let maxBottom = 0;\n for (let i = 0; i < childCount; i++) {\n const child = rootYoga.getChild(i);\n const childLayout = child.getComputedLayout();\n const bottom = childLayout.top + childLayout.height;\n if (bottom > maxBottom) {\n maxBottom = bottom;\n }\n }\n\n // ルートの paddingBottom を加算\n const paddingBottom = rootYoga.getComputedPadding(2); // EDGE_BOTTOM = 2\n return maxBottom + paddingBottom;\n}\n\n/**\n * スライドのオーバーフローを検出し、段階的に調整してスライド内に収める。\n *\n * 調整の優先順:\n * 1. テーブル行高さ縮小\n * 2. フォントサイズ縮小\n * 3. gap/padding 縮小\n * 4. 全体スケーリング(フォールバック)\n */\nexport async function autoFitSlide(\n node: POMNode,\n slideSize: { w: number; h: number },\n ctx: BuildContext,\n): Promise<YogaNodeMap> {\n // Phase 1: 戦略を順次適用してオーバーフローを解消\n for (const strategy of strategies) {\n const result = await measureOverflow(node, slideSize, ctx);\n freeYogaTree(result.map);\n\n if (!result.isOverflowing) {\n break;\n }\n\n const strategyResult = strategy(node, result.targetRatio);\n if (!strategyResult.changed) {\n continue;\n }\n }\n\n // Phase 2: 最終レイアウト計算とオーバーフロー検証\n return finalizeLayout(node, slideSize, ctx);\n}\n\n/**\n * 最終レイアウトを計算し、オーバーフローが残っていれば警告を出力する。\n */\nasync function finalizeLayout(\n node: POMNode,\n slideSize: { w: number; h: number },\n ctx: BuildContext,\n): Promise<YogaNodeMap> {\n const result = await measureOverflow(node, slideSize, ctx);\n if (result.isOverflowing) {\n ctx.diagnostics.add(\n \"AUTOFIT_OVERFLOW\",\n `autoFit: content height (${Math.round(result.contentHeight)}px) exceeds slide height (${slideSize.h}px) after all adjustments.`,\n );\n }\n freeYogaTree(result.map);\n\n return calcYogaLayout(node, slideSize, ctx);\n}\n"],"mappings":";;;;;;;;AAYA,MAAM,qBAAqB;AAI3B,MAAM,aAAyB;CAC7B;CACA;CACA;CACA;AACF;;;;AAcA,eAAe,gBACb,MACA,WACA,KACyB;CACzB,MAAM,MAAM,MAAM,eAAe,MAAM,WAAW,GAAG;CACrD,MAAM,gBAAgB,kBAAkB,KAAK,IAAI;CACjD,MAAM,gBAAgB,gBAAgB,UAAU,IAAI;CAEpD,OAAO;EAAE;EAAe;EAAe,aADnB,gBAAgB,UAAU,IAAI,gBAAgB;EACd;CAAI;AAC1D;;;;;;;;AASA,SAAS,kBAAkB,KAAkB,MAAuB;CAClE,MAAM,WAAW,IAAI,IAAI,IAAI;CAC7B,IAAI,CAAC,UACH,MAAM,IAAI,MAAM,yCAAyC;CAG3D,MAAM,aAAa,SAAS,cAAc;CAC1C,IAAI,eAAe,GACjB,OAAO,SAAS,kBAAkB;CAGpC,IAAI,YAAY;CAChB,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAAK;EAEnC,MAAM,cADQ,SAAS,SAAS,CACR,CAAC,CAAC,kBAAkB;EAC5C,MAAM,SAAS,YAAY,MAAM,YAAY;EAC7C,IAAI,SAAS,WACX,YAAY;CAEhB;CAGA,MAAM,gBAAgB,SAAS,mBAAmB,CAAC;CACnD,OAAO,YAAY;AACrB;;;;;;;;;;AAWA,eAAsB,aACpB,MACA,WACA,KACsB;CAEtB,KAAK,MAAM,YAAY,YAAY;EACjC,MAAM,SAAS,MAAM,gBAAgB,MAAM,WAAW,GAAG;EACzD,aAAa,OAAO,GAAG;EAEvB,IAAI,CAAC,OAAO,eACV;EAIF,IAAI,CADmB,SAAS,MAAM,OAAO,WAC3B,CAAC,CAAC,SAClB;CAEJ;CAGA,OAAO,eAAe,MAAM,WAAW,GAAG;AAC5C;;;;AAKA,eAAe,eACb,MACA,WACA,KACsB;CACtB,MAAM,SAAS,MAAM,gBAAgB,MAAM,WAAW,GAAG;CACzD,IAAI,OAAO,eACT,IAAI,YAAY,IACd,oBACA,4BAA4B,KAAK,MAAM,OAAO,aAAa,EAAE,4BAA4B,UAAU,EAAE,2BACvG;CAEF,aAAa,OAAO,GAAG;CAEvB,OAAO,eAAe,MAAM,WAAW,GAAG;AAC5C"}
|
|
@@ -1,32 +1,30 @@
|
|
|
1
1
|
import { walkPOMTree } from "../../shared/walkTree.js";
|
|
2
|
+
import { toStrategyResult } from "../strategyResult.js";
|
|
2
3
|
//#region src/autoFit/strategies/reduceFontSize.ts
|
|
3
4
|
const MIN_FONT_SIZE = 10;
|
|
4
5
|
const MIN_SCALE = .6;
|
|
5
6
|
/**
|
|
6
7
|
* テキスト系ノードの fontSize を縮小する。
|
|
7
8
|
* 対象: text, ul, ol, shape
|
|
8
|
-
* @returns 変更があった場合 true
|
|
9
9
|
*/
|
|
10
10
|
function reduceFontSize(node, targetRatio) {
|
|
11
11
|
const ratio = Math.max(targetRatio, MIN_SCALE);
|
|
12
12
|
let changed = false;
|
|
13
|
+
let sawTarget = false;
|
|
13
14
|
walkPOMTree(node, (n) => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if (newSize !== n.fontSize) {
|
|
22
|
-
n.fontSize = newSize;
|
|
23
|
-
changed = true;
|
|
24
|
-
}
|
|
15
|
+
if (n.type === "text" || n.type === "shape" || n.type === "ul" || n.type === "ol") {
|
|
16
|
+
if (n.fontSize !== void 0) {
|
|
17
|
+
sawTarget = true;
|
|
18
|
+
const newSize = Math.max(MIN_FONT_SIZE, Math.round(n.fontSize * ratio));
|
|
19
|
+
if (newSize !== n.fontSize) {
|
|
20
|
+
n.fontSize = newSize;
|
|
21
|
+
changed = true;
|
|
25
22
|
}
|
|
26
|
-
|
|
23
|
+
}
|
|
27
24
|
}
|
|
28
25
|
if (n.type === "ul" || n.type === "ol") {
|
|
29
26
|
for (const item of n.items) if (item.fontSize !== void 0) {
|
|
27
|
+
sawTarget = true;
|
|
30
28
|
const newSize = Math.max(MIN_FONT_SIZE, Math.round(item.fontSize * ratio));
|
|
31
29
|
if (newSize !== item.fontSize) {
|
|
32
30
|
item.fontSize = newSize;
|
|
@@ -36,6 +34,7 @@ function reduceFontSize(node, targetRatio) {
|
|
|
36
34
|
}
|
|
37
35
|
if (n.type === "table") {
|
|
38
36
|
for (const row of n.rows) for (const cell of row.cells) if (cell.fontSize !== void 0) {
|
|
37
|
+
sawTarget = true;
|
|
39
38
|
const newSize = Math.max(MIN_FONT_SIZE, Math.round(cell.fontSize * ratio));
|
|
40
39
|
if (newSize !== cell.fontSize) {
|
|
41
40
|
cell.fontSize = newSize;
|
|
@@ -44,7 +43,10 @@ function reduceFontSize(node, targetRatio) {
|
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
45
|
});
|
|
47
|
-
return
|
|
46
|
+
return toStrategyResult({
|
|
47
|
+
changed,
|
|
48
|
+
sawTarget
|
|
49
|
+
});
|
|
48
50
|
}
|
|
49
51
|
//#endregion
|
|
50
52
|
export { reduceFontSize };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reduceFontSize.js","names":[],"sources":["../../../src/autoFit/strategies/reduceFontSize.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\n\nconst MIN_FONT_SIZE = 10;\nconst MIN_SCALE = 0.6;\n\n/**\n * テキスト系ノードの fontSize を縮小する。\n * 対象: text, ul, ol, shape\n
|
|
1
|
+
{"version":3,"file":"reduceFontSize.js","names":[],"sources":["../../../src/autoFit/strategies/reduceFontSize.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\nimport type { AutoFitStrategyResult } from \"../strategyResult.ts\";\nimport { toStrategyResult } from \"../strategyResult.ts\";\n\nconst MIN_FONT_SIZE = 10;\nconst MIN_SCALE = 0.6;\n\n/**\n * テキスト系ノードの fontSize を縮小する。\n * 対象: text, ul, ol, shape\n */\nexport function reduceFontSize(\n node: POMNode,\n targetRatio: number,\n): AutoFitStrategyResult {\n const ratio = Math.max(targetRatio, MIN_SCALE);\n let changed = false;\n let sawTarget = false;\n\n walkPOMTree(node, (n) => {\n if (\n n.type === \"text\" ||\n n.type === \"shape\" ||\n n.type === \"ul\" ||\n n.type === \"ol\"\n ) {\n if (n.fontSize !== undefined) {\n sawTarget = true;\n const newSize = Math.max(MIN_FONT_SIZE, Math.round(n.fontSize * ratio));\n if (newSize !== n.fontSize) {\n n.fontSize = newSize;\n changed = true;\n }\n }\n }\n\n // ul/ol の li 要素の fontSize も縮小\n if (n.type === \"ul\" || n.type === \"ol\") {\n for (const item of n.items) {\n if (item.fontSize !== undefined) {\n sawTarget = true;\n const newSize = Math.max(\n MIN_FONT_SIZE,\n Math.round(item.fontSize * ratio),\n );\n if (newSize !== item.fontSize) {\n item.fontSize = newSize;\n changed = true;\n }\n }\n }\n }\n\n // table セルの fontSize も縮小\n if (n.type === \"table\") {\n for (const row of n.rows) {\n for (const cell of row.cells) {\n if (cell.fontSize !== undefined) {\n sawTarget = true;\n const newSize = Math.max(\n MIN_FONT_SIZE,\n Math.round(cell.fontSize * ratio),\n );\n if (newSize !== cell.fontSize) {\n cell.fontSize = newSize;\n changed = true;\n }\n }\n }\n }\n }\n });\n\n return toStrategyResult({ changed, sawTarget });\n}\n"],"mappings":";;;AAKA,MAAM,gBAAgB;AACtB,MAAM,YAAY;;;;;AAMlB,SAAgB,eACd,MACA,aACuB;CACvB,MAAM,QAAQ,KAAK,IAAI,aAAa,SAAS;CAC7C,IAAI,UAAU;CACd,IAAI,YAAY;CAEhB,YAAY,OAAO,MAAM;EACvB,IACE,EAAE,SAAS,UACX,EAAE,SAAS,WACX,EAAE,SAAS,QACX,EAAE,SAAS;OAEP,EAAE,aAAa,KAAA,GAAW;IAC5B,YAAY;IACZ,MAAM,UAAU,KAAK,IAAI,eAAe,KAAK,MAAM,EAAE,WAAW,KAAK,CAAC;IACtE,IAAI,YAAY,EAAE,UAAU;KAC1B,EAAE,WAAW;KACb,UAAU;IACZ;GACF;;EAIF,IAAI,EAAE,SAAS,QAAQ,EAAE,SAAS;QAC3B,MAAM,QAAQ,EAAE,OACnB,IAAI,KAAK,aAAa,KAAA,GAAW;IAC/B,YAAY;IACZ,MAAM,UAAU,KAAK,IACnB,eACA,KAAK,MAAM,KAAK,WAAW,KAAK,CAClC;IACA,IAAI,YAAY,KAAK,UAAU;KAC7B,KAAK,WAAW;KAChB,UAAU;IACZ;GACF;;EAKJ,IAAI,EAAE,SAAS;QACR,MAAM,OAAO,EAAE,MAClB,KAAK,MAAM,QAAQ,IAAI,OACrB,IAAI,KAAK,aAAa,KAAA,GAAW;IAC/B,YAAY;IACZ,MAAM,UAAU,KAAK,IACnB,eACA,KAAK,MAAM,KAAK,WAAW,KAAK,CAClC;IACA,IAAI,YAAY,KAAK,UAAU;KAC7B,KAAK,WAAW;KAChB,UAAU;IACZ;GACF;;CAIR,CAAC;CAED,OAAO,iBAAiB;EAAE;EAAS;CAAU,CAAC;AAChD"}
|
|
@@ -1,46 +1,39 @@
|
|
|
1
|
+
import { mapBoxSpacing } from "../../shared/boxSpacing.js";
|
|
1
2
|
import { walkPOMTree } from "../../shared/walkTree.js";
|
|
3
|
+
import { toStrategyResult } from "../strategyResult.js";
|
|
2
4
|
//#region src/autoFit/strategies/reduceGapAndPadding.ts
|
|
3
5
|
const MIN_GAP = 2;
|
|
4
6
|
const MIN_PADDING = 2;
|
|
5
7
|
const MIN_SCALE = .25;
|
|
6
8
|
/**
|
|
7
9
|
* gap と padding を縮小する。
|
|
8
|
-
* @returns 変更があった場合 true
|
|
9
10
|
*/
|
|
10
11
|
function reduceGapAndPadding(node, targetRatio) {
|
|
11
12
|
const ratio = Math.max(targetRatio, MIN_SCALE);
|
|
12
13
|
let changed = false;
|
|
14
|
+
let sawTarget = false;
|
|
13
15
|
walkPOMTree(node, (n) => {
|
|
14
16
|
if ((n.type === "vstack" || n.type === "hstack") && n.gap !== void 0) {
|
|
17
|
+
sawTarget = true;
|
|
15
18
|
const newGap = Math.max(MIN_GAP, Math.round(n.gap * ratio));
|
|
16
19
|
if (newGap !== n.gap) {
|
|
17
20
|
n.gap = newGap;
|
|
18
21
|
changed = true;
|
|
19
22
|
}
|
|
20
23
|
}
|
|
21
|
-
if (n.padding !== void 0)
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
if (n.padding !== void 0) {
|
|
25
|
+
sawTarget = true;
|
|
26
|
+
const result = mapBoxSpacing(n.padding, (v) => Math.max(MIN_PADDING, Math.round(v * ratio)));
|
|
27
|
+
if (result.changed) {
|
|
28
|
+
n.padding = result.value;
|
|
25
29
|
changed = true;
|
|
26
30
|
}
|
|
27
|
-
} else for (const dir of [
|
|
28
|
-
"top",
|
|
29
|
-
"right",
|
|
30
|
-
"bottom",
|
|
31
|
-
"left"
|
|
32
|
-
]) {
|
|
33
|
-
const val = n.padding[dir];
|
|
34
|
-
if (val !== void 0) {
|
|
35
|
-
const newVal = Math.max(MIN_PADDING, Math.round(val * ratio));
|
|
36
|
-
if (newVal !== val) {
|
|
37
|
-
n.padding[dir] = newVal;
|
|
38
|
-
changed = true;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
31
|
}
|
|
42
32
|
});
|
|
43
|
-
return
|
|
33
|
+
return toStrategyResult({
|
|
34
|
+
changed,
|
|
35
|
+
sawTarget
|
|
36
|
+
});
|
|
44
37
|
}
|
|
45
38
|
//#endregion
|
|
46
39
|
export { reduceGapAndPadding };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reduceGapAndPadding.js","names":[],"sources":["../../../src/autoFit/strategies/reduceGapAndPadding.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\n\nconst MIN_GAP = 2;\nconst MIN_PADDING = 2;\nconst MIN_SCALE = 0.25;\n\n/**\n * gap と padding を縮小する。\n
|
|
1
|
+
{"version":3,"file":"reduceGapAndPadding.js","names":[],"sources":["../../../src/autoFit/strategies/reduceGapAndPadding.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\nimport { mapBoxSpacing } from \"../../shared/boxSpacing.ts\";\nimport type { AutoFitStrategyResult } from \"../strategyResult.ts\";\nimport { toStrategyResult } from \"../strategyResult.ts\";\n\nconst MIN_GAP = 2;\nconst MIN_PADDING = 2;\nconst MIN_SCALE = 0.25;\n\n/**\n * gap と padding を縮小する。\n */\nexport function reduceGapAndPadding(\n node: POMNode,\n targetRatio: number,\n): AutoFitStrategyResult {\n const ratio = Math.max(targetRatio, MIN_SCALE);\n let changed = false;\n let sawTarget = false;\n\n walkPOMTree(node, (n) => {\n // gap の縮小(vstack, hstack)\n if ((n.type === \"vstack\" || n.type === \"hstack\") && n.gap !== undefined) {\n sawTarget = true;\n const newGap = Math.max(MIN_GAP, Math.round(n.gap * ratio));\n if (newGap !== n.gap) {\n n.gap = newGap;\n changed = true;\n }\n }\n\n // padding の縮小\n if (n.padding !== undefined) {\n sawTarget = true;\n const result = mapBoxSpacing(n.padding, (v) =>\n Math.max(MIN_PADDING, Math.round(v * ratio)),\n );\n if (result.changed) {\n n.padding = result.value;\n changed = true;\n }\n }\n });\n\n return toStrategyResult({ changed, sawTarget });\n}\n"],"mappings":";;;;AAMA,MAAM,UAAU;AAChB,MAAM,cAAc;AACpB,MAAM,YAAY;;;;AAKlB,SAAgB,oBACd,MACA,aACuB;CACvB,MAAM,QAAQ,KAAK,IAAI,aAAa,SAAS;CAC7C,IAAI,UAAU;CACd,IAAI,YAAY;CAEhB,YAAY,OAAO,MAAM;EAEvB,KAAK,EAAE,SAAS,YAAY,EAAE,SAAS,aAAa,EAAE,QAAQ,KAAA,GAAW;GACvE,YAAY;GACZ,MAAM,SAAS,KAAK,IAAI,SAAS,KAAK,MAAM,EAAE,MAAM,KAAK,CAAC;GAC1D,IAAI,WAAW,EAAE,KAAK;IACpB,EAAE,MAAM;IACR,UAAU;GACZ;EACF;EAGA,IAAI,EAAE,YAAY,KAAA,GAAW;GAC3B,YAAY;GACZ,MAAM,SAAS,cAAc,EAAE,UAAU,MACvC,KAAK,IAAI,aAAa,KAAK,MAAM,IAAI,KAAK,CAAC,CAC7C;GACA,IAAI,OAAO,SAAS;IAClB,EAAE,UAAU,OAAO;IACnB,UAAU;GACZ;EACF;CACF,CAAC;CAED,OAAO,iBAAiB;EAAE;EAAS;CAAU,CAAC;AAChD"}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { walkPOMTree } from "../../shared/walkTree.js";
|
|
2
|
+
import { toStrategyResult } from "../strategyResult.js";
|
|
2
3
|
//#region src/autoFit/strategies/reduceTableRowHeight.ts
|
|
3
4
|
const MIN_ROW_HEIGHT = 20;
|
|
4
5
|
const MIN_SCALE = .5;
|
|
5
6
|
/**
|
|
6
7
|
* テーブルの defaultRowHeight と各行の height を縮小する。
|
|
7
|
-
* @returns 変更があった場合 true
|
|
8
8
|
*/
|
|
9
9
|
function reduceTableRowHeight(node, targetRatio) {
|
|
10
10
|
const ratio = Math.max(targetRatio, MIN_SCALE);
|
|
11
11
|
let changed = false;
|
|
12
|
+
let sawTarget = false;
|
|
12
13
|
walkPOMTree(node, (n) => {
|
|
13
14
|
if (n.type !== "table") return;
|
|
14
15
|
if (n.defaultRowHeight !== void 0) {
|
|
16
|
+
sawTarget = true;
|
|
15
17
|
const newHeight = Math.max(MIN_ROW_HEIGHT, Math.round(n.defaultRowHeight * ratio));
|
|
16
18
|
if (newHeight !== n.defaultRowHeight) {
|
|
17
19
|
n.defaultRowHeight = newHeight;
|
|
@@ -19,6 +21,7 @@ function reduceTableRowHeight(node, targetRatio) {
|
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
for (const row of n.rows) if (row.height !== void 0) {
|
|
24
|
+
sawTarget = true;
|
|
22
25
|
const newHeight = Math.max(MIN_ROW_HEIGHT, Math.round(row.height * ratio));
|
|
23
26
|
if (newHeight !== row.height) {
|
|
24
27
|
row.height = newHeight;
|
|
@@ -26,7 +29,10 @@ function reduceTableRowHeight(node, targetRatio) {
|
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
});
|
|
29
|
-
return
|
|
32
|
+
return toStrategyResult({
|
|
33
|
+
changed,
|
|
34
|
+
sawTarget
|
|
35
|
+
});
|
|
30
36
|
}
|
|
31
37
|
//#endregion
|
|
32
38
|
export { reduceTableRowHeight };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reduceTableRowHeight.js","names":[],"sources":["../../../src/autoFit/strategies/reduceTableRowHeight.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\n\nconst MIN_ROW_HEIGHT = 20;\nconst MIN_SCALE = 0.5;\n\n/**\n * テーブルの defaultRowHeight と各行の height を縮小する。\n
|
|
1
|
+
{"version":3,"file":"reduceTableRowHeight.js","names":[],"sources":["../../../src/autoFit/strategies/reduceTableRowHeight.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\nimport type { AutoFitStrategyResult } from \"../strategyResult.ts\";\nimport { toStrategyResult } from \"../strategyResult.ts\";\n\nconst MIN_ROW_HEIGHT = 20;\nconst MIN_SCALE = 0.5;\n\n/**\n * テーブルの defaultRowHeight と各行の height を縮小する。\n */\nexport function reduceTableRowHeight(\n node: POMNode,\n targetRatio: number,\n): AutoFitStrategyResult {\n const ratio = Math.max(targetRatio, MIN_SCALE);\n let changed = false;\n let sawTarget = false;\n\n walkPOMTree(node, (n) => {\n if (n.type !== \"table\") return;\n\n if (n.defaultRowHeight !== undefined) {\n sawTarget = true;\n const newHeight = Math.max(\n MIN_ROW_HEIGHT,\n Math.round(n.defaultRowHeight * ratio),\n );\n if (newHeight !== n.defaultRowHeight) {\n n.defaultRowHeight = newHeight;\n changed = true;\n }\n }\n\n for (const row of n.rows) {\n if (row.height !== undefined) {\n sawTarget = true;\n const newHeight = Math.max(\n MIN_ROW_HEIGHT,\n Math.round(row.height * ratio),\n );\n if (newHeight !== row.height) {\n row.height = newHeight;\n changed = true;\n }\n }\n }\n });\n\n return toStrategyResult({ changed, sawTarget });\n}\n"],"mappings":";;;AAKA,MAAM,iBAAiB;AACvB,MAAM,YAAY;;;;AAKlB,SAAgB,qBACd,MACA,aACuB;CACvB,MAAM,QAAQ,KAAK,IAAI,aAAa,SAAS;CAC7C,IAAI,UAAU;CACd,IAAI,YAAY;CAEhB,YAAY,OAAO,MAAM;EACvB,IAAI,EAAE,SAAS,SAAS;EAExB,IAAI,EAAE,qBAAqB,KAAA,GAAW;GACpC,YAAY;GACZ,MAAM,YAAY,KAAK,IACrB,gBACA,KAAK,MAAM,EAAE,mBAAmB,KAAK,CACvC;GACA,IAAI,cAAc,EAAE,kBAAkB;IACpC,EAAE,mBAAmB;IACrB,UAAU;GACZ;EACF;EAEA,KAAK,MAAM,OAAO,EAAE,MAClB,IAAI,IAAI,WAAW,KAAA,GAAW;GAC5B,YAAY;GACZ,MAAM,YAAY,KAAK,IACrB,gBACA,KAAK,MAAM,IAAI,SAAS,KAAK,CAC/B;GACA,IAAI,cAAc,IAAI,QAAQ;IAC5B,IAAI,SAAS;IACb,UAAU;GACZ;EACF;CAEJ,CAAC;CAED,OAAO,iBAAiB;EAAE;EAAS;CAAU,CAAC;AAChD"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { mapBoxSpacing } from "../../shared/boxSpacing.js";
|
|
1
2
|
import { walkPOMTree } from "../../shared/walkTree.js";
|
|
3
|
+
import { toStrategyResult } from "../strategyResult.js";
|
|
2
4
|
//#region src/autoFit/strategies/uniformScale.ts
|
|
3
5
|
const MIN_SCALE = .5;
|
|
4
6
|
function scaleNumber(value, ratio, min) {
|
|
@@ -6,13 +8,14 @@ function scaleNumber(value, ratio, min) {
|
|
|
6
8
|
}
|
|
7
9
|
/**
|
|
8
10
|
* 全サイズ関連プロパティを一律スケーリングする(フォールバック)。
|
|
9
|
-
* @returns 変更があった場合 true
|
|
10
11
|
*/
|
|
11
12
|
function uniformScale(node, targetRatio) {
|
|
12
13
|
const ratio = Math.max(targetRatio, MIN_SCALE);
|
|
13
14
|
let changed = false;
|
|
15
|
+
let sawTarget = false;
|
|
14
16
|
walkPOMTree(node, (n) => {
|
|
15
17
|
if ("fontSize" in n && typeof n.fontSize === "number") {
|
|
18
|
+
sawTarget = true;
|
|
16
19
|
const newVal = scaleNumber(n.fontSize, ratio, 8);
|
|
17
20
|
if (newVal !== n.fontSize) {
|
|
18
21
|
n.fontSize = newVal;
|
|
@@ -20,35 +23,24 @@ function uniformScale(node, targetRatio) {
|
|
|
20
23
|
}
|
|
21
24
|
}
|
|
22
25
|
if ((n.type === "vstack" || n.type === "hstack") && n.gap !== void 0) {
|
|
26
|
+
sawTarget = true;
|
|
23
27
|
const newVal = scaleNumber(n.gap, ratio, 1);
|
|
24
28
|
if (newVal !== n.gap) {
|
|
25
29
|
n.gap = newVal;
|
|
26
30
|
changed = true;
|
|
27
31
|
}
|
|
28
32
|
}
|
|
29
|
-
if (n.padding !== void 0)
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
if (n.padding !== void 0) {
|
|
34
|
+
sawTarget = true;
|
|
35
|
+
const result = mapBoxSpacing(n.padding, (v) => scaleNumber(v, ratio, 1));
|
|
36
|
+
if (result.changed) {
|
|
37
|
+
n.padding = result.value;
|
|
33
38
|
changed = true;
|
|
34
39
|
}
|
|
35
|
-
} else for (const dir of [
|
|
36
|
-
"top",
|
|
37
|
-
"right",
|
|
38
|
-
"bottom",
|
|
39
|
-
"left"
|
|
40
|
-
]) {
|
|
41
|
-
const val = n.padding[dir];
|
|
42
|
-
if (val !== void 0) {
|
|
43
|
-
const newVal = scaleNumber(val, ratio, 1);
|
|
44
|
-
if (newVal !== val) {
|
|
45
|
-
n.padding[dir] = newVal;
|
|
46
|
-
changed = true;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
40
|
}
|
|
50
41
|
if (n.type === "table") {
|
|
51
42
|
if (n.defaultRowHeight !== void 0) {
|
|
43
|
+
sawTarget = true;
|
|
52
44
|
const newVal = scaleNumber(n.defaultRowHeight, ratio, 16);
|
|
53
45
|
if (newVal !== n.defaultRowHeight) {
|
|
54
46
|
n.defaultRowHeight = newVal;
|
|
@@ -56,6 +48,7 @@ function uniformScale(node, targetRatio) {
|
|
|
56
48
|
}
|
|
57
49
|
}
|
|
58
50
|
for (const row of n.rows) if (row.height !== void 0) {
|
|
51
|
+
sawTarget = true;
|
|
59
52
|
const newVal = scaleNumber(row.height, ratio, 16);
|
|
60
53
|
if (newVal !== row.height) {
|
|
61
54
|
row.height = newVal;
|
|
@@ -65,6 +58,7 @@ function uniformScale(node, targetRatio) {
|
|
|
65
58
|
}
|
|
66
59
|
if (n.type === "ul" || n.type === "ol") {
|
|
67
60
|
for (const item of n.items) if (item.fontSize !== void 0) {
|
|
61
|
+
sawTarget = true;
|
|
68
62
|
const newVal = scaleNumber(item.fontSize, ratio, 8);
|
|
69
63
|
if (newVal !== item.fontSize) {
|
|
70
64
|
item.fontSize = newVal;
|
|
@@ -73,6 +67,7 @@ function uniformScale(node, targetRatio) {
|
|
|
73
67
|
}
|
|
74
68
|
}
|
|
75
69
|
if (n.type === "icon" && n.size !== void 0) {
|
|
70
|
+
sawTarget = true;
|
|
76
71
|
const newVal = scaleNumber(n.size, ratio, 8);
|
|
77
72
|
if (newVal !== n.size) {
|
|
78
73
|
n.size = newVal;
|
|
@@ -81,6 +76,7 @@ function uniformScale(node, targetRatio) {
|
|
|
81
76
|
}
|
|
82
77
|
if (n.type === "table") {
|
|
83
78
|
for (const row of n.rows) for (const cell of row.cells) if (cell.fontSize !== void 0) {
|
|
79
|
+
sawTarget = true;
|
|
84
80
|
const newVal = scaleNumber(cell.fontSize, ratio, 8);
|
|
85
81
|
if (newVal !== cell.fontSize) {
|
|
86
82
|
cell.fontSize = newVal;
|
|
@@ -89,7 +85,10 @@ function uniformScale(node, targetRatio) {
|
|
|
89
85
|
}
|
|
90
86
|
}
|
|
91
87
|
});
|
|
92
|
-
return
|
|
88
|
+
return toStrategyResult({
|
|
89
|
+
changed,
|
|
90
|
+
sawTarget
|
|
91
|
+
});
|
|
93
92
|
}
|
|
94
93
|
//#endregion
|
|
95
94
|
export { uniformScale };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uniformScale.js","names":[],"sources":["../../../src/autoFit/strategies/uniformScale.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\n\nconst MIN_SCALE = 0.5;\n\nfunction scaleNumber(value: number, ratio: number, min: number): number {\n return Math.max(min, Math.round(value * ratio));\n}\n\n/**\n * 全サイズ関連プロパティを一律スケーリングする(フォールバック)。\n
|
|
1
|
+
{"version":3,"file":"uniformScale.js","names":[],"sources":["../../../src/autoFit/strategies/uniformScale.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport { walkPOMTree } from \"../../shared/walkTree.ts\";\nimport { mapBoxSpacing } from \"../../shared/boxSpacing.ts\";\nimport type { AutoFitStrategyResult } from \"../strategyResult.ts\";\nimport { toStrategyResult } from \"../strategyResult.ts\";\n\nconst MIN_SCALE = 0.5;\n\nfunction scaleNumber(value: number, ratio: number, min: number): number {\n return Math.max(min, Math.round(value * ratio));\n}\n\n/**\n * 全サイズ関連プロパティを一律スケーリングする(フォールバック)。\n */\nexport function uniformScale(\n node: POMNode,\n targetRatio: number,\n): AutoFitStrategyResult {\n const ratio = Math.max(targetRatio, MIN_SCALE);\n let changed = false;\n let sawTarget = false;\n\n walkPOMTree(node, (n) => {\n // fontSize\n if (\"fontSize\" in n && typeof n.fontSize === \"number\") {\n sawTarget = true;\n const newVal = scaleNumber(n.fontSize, ratio, 8);\n if (newVal !== n.fontSize) {\n (n as { fontSize: number }).fontSize = newVal;\n changed = true;\n }\n }\n\n // gap (vstack/hstack)\n if ((n.type === \"vstack\" || n.type === \"hstack\") && n.gap !== undefined) {\n sawTarget = true;\n const newVal = scaleNumber(n.gap, ratio, 1);\n if (newVal !== n.gap) {\n n.gap = newVal;\n changed = true;\n }\n }\n\n // padding\n if (n.padding !== undefined) {\n sawTarget = true;\n const result = mapBoxSpacing(n.padding, (v) => scaleNumber(v, ratio, 1));\n if (result.changed) {\n n.padding = result.value;\n changed = true;\n }\n }\n\n // table: defaultRowHeight, row.height\n if (n.type === \"table\") {\n if (n.defaultRowHeight !== undefined) {\n sawTarget = true;\n const newVal = scaleNumber(n.defaultRowHeight, ratio, 16);\n if (newVal !== n.defaultRowHeight) {\n n.defaultRowHeight = newVal;\n changed = true;\n }\n }\n for (const row of n.rows) {\n if (row.height !== undefined) {\n sawTarget = true;\n const newVal = scaleNumber(row.height, ratio, 16);\n if (newVal !== row.height) {\n row.height = newVal;\n changed = true;\n }\n }\n }\n }\n\n // ul/ol items fontSize\n if (n.type === \"ul\" || n.type === \"ol\") {\n for (const item of n.items) {\n if (item.fontSize !== undefined) {\n sawTarget = true;\n const newVal = scaleNumber(item.fontSize, ratio, 8);\n if (newVal !== item.fontSize) {\n item.fontSize = newVal;\n changed = true;\n }\n }\n }\n }\n\n // icon size\n if (n.type === \"icon\" && n.size !== undefined) {\n sawTarget = true;\n const newVal = scaleNumber(n.size, ratio, 8);\n if (newVal !== n.size) {\n n.size = newVal;\n changed = true;\n }\n }\n\n // table cells fontSize\n if (n.type === \"table\") {\n for (const row of n.rows) {\n for (const cell of row.cells) {\n if (cell.fontSize !== undefined) {\n sawTarget = true;\n const newVal = scaleNumber(cell.fontSize, ratio, 8);\n if (newVal !== cell.fontSize) {\n cell.fontSize = newVal;\n changed = true;\n }\n }\n }\n }\n }\n });\n\n return toStrategyResult({ changed, sawTarget });\n}\n"],"mappings":";;;;AAMA,MAAM,YAAY;AAElB,SAAS,YAAY,OAAe,OAAe,KAAqB;CACtE,OAAO,KAAK,IAAI,KAAK,KAAK,MAAM,QAAQ,KAAK,CAAC;AAChD;;;;AAKA,SAAgB,aACd,MACA,aACuB;CACvB,MAAM,QAAQ,KAAK,IAAI,aAAa,SAAS;CAC7C,IAAI,UAAU;CACd,IAAI,YAAY;CAEhB,YAAY,OAAO,MAAM;EAEvB,IAAI,cAAc,KAAK,OAAO,EAAE,aAAa,UAAU;GACrD,YAAY;GACZ,MAAM,SAAS,YAAY,EAAE,UAAU,OAAO,CAAC;GAC/C,IAAI,WAAW,EAAE,UAAU;IACzB,EAA4B,WAAW;IACvC,UAAU;GACZ;EACF;EAGA,KAAK,EAAE,SAAS,YAAY,EAAE,SAAS,aAAa,EAAE,QAAQ,KAAA,GAAW;GACvE,YAAY;GACZ,MAAM,SAAS,YAAY,EAAE,KAAK,OAAO,CAAC;GAC1C,IAAI,WAAW,EAAE,KAAK;IACpB,EAAE,MAAM;IACR,UAAU;GACZ;EACF;EAGA,IAAI,EAAE,YAAY,KAAA,GAAW;GAC3B,YAAY;GACZ,MAAM,SAAS,cAAc,EAAE,UAAU,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC;GACvE,IAAI,OAAO,SAAS;IAClB,EAAE,UAAU,OAAO;IACnB,UAAU;GACZ;EACF;EAGA,IAAI,EAAE,SAAS,SAAS;GACtB,IAAI,EAAE,qBAAqB,KAAA,GAAW;IACpC,YAAY;IACZ,MAAM,SAAS,YAAY,EAAE,kBAAkB,OAAO,EAAE;IACxD,IAAI,WAAW,EAAE,kBAAkB;KACjC,EAAE,mBAAmB;KACrB,UAAU;IACZ;GACF;GACA,KAAK,MAAM,OAAO,EAAE,MAClB,IAAI,IAAI,WAAW,KAAA,GAAW;IAC5B,YAAY;IACZ,MAAM,SAAS,YAAY,IAAI,QAAQ,OAAO,EAAE;IAChD,IAAI,WAAW,IAAI,QAAQ;KACzB,IAAI,SAAS;KACb,UAAU;IACZ;GACF;EAEJ;EAGA,IAAI,EAAE,SAAS,QAAQ,EAAE,SAAS;QAC3B,MAAM,QAAQ,EAAE,OACnB,IAAI,KAAK,aAAa,KAAA,GAAW;IAC/B,YAAY;IACZ,MAAM,SAAS,YAAY,KAAK,UAAU,OAAO,CAAC;IAClD,IAAI,WAAW,KAAK,UAAU;KAC5B,KAAK,WAAW;KAChB,UAAU;IACZ;GACF;;EAKJ,IAAI,EAAE,SAAS,UAAU,EAAE,SAAS,KAAA,GAAW;GAC7C,YAAY;GACZ,MAAM,SAAS,YAAY,EAAE,MAAM,OAAO,CAAC;GAC3C,IAAI,WAAW,EAAE,MAAM;IACrB,EAAE,OAAO;IACT,UAAU;GACZ;EACF;EAGA,IAAI,EAAE,SAAS;QACR,MAAM,OAAO,EAAE,MAClB,KAAK,MAAM,QAAQ,IAAI,OACrB,IAAI,KAAK,aAAa,KAAA,GAAW;IAC/B,YAAY;IACZ,MAAM,SAAS,YAAY,KAAK,UAAU,OAAO,CAAC;IAClD,IAAI,WAAW,KAAK,UAAU;KAC5B,KAAK,WAAW;KAChB,UAAU;IACZ;GACF;;CAIR,CAAC;CAED,OAAO,iBAAiB;EAAE;EAAS;CAAU,CAAC;AAChD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/autoFit/strategyResult.ts
|
|
2
|
+
/**
|
|
3
|
+
* strategy 内部で集計した「変更有無」「調整対象の有無」から共通 result を組み立てる。
|
|
4
|
+
*/
|
|
5
|
+
function toStrategyResult(params) {
|
|
6
|
+
if (params.changed) return { changed: true };
|
|
7
|
+
return {
|
|
8
|
+
changed: false,
|
|
9
|
+
reason: params.sawTarget ? "no-effective-change" : "no-target"
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { toStrategyResult };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=strategyResult.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"strategyResult.js","names":[],"sources":["../../src/autoFit/strategyResult.ts"],"sourcesContent":["/** AutoFit strategy が変更を適用できなかった理由 */\nexport type AutoFitSkipReason =\n /** 調整対象となる属性を持つノードが存在しない */\n | \"no-target\"\n /** 調整対象はあるが、下限値への到達や丸めにより値が変化しなかった */\n | \"no-effective-change\";\n\n/** AutoFit strategy の適用結果 */\nexport type AutoFitStrategyResult =\n | { changed: true }\n | { changed: false; reason: AutoFitSkipReason };\n\n/**\n * strategy 内部で集計した「変更有無」「調整対象の有無」から共通 result を組み立てる。\n */\nexport function toStrategyResult(params: {\n changed: boolean;\n sawTarget: boolean;\n}): AutoFitStrategyResult {\n if (params.changed) {\n return { changed: true };\n }\n return {\n changed: false,\n reason: params.sawTarget ? \"no-effective-change\" : \"no-target\",\n };\n}\n"],"mappings":";;;;AAeA,SAAgB,iBAAiB,QAGP;CACxB,IAAI,OAAO,SACT,OAAO,EAAE,SAAS,KAAK;CAEzB,OAAO;EACL,SAAS;EACT,QAAQ,OAAO,YAAY,wBAAwB;CACrD;AACF"}
|
package/dist/buildPptx.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildPptx.d.ts","names":[],"sources":["../src/buildPptx.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"buildPptx.d.ts","names":[],"sources":["../src/buildPptx.ts"],"mappings":";;;;;UAmBiB,eAAA;EACf,IAAA,sBAA0B,OAAA;EAC1B,WAAA,EAAa,UAAU;AAAA;AAAA,iBAGH,SAAA,CACpB,GAAA,UACA,SAAA;EAAa,CAAA;EAAW,CAAA;AAAA,GACxB,OAAA;EACE,MAAA,GAAS,kBAAA;EACT,UAAA,GAAa,WAAA,GAAc,UAAA;EAC3B,eAAA,GAAkB,mBAAA;EAClB,OAAA;EACA,MAAA;AAAA,IAED,OAAA,CAAQ,eAAA"}
|
package/dist/buildPptx.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { freeYogaTree } from "./shared/freeYogaTree.js";
|
|
2
|
-
import { toPositioned } from "./toPositioned/toPositioned.js";
|
|
3
2
|
import { calcYogaLayout } from "./calcYogaLayout/calcYogaLayout.js";
|
|
4
3
|
import { autoFitSlide } from "./autoFit/autoFit.js";
|
|
5
4
|
import { DiagnosticsError } from "./diagnostics.js";
|
|
@@ -9,6 +8,8 @@ import { extractLayoutResults } from "./calcYogaLayout/types.js";
|
|
|
9
8
|
import { parseMasterPptx } from "./parseMasterPptx.js";
|
|
10
9
|
import { parseXml } from "./parseXml/parseXml.js";
|
|
11
10
|
import { renderPptx } from "./renderPptx/renderPptx.js";
|
|
11
|
+
import { toPositioned } from "./toPositioned/toPositioned.js";
|
|
12
|
+
import { validatePositioned } from "./validatePositioned/validatePositioned.js";
|
|
12
13
|
//#region src/buildPptx.ts
|
|
13
14
|
async function buildPptx(xml, slideSize, options) {
|
|
14
15
|
const ctx = createBuildContext(options?.textMeasurement ?? "auto");
|
|
@@ -16,12 +17,13 @@ async function buildPptx(xml, slideSize, options) {
|
|
|
16
17
|
if (options?.master) ctx.gradientFills.reserveColors(JSON.stringify(options.master));
|
|
17
18
|
const nodes = parseXml(xml);
|
|
18
19
|
const positionedPages = [];
|
|
19
|
-
for (const node of nodes) {
|
|
20
|
+
for (const [slideIndex, node] of nodes.entries()) {
|
|
20
21
|
let map;
|
|
21
22
|
try {
|
|
22
23
|
if (options?.autoFit !== false) map = await autoFitSlide(node, slideSize, ctx);
|
|
23
24
|
else map = await calcYogaLayout(node, slideSize, ctx);
|
|
24
25
|
const positioned = await toPositioned(node, ctx, extractLayoutResults(map));
|
|
26
|
+
validatePositioned(positioned, slideSize, ctx, slideIndex);
|
|
25
27
|
positionedPages.push(positioned);
|
|
26
28
|
} finally {
|
|
27
29
|
if (map) freeYogaTree(map);
|
package/dist/buildPptx.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildPptx.js","names":[],"sources":["../src/buildPptx.ts"],"sourcesContent":["import { autoFitSlide } from \"./autoFit/autoFit.ts\";\nimport { createBuildContext } from \"./buildContext.ts\";\nimport { calcYogaLayout } from \"./calcYogaLayout/calcYogaLayout.ts\";\nimport type { TextMeasurementMode } from \"./calcYogaLayout/measureText.ts\";\nimport type { YogaNodeMap } from \"./calcYogaLayout/types.ts\";\nimport { extractLayoutResults } from \"./calcYogaLayout/types.ts\";\nimport type { Diagnostic } from \"./diagnostics.ts\";\nimport { DiagnosticsError } from \"./diagnostics.ts\";\nimport { parseMasterPptx } from \"./parseMasterPptx.ts\";\nimport { parseXml } from \"./parseXml/parseXml.ts\";\nimport { patchPptxWriteForGradientFills } from \"./renderPptx/gradientFills.ts\";\nimport { renderPptx } from \"./renderPptx/renderPptx.ts\";\nimport { freeYogaTree } from \"./shared/freeYogaTree.ts\";\nimport { toPositioned } from \"./toPositioned/toPositioned.ts\";\nimport { PositionedNode, SlideMasterOptions } from \"./types.ts\";\n\nexport type { TextMeasurementMode };\n\nexport interface BuildPptxResult {\n pptx: import(\"pptxgenjs\").default;\n diagnostics: Diagnostic[];\n}\n\nexport async function buildPptx(\n xml: string,\n slideSize: { w: number; h: number },\n options?: {\n master?: SlideMasterOptions;\n masterPptx?: ArrayBuffer | Uint8Array;\n textMeasurement?: TextMeasurementMode;\n autoFit?: boolean;\n strict?: boolean;\n },\n): Promise<BuildPptxResult> {\n const ctx = createBuildContext(options?.textMeasurement ?? \"auto\");\n\n // グラデーション後処理のマーカー色がユーザー指定色と衝突しないよう、\n // 入力 XML / master オプション中に現れる色を予約しておく\n ctx.gradientFills.reserveColors(xml);\n if (options?.master) {\n ctx.gradientFills.reserveColors(JSON.stringify(options.master));\n }\n\n const nodes = parseXml(xml);\n const positionedPages: PositionedNode[] = [];\n\n for (const node of nodes) {\n let map: YogaNodeMap | undefined;\n try {\n if (options?.autoFit !== false) {\n map = await autoFitSlide(node, slideSize, ctx);\n } else {\n map = await calcYogaLayout(node, slideSize, ctx);\n }\n const layoutMap = extractLayoutResults(map);\n const positioned = await toPositioned(node, ctx, layoutMap);\n positionedPages.push(positioned);\n } finally {\n if (map) freeYogaTree(map);\n }\n }\n\n // masterPptx から背景を抽出し、master オプションにマージ\n let master = options?.master;\n if (options?.masterPptx) {\n try {\n const bg = await parseMasterPptx(options.masterPptx);\n if (bg) {\n if (master) {\n // 明示的に background が指定されていない場合のみ、masterPptx の背景を使用\n if (!master.background) {\n master = { ...master, background: bg };\n }\n } else {\n master = { background: bg };\n }\n }\n } catch (e) {\n const message =\n e instanceof Error ? e.message : \"Unknown error parsing masterPptx\";\n ctx.diagnostics.add(\"MASTER_PPTX_PARSE_FAILED\", message);\n }\n }\n\n const pptx = await renderPptx(positionedPages, slideSize, ctx, master);\n\n // backgroundGradient 使用時は write/writeFile に gradFill 置換の後処理を仕込む\n patchPptxWriteForGradientFills(pptx, ctx.gradientFills);\n\n const diagnostics = ctx.diagnostics.items;\n\n if (options?.strict && diagnostics.length > 0) {\n throw new DiagnosticsError(diagnostics);\n }\n\n return { pptx, diagnostics };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"buildPptx.js","names":[],"sources":["../src/buildPptx.ts"],"sourcesContent":["import { autoFitSlide } from \"./autoFit/autoFit.ts\";\nimport { createBuildContext } from \"./buildContext.ts\";\nimport { calcYogaLayout } from \"./calcYogaLayout/calcYogaLayout.ts\";\nimport type { TextMeasurementMode } from \"./calcYogaLayout/measureText.ts\";\nimport type { YogaNodeMap } from \"./calcYogaLayout/types.ts\";\nimport { extractLayoutResults } from \"./calcYogaLayout/types.ts\";\nimport type { Diagnostic } from \"./diagnostics.ts\";\nimport { DiagnosticsError } from \"./diagnostics.ts\";\nimport { parseMasterPptx } from \"./parseMasterPptx.ts\";\nimport { parseXml } from \"./parseXml/parseXml.ts\";\nimport { patchPptxWriteForGradientFills } from \"./renderPptx/gradientFills.ts\";\nimport { renderPptx } from \"./renderPptx/renderPptx.ts\";\nimport { freeYogaTree } from \"./shared/freeYogaTree.ts\";\nimport { toPositioned } from \"./toPositioned/toPositioned.ts\";\nimport { PositionedNode, SlideMasterOptions } from \"./types.ts\";\nimport { validatePositioned } from \"./validatePositioned/validatePositioned.ts\";\n\nexport type { TextMeasurementMode };\n\nexport interface BuildPptxResult {\n pptx: import(\"pptxgenjs\").default;\n diagnostics: Diagnostic[];\n}\n\nexport async function buildPptx(\n xml: string,\n slideSize: { w: number; h: number },\n options?: {\n master?: SlideMasterOptions;\n masterPptx?: ArrayBuffer | Uint8Array;\n textMeasurement?: TextMeasurementMode;\n autoFit?: boolean;\n strict?: boolean;\n },\n): Promise<BuildPptxResult> {\n const ctx = createBuildContext(options?.textMeasurement ?? \"auto\");\n\n // グラデーション後処理のマーカー色がユーザー指定色と衝突しないよう、\n // 入力 XML / master オプション中に現れる色を予約しておく\n ctx.gradientFills.reserveColors(xml);\n if (options?.master) {\n ctx.gradientFills.reserveColors(JSON.stringify(options.master));\n }\n\n const nodes = parseXml(xml);\n const positionedPages: PositionedNode[] = [];\n\n for (const [slideIndex, node] of nodes.entries()) {\n let map: YogaNodeMap | undefined;\n try {\n if (options?.autoFit !== false) {\n map = await autoFitSlide(node, slideSize, ctx);\n } else {\n map = await calcYogaLayout(node, slideSize, ctx);\n }\n const layoutMap = extractLayoutResults(map);\n const positioned = await toPositioned(node, ctx, layoutMap);\n validatePositioned(positioned, slideSize, ctx, slideIndex);\n positionedPages.push(positioned);\n } finally {\n if (map) freeYogaTree(map);\n }\n }\n\n // masterPptx から背景を抽出し、master オプションにマージ\n let master = options?.master;\n if (options?.masterPptx) {\n try {\n const bg = await parseMasterPptx(options.masterPptx);\n if (bg) {\n if (master) {\n // 明示的に background が指定されていない場合のみ、masterPptx の背景を使用\n if (!master.background) {\n master = { ...master, background: bg };\n }\n } else {\n master = { background: bg };\n }\n }\n } catch (e) {\n const message =\n e instanceof Error ? e.message : \"Unknown error parsing masterPptx\";\n ctx.diagnostics.add(\"MASTER_PPTX_PARSE_FAILED\", message);\n }\n }\n\n const pptx = await renderPptx(positionedPages, slideSize, ctx, master);\n\n // backgroundGradient 使用時は write/writeFile に gradFill 置換の後処理を仕込む\n patchPptxWriteForGradientFills(pptx, ctx.gradientFills);\n\n const diagnostics = ctx.diagnostics.items;\n\n if (options?.strict && diagnostics.length > 0) {\n throw new DiagnosticsError(diagnostics);\n }\n\n return { pptx, diagnostics };\n}\n"],"mappings":";;;;;;;;;;;;;AAwBA,eAAsB,UACpB,KACA,WACA,SAO0B;CAC1B,MAAM,MAAM,mBAAmB,SAAS,mBAAmB,MAAM;CAIjE,IAAI,cAAc,cAAc,GAAG;CACnC,IAAI,SAAS,QACX,IAAI,cAAc,cAAc,KAAK,UAAU,QAAQ,MAAM,CAAC;CAGhE,MAAM,QAAQ,SAAS,GAAG;CAC1B,MAAM,kBAAoC,CAAC;CAE3C,KAAK,MAAM,CAAC,YAAY,SAAS,MAAM,QAAQ,GAAG;EAChD,IAAI;EACJ,IAAI;GACF,IAAI,SAAS,YAAY,OACvB,MAAM,MAAM,aAAa,MAAM,WAAW,GAAG;QAE7C,MAAM,MAAM,eAAe,MAAM,WAAW,GAAG;GAGjD,MAAM,aAAa,MAAM,aAAa,MAAM,KAD1B,qBAAqB,GACkB,CAAC;GAC1D,mBAAmB,YAAY,WAAW,KAAK,UAAU;GACzD,gBAAgB,KAAK,UAAU;EACjC,UAAU;GACR,IAAI,KAAK,aAAa,GAAG;EAC3B;CACF;CAGA,IAAI,SAAS,SAAS;CACtB,IAAI,SAAS,YACX,IAAI;EACF,MAAM,KAAK,MAAM,gBAAgB,QAAQ,UAAU;EACnD,IAAI,IACF,IAAI;OAEE,CAAC,OAAO,YACV,SAAS;IAAE,GAAG;IAAQ,YAAY;GAAG;EAAA,OAGvC,SAAS,EAAE,YAAY,GAAG;CAGhC,SAAS,GAAG;EACV,MAAM,UACJ,aAAa,QAAQ,EAAE,UAAU;EACnC,IAAI,YAAY,IAAI,4BAA4B,OAAO;CACzD;CAGF,MAAM,OAAO,MAAM,WAAW,iBAAiB,WAAW,KAAK,MAAM;CAGrE,+BAA+B,MAAM,IAAI,aAAa;CAEtD,MAAM,cAAc,IAAI,YAAY;CAEpC,IAAI,SAAS,UAAU,YAAY,SAAS,GAC1C,MAAM,IAAI,iBAAiB,WAAW;CAGxC,OAAO;EAAE;EAAM;CAAY;AAC7B"}
|