@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.
Files changed (124) hide show
  1. package/README.md +35 -23
  2. package/dist/autoFit/autoFit.js +1 -1
  3. package/dist/autoFit/autoFit.js.map +1 -1
  4. package/dist/autoFit/strategies/reduceFontSize.js +16 -14
  5. package/dist/autoFit/strategies/reduceFontSize.js.map +1 -1
  6. package/dist/autoFit/strategies/reduceGapAndPadding.js +13 -20
  7. package/dist/autoFit/strategies/reduceGapAndPadding.js.map +1 -1
  8. package/dist/autoFit/strategies/reduceTableRowHeight.js +8 -2
  9. package/dist/autoFit/strategies/reduceTableRowHeight.js.map +1 -1
  10. package/dist/autoFit/strategies/uniformScale.js +19 -20
  11. package/dist/autoFit/strategies/uniformScale.js.map +1 -1
  12. package/dist/autoFit/strategyResult.js +15 -0
  13. package/dist/autoFit/strategyResult.js.map +1 -0
  14. package/dist/buildPptx.d.ts.map +1 -1
  15. package/dist/buildPptx.js +4 -2
  16. package/dist/buildPptx.js.map +1 -1
  17. package/dist/calcYogaLayout/calcYogaLayout.js +16 -27
  18. package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
  19. package/dist/diagnostics.d.ts +1 -1
  20. package/dist/diagnostics.d.ts.map +1 -1
  21. package/dist/diagnostics.js.map +1 -1
  22. package/dist/parseXml/coercionRules.js +43 -8
  23. package/dist/parseXml/coercionRules.js.map +1 -1
  24. package/dist/parseXml/parseXml.d.ts +8 -3
  25. package/dist/parseXml/parseXml.d.ts.map +1 -1
  26. package/dist/parseXml/parseXml.js +192 -212
  27. package/dist/parseXml/parseXml.js.map +1 -1
  28. package/dist/parseXml/serializeXml.d.ts.map +1 -1
  29. package/dist/parseXml/serializeXml.js +12 -17
  30. package/dist/parseXml/serializeXml.js.map +1 -1
  31. package/dist/registry/definitions/arrow.js +2 -2
  32. package/dist/registry/definitions/arrow.js.map +1 -1
  33. package/dist/registry/definitions/chart.js +2 -2
  34. package/dist/registry/definitions/chart.js.map +1 -1
  35. package/dist/registry/definitions/compositeNodes.js +7 -12
  36. package/dist/registry/definitions/compositeNodes.js.map +1 -1
  37. package/dist/registry/definitions/icon.js +2 -2
  38. package/dist/registry/definitions/icon.js.map +1 -1
  39. package/dist/registry/definitions/image.js +2 -2
  40. package/dist/registry/definitions/image.js.map +1 -1
  41. package/dist/registry/definitions/layer.js +4 -5
  42. package/dist/registry/definitions/layer.js.map +1 -1
  43. package/dist/registry/definitions/line.js +2 -2
  44. package/dist/registry/definitions/line.js.map +1 -1
  45. package/dist/registry/definitions/list.js +3 -4
  46. package/dist/registry/definitions/list.js.map +1 -1
  47. package/dist/registry/definitions/shape.js +2 -2
  48. package/dist/registry/definitions/shape.js.map +1 -1
  49. package/dist/registry/definitions/stack.js +3 -4
  50. package/dist/registry/definitions/stack.js.map +1 -1
  51. package/dist/registry/definitions/svg.js +2 -2
  52. package/dist/registry/definitions/svg.js.map +1 -1
  53. package/dist/registry/definitions/table.js +2 -2
  54. package/dist/registry/definitions/table.js.map +1 -1
  55. package/dist/registry/definitions/text.js +2 -2
  56. package/dist/registry/definitions/text.js.map +1 -1
  57. package/dist/registry/index.js.map +1 -1
  58. package/dist/registry/nodeMetadata.js +208 -0
  59. package/dist/registry/nodeMetadata.js.map +1 -0
  60. package/dist/registry/nodeRegistry.js +3 -0
  61. package/dist/registry/nodeRegistry.js.map +1 -1
  62. package/dist/registry/xmlChildRules.js +55 -0
  63. package/dist/registry/xmlChildRules.js.map +1 -0
  64. package/dist/renderPptx/nodes/arrow.js +7 -28
  65. package/dist/renderPptx/nodes/arrow.js.map +1 -1
  66. package/dist/renderPptx/nodes/chart.js +2 -7
  67. package/dist/renderPptx/nodes/chart.js.map +1 -1
  68. package/dist/renderPptx/nodes/flow.js +6 -13
  69. package/dist/renderPptx/nodes/flow.js.map +1 -1
  70. package/dist/renderPptx/nodes/icon.js +4 -2
  71. package/dist/renderPptx/nodes/icon.js.map +1 -1
  72. package/dist/renderPptx/nodes/image.js +5 -13
  73. package/dist/renderPptx/nodes/image.js.map +1 -1
  74. package/dist/renderPptx/nodes/line.js +9 -33
  75. package/dist/renderPptx/nodes/line.js.map +1 -1
  76. package/dist/renderPptx/nodes/list.js +8 -20
  77. package/dist/renderPptx/nodes/list.js.map +1 -1
  78. package/dist/renderPptx/nodes/matrix.js +10 -11
  79. package/dist/renderPptx/nodes/matrix.js.map +1 -1
  80. package/dist/renderPptx/nodes/processArrow.js +9 -16
  81. package/dist/renderPptx/nodes/processArrow.js.map +1 -1
  82. package/dist/renderPptx/nodes/pyramid.js +5 -7
  83. package/dist/renderPptx/nodes/pyramid.js.map +1 -1
  84. package/dist/renderPptx/nodes/shape.js +7 -20
  85. package/dist/renderPptx/nodes/shape.js.map +1 -1
  86. package/dist/renderPptx/nodes/svg.js +2 -5
  87. package/dist/renderPptx/nodes/svg.js.map +1 -1
  88. package/dist/renderPptx/nodes/table.js +2 -5
  89. package/dist/renderPptx/nodes/table.js.map +1 -1
  90. package/dist/renderPptx/nodes/text.js +4 -1
  91. package/dist/renderPptx/nodes/text.js.map +1 -1
  92. package/dist/renderPptx/nodes/timeline.js +20 -22
  93. package/dist/renderPptx/nodes/timeline.js.map +1 -1
  94. package/dist/renderPptx/nodes/tree.js +5 -5
  95. package/dist/renderPptx/nodes/tree.js.map +1 -1
  96. package/dist/renderPptx/renderPptx.js +13 -29
  97. package/dist/renderPptx/renderPptx.js.map +1 -1
  98. package/dist/renderPptx/textOptions.js +32 -8
  99. package/dist/renderPptx/textOptions.js.map +1 -1
  100. package/dist/renderPptx/units.js +11 -1
  101. package/dist/renderPptx/units.js.map +1 -1
  102. package/dist/renderPptx/utils/backgroundBorder.js +103 -57
  103. package/dist/renderPptx/utils/backgroundBorder.js.map +1 -1
  104. package/dist/renderPptx/utils/contentArea.js +26 -9
  105. package/dist/renderPptx/utils/contentArea.js.map +1 -1
  106. package/dist/renderPptx/utils/scaleToFit.js +17 -1
  107. package/dist/renderPptx/utils/scaleToFit.js.map +1 -1
  108. package/dist/renderPptx/utils/straightLine.js +41 -0
  109. package/dist/renderPptx/utils/straightLine.js.map +1 -0
  110. package/dist/renderPptx/utils/visualStyle.js +113 -0
  111. package/dist/renderPptx/utils/visualStyle.js.map +1 -0
  112. package/dist/shared/boxSpacing.js +63 -0
  113. package/dist/shared/boxSpacing.js.map +1 -0
  114. package/dist/shared/walkTree.js +1 -7
  115. package/dist/shared/walkTree.js.map +1 -1
  116. package/dist/toPositioned/toPositioned.js +1 -1
  117. package/dist/toPositioned/toPositioned.js.map +1 -1
  118. package/dist/types.d.ts +1127 -95
  119. package/dist/types.d.ts.map +1 -1
  120. package/dist/types.js +47 -17
  121. package/dist/types.js.map +1 -1
  122. package/dist/validatePositioned/validatePositioned.js +92 -0
  123. package/dist/validatePositioned/validatePositioned.js.map +1 -0
  124. package/package.json +4 -3
@@ -1,3 +1,5 @@
1
+ import { resolveBoxSpacing } from "../../shared/boxSpacing.js";
2
+ import { rectPxToIn } from "../units.js";
1
3
  //#region src/renderPptx/utils/contentArea.ts
2
4
  /**
3
5
  * ノードの padding を考慮したコンテンツ描画領域を計算する。
@@ -11,14 +13,7 @@ function getContentArea(node) {
11
13
  w: node.w,
12
14
  h: node.h
13
15
  };
14
- let top, right, bottom, left;
15
- if (typeof node.padding === "number") top = right = bottom = left = node.padding;
16
- else {
17
- top = node.padding.top ?? 0;
18
- right = node.padding.right ?? 0;
19
- bottom = node.padding.bottom ?? 0;
20
- left = node.padding.left ?? 0;
21
- }
16
+ const { top, right, bottom, left } = resolveBoxSpacing(node.padding);
22
17
  return {
23
18
  x: node.x + left,
24
19
  y: node.y + top,
@@ -26,7 +21,29 @@ function getContentArea(node) {
26
21
  h: Math.max(0, node.h - top - bottom)
27
22
  };
28
23
  }
24
+ /**
25
+ * コンテンツ描画領域を pptxgenjs の位置オプション (inch 単位の x/y/w/h)
26
+ * として返す。コンテンツを領域いっぱいに描画する renderer はこれを
27
+ * addShape / addText 等のオプションへ spread するだけでよい。
28
+ */
29
+ function getContentAreaIn(node) {
30
+ return rectPxToIn(getContentArea(node));
31
+ }
32
+ /**
33
+ * ノードの x/y/w/h を指定領域 (通常はコンテンツ領域) で置き換えた
34
+ * 仮想ノードを返す。padding を解決済みの領域を基準に下位の描画関数へ
35
+ * ノードを渡すために使う。
36
+ */
37
+ function withContentBounds(node, bounds) {
38
+ return {
39
+ ...node,
40
+ x: bounds.x,
41
+ y: bounds.y,
42
+ w: bounds.w,
43
+ h: bounds.h
44
+ };
45
+ }
29
46
  //#endregion
30
- export { getContentArea };
47
+ export { getContentArea, getContentAreaIn, withContentBounds };
31
48
 
32
49
  //# sourceMappingURL=contentArea.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"contentArea.js","names":[],"sources":["../../../src/renderPptx/utils/contentArea.ts"],"sourcesContent":["type Padding =\n | number\n | {\n top?: number;\n right?: number;\n bottom?: number;\n left?: number;\n };\n\ninterface ContentArea {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * ノードの padding を考慮したコンテンツ描画領域を計算する。\n * background/border はノード全体の領域 (node.x/y/w/h) に描画し、\n * コンテンツはこの関数で返される領域に描画する。\n */\nexport function getContentArea(node: {\n x: number;\n y: number;\n w: number;\n h: number;\n padding?: Padding;\n}): ContentArea {\n if (node.padding === undefined) {\n return { x: node.x, y: node.y, w: node.w, h: node.h };\n }\n\n let top: number, right: number, bottom: number, left: number;\n\n if (typeof node.padding === \"number\") {\n top = right = bottom = left = node.padding;\n } else {\n top = node.padding.top ?? 0;\n right = node.padding.right ?? 0;\n bottom = node.padding.bottom ?? 0;\n left = node.padding.left ?? 0;\n }\n\n return {\n x: node.x + left,\n y: node.y + top,\n w: Math.max(0, node.w - left - right),\n h: Math.max(0, node.h - top - bottom),\n };\n}\n"],"mappings":";;;;;;AAqBA,SAAgB,eAAe,MAMf;CACd,IAAI,KAAK,YAAY,KAAA,GACnB,OAAO;EAAE,GAAG,KAAK;EAAG,GAAG,KAAK;EAAG,GAAG,KAAK;EAAG,GAAG,KAAK;CAAE;CAGtD,IAAI,KAAa,OAAe,QAAgB;CAEhD,IAAI,OAAO,KAAK,YAAY,UAC1B,MAAM,QAAQ,SAAS,OAAO,KAAK;MAC9B;EACL,MAAM,KAAK,QAAQ,OAAO;EAC1B,QAAQ,KAAK,QAAQ,SAAS;EAC9B,SAAS,KAAK,QAAQ,UAAU;EAChC,OAAO,KAAK,QAAQ,QAAQ;CAC9B;CAEA,OAAO;EACL,GAAG,KAAK,IAAI;EACZ,GAAG,KAAK,IAAI;EACZ,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK;EACpC,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,MAAM;CACtC;AACF"}
1
+ {"version":3,"file":"contentArea.js","names":[],"sources":["../../../src/renderPptx/utils/contentArea.ts"],"sourcesContent":["import {\n resolveBoxSpacing,\n type BoxSpacingInput,\n} from \"../../shared/boxSpacing.ts\";\nimport { rectPxToIn } from \"../units.ts\";\n\ninterface ContentArea {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\n/**\n * ノードの padding を考慮したコンテンツ描画領域を計算する。\n * background/border はノード全体の領域 (node.x/y/w/h) に描画し、\n * コンテンツはこの関数で返される領域に描画する。\n */\nexport function getContentArea(node: {\n x: number;\n y: number;\n w: number;\n h: number;\n padding?: BoxSpacingInput;\n}): ContentArea {\n if (node.padding === undefined) {\n return { x: node.x, y: node.y, w: node.w, h: node.h };\n }\n\n const { top, right, bottom, left } = resolveBoxSpacing(node.padding);\n\n return {\n x: node.x + left,\n y: node.y + top,\n w: Math.max(0, node.w - left - right),\n h: Math.max(0, node.h - top - bottom),\n };\n}\n\n/**\n * コンテンツ描画領域を pptxgenjs の位置オプション (inch 単位の x/y/w/h)\n * として返す。コンテンツを領域いっぱいに描画する renderer はこれを\n * addShape / addText 等のオプションへ spread するだけでよい。\n */\nexport function getContentAreaIn(\n node: Parameters<typeof getContentArea>[0],\n): ReturnType<typeof rectPxToIn> {\n return rectPxToIn(getContentArea(node));\n}\n\n/**\n * ノードの x/y/w/h を指定領域 (通常はコンテンツ領域) で置き換えた\n * 仮想ノードを返す。padding を解決済みの領域を基準に下位の描画関数へ\n * ノードを渡すために使う。\n */\nexport function withContentBounds<\n T extends { x: number; y: number; w: number; h: number },\n>(node: T, bounds: ContentArea): T {\n return { ...node, x: bounds.x, y: bounds.y, w: bounds.w, h: bounds.h };\n}\n"],"mappings":";;;;;;;;AAkBA,SAAgB,eAAe,MAMf;CACd,IAAI,KAAK,YAAY,KAAA,GACnB,OAAO;EAAE,GAAG,KAAK;EAAG,GAAG,KAAK;EAAG,GAAG,KAAK;EAAG,GAAG,KAAK;CAAE;CAGtD,MAAM,EAAE,KAAK,OAAO,QAAQ,SAAS,kBAAkB,KAAK,OAAO;CAEnE,OAAO;EACL,GAAG,KAAK,IAAI;EACZ,GAAG,KAAK,IAAI;EACZ,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,OAAO,KAAK;EACpC,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,MAAM,MAAM;CACtC;AACF;;;;;;AAOA,SAAgB,iBACd,MAC+B;CAC/B,OAAO,WAAW,eAAe,IAAI,CAAC;AACxC;;;;;;AAOA,SAAgB,kBAEd,MAAS,QAAwB;CACjC,OAAO;EAAE,GAAG;EAAM,GAAG,OAAO;EAAG,GAAG,OAAO;EAAG,GAAG,OAAO;EAAG,GAAG,OAAO;CAAE;AACvE"}
@@ -1,3 +1,4 @@
1
+ import { getContentArea } from "./contentArea.js";
1
2
  //#region src/renderPptx/utils/scaleToFit.ts
2
3
  const MIN_SCALE_THRESHOLD = .5;
3
4
  /**
@@ -17,7 +18,22 @@ function calcScaleFactor(allocatedW, allocatedH, intrinsicW, intrinsicH, nodeTyp
17
18
  }
18
19
  return scaleFactor;
19
20
  }
21
+ /**
22
+ * scaleToFit 系 diagram renderer (timeline / matrix / flow / processArrow /
23
+ * pyramid / tree) の共通前処理。padding を除いたコンテンツ領域と、
24
+ * 固有サイズに対するスケール係数をまとめて解決する。
25
+ *
26
+ * diagnostics のラベルには node.type を使うため、renderer ごとに
27
+ * ノードタイプ文字列を手書きする必要がない。
28
+ */
29
+ function resolveScaledContentArea(node, intrinsic, ctx) {
30
+ const content = getContentArea(node);
31
+ return {
32
+ content,
33
+ scaleFactor: calcScaleFactor(content.w, content.h, intrinsic.width, intrinsic.height, node.type, ctx.buildContext.diagnostics)
34
+ };
35
+ }
20
36
  //#endregion
21
- export { calcScaleFactor };
37
+ export { resolveScaledContentArea };
22
38
 
23
39
  //# sourceMappingURL=scaleToFit.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scaleToFit.js","names":[],"sources":["../../../src/renderPptx/utils/scaleToFit.ts"],"sourcesContent":["import type { DiagnosticCollector } from \"../../diagnostics.ts\";\n\nconst MIN_SCALE_THRESHOLD = 0.5;\n\n/**\n * 割り当てサイズと固有サイズからスケール係数を計算する。\n *\n * - scaleFactor = min(allocatedW / intrinsicW, allocatedH / intrinsicH, 1.0)\n * - scaleFactor < MIN_SCALE_THRESHOLD の場合、閾値でクランプして diagnostics に記録\n */\nexport function calcScaleFactor(\n allocatedW: number,\n allocatedH: number,\n intrinsicW: number,\n intrinsicH: number,\n nodeType: string,\n diagnostics: DiagnosticCollector,\n): number {\n if (intrinsicW <= 0 || intrinsicH <= 0) return 1.0;\n\n const scaleX = allocatedW / intrinsicW;\n const scaleY = allocatedH / intrinsicH;\n let scaleFactor = Math.min(scaleX, scaleY, 1.0);\n\n if (scaleFactor < MIN_SCALE_THRESHOLD) {\n diagnostics.add(\n \"SCALE_BELOW_THRESHOLD\",\n `${nodeType} node: scale factor ${scaleFactor.toFixed(2)} is below threshold ${MIN_SCALE_THRESHOLD}. Content may overflow.`,\n );\n scaleFactor = MIN_SCALE_THRESHOLD;\n }\n\n return scaleFactor;\n}\n"],"mappings":";AAEA,MAAM,sBAAsB;;;;;;;AAQ5B,SAAgB,gBACd,YACA,YACA,YACA,YACA,UACA,aACQ;CACR,IAAI,cAAc,KAAK,cAAc,GAAG,OAAO;CAE/C,MAAM,SAAS,aAAa;CAC5B,MAAM,SAAS,aAAa;CAC5B,IAAI,cAAc,KAAK,IAAI,QAAQ,QAAQ,CAAG;CAE9C,IAAI,cAAc,qBAAqB;EACrC,YAAY,IACV,yBACA,GAAG,SAAS,sBAAsB,YAAY,QAAQ,CAAC,EAAE,sBAAsB,oBAAoB,wBACrG;EACA,cAAc;CAChB;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"scaleToFit.js","names":[],"sources":["../../../src/renderPptx/utils/scaleToFit.ts"],"sourcesContent":["import type { DiagnosticCollector } from \"../../diagnostics.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { getContentArea } from \"./contentArea.ts\";\n\nconst MIN_SCALE_THRESHOLD = 0.5;\n\n/**\n * 割り当てサイズと固有サイズからスケール係数を計算する。\n *\n * - scaleFactor = min(allocatedW / intrinsicW, allocatedH / intrinsicH, 1.0)\n * - scaleFactor < MIN_SCALE_THRESHOLD の場合、閾値でクランプして diagnostics に記録\n */\nexport function calcScaleFactor(\n allocatedW: number,\n allocatedH: number,\n intrinsicW: number,\n intrinsicH: number,\n nodeType: string,\n diagnostics: DiagnosticCollector,\n): number {\n if (intrinsicW <= 0 || intrinsicH <= 0) return 1.0;\n\n const scaleX = allocatedW / intrinsicW;\n const scaleY = allocatedH / intrinsicH;\n let scaleFactor = Math.min(scaleX, scaleY, 1.0);\n\n if (scaleFactor < MIN_SCALE_THRESHOLD) {\n diagnostics.add(\n \"SCALE_BELOW_THRESHOLD\",\n `${nodeType} node: scale factor ${scaleFactor.toFixed(2)} is below threshold ${MIN_SCALE_THRESHOLD}. Content may overflow.`,\n );\n scaleFactor = MIN_SCALE_THRESHOLD;\n }\n\n return scaleFactor;\n}\n\n/**\n * scaleToFit 系 diagram renderer (timeline / matrix / flow / processArrow /\n * pyramid / tree) の共通前処理。padding を除いたコンテンツ領域と、\n * 固有サイズに対するスケール係数をまとめて解決する。\n *\n * diagnostics のラベルには node.type を使うため、renderer ごとに\n * ノードタイプ文字列を手書きする必要がない。\n */\nexport function resolveScaledContentArea(\n node: Parameters<typeof getContentArea>[0] & { type: string },\n intrinsic: { width: number; height: number },\n ctx: RenderContext,\n): { content: ReturnType<typeof getContentArea>; scaleFactor: number } {\n const content = getContentArea(node);\n const scaleFactor = calcScaleFactor(\n content.w,\n content.h,\n intrinsic.width,\n intrinsic.height,\n node.type,\n ctx.buildContext.diagnostics,\n );\n return { content, scaleFactor };\n}\n"],"mappings":";;AAIA,MAAM,sBAAsB;;;;;;;AAQ5B,SAAgB,gBACd,YACA,YACA,YACA,YACA,UACA,aACQ;CACR,IAAI,cAAc,KAAK,cAAc,GAAG,OAAO;CAE/C,MAAM,SAAS,aAAa;CAC5B,MAAM,SAAS,aAAa;CAC5B,IAAI,cAAc,KAAK,IAAI,QAAQ,QAAQ,CAAG;CAE9C,IAAI,cAAc,qBAAqB;EACrC,YAAY,IACV,yBACA,GAAG,SAAS,sBAAsB,YAAY,QAAQ,CAAC,EAAE,sBAAsB,oBAAoB,wBACrG;EACA,cAAc;CAChB;CAEA,OAAO;AACT;;;;;;;;;AAUA,SAAgB,yBACd,MACA,WACA,KACqE;CACrE,MAAM,UAAU,eAAe,IAAI;CASnC,OAAO;EAAE;EAAS,aARE,gBAClB,QAAQ,GACR,QAAQ,GACR,UAAU,OACV,UAAU,QACV,KAAK,MACL,IAAI,aAAa,WAES;CAAE;AAChC"}
@@ -0,0 +1,41 @@
1
+ import { pxToIn, pxToPt } from "../units.js";
2
+ //#region src/renderPptx/utils/straightLine.ts
3
+ /**
4
+ * boolean | LineArrowOptions から pptxgenjs の arrow type を取得
5
+ */
6
+ function resolveArrowType(arrow) {
7
+ if (arrow === void 0) return;
8
+ if (arrow === false) return "none";
9
+ if (arrow === true) return "triangle";
10
+ return arrow.type ?? "triangle";
11
+ }
12
+ /**
13
+ * 始点 (x1, y1) から終点 (x2, y2) への直線を描画する
14
+ */
15
+ function addStraightLine(ctx, { x1, y1, x2, y2 }, { color, lineWidth, dashType, beginArrow, endArrow }) {
16
+ const minX = Math.min(x1, x2);
17
+ const minY = Math.min(y1, y2);
18
+ const lineW = Math.abs(x2 - x1);
19
+ const lineH = Math.abs(y2 - y1);
20
+ const flipH = x2 < x1;
21
+ const flipV = y2 < y1;
22
+ ctx.slide.addShape(ctx.pptx.ShapeType.line, {
23
+ x: pxToIn(minX),
24
+ y: pxToIn(minY),
25
+ w: pxToIn(lineW),
26
+ h: pxToIn(lineH),
27
+ flipH,
28
+ flipV,
29
+ line: {
30
+ color: color ?? "000000",
31
+ width: lineWidth !== void 0 ? pxToPt(lineWidth) : 1,
32
+ dashType,
33
+ beginArrowType: resolveArrowType(beginArrow),
34
+ endArrowType: resolveArrowType(endArrow)
35
+ }
36
+ });
37
+ }
38
+ //#endregion
39
+ export { addStraightLine };
40
+
41
+ //# sourceMappingURL=straightLine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"straightLine.js","names":[],"sources":["../../../src/renderPptx/utils/straightLine.ts"],"sourcesContent":["/**\n * 2 点間の直線を pptxgenjs の line shape に変換する共通描画処理。\n *\n * pptxgenjs の line shape は左上座標 (x, y) + サイズ (w, h) で表現され、\n * 線の向き (始点→終点) は flipH / flipV で表すため、端点座標からの\n * 変換ロジックを Line / Arrow ノードで共有する。\n */\nimport type { LineArrow, LineNode } from \"../../types.ts\";\nimport type { RenderContext } from \"../types.ts\";\nimport { pxToIn, pxToPt } from \"../units.ts\";\n\n/**\n * boolean | LineArrowOptions から pptxgenjs の arrow type を取得\n */\nexport function resolveArrowType(\n arrow: LineArrow | undefined,\n): \"none\" | \"arrow\" | \"diamond\" | \"oval\" | \"stealth\" | \"triangle\" | undefined {\n if (arrow === undefined) {\n return undefined;\n }\n if (arrow === false) {\n return \"none\";\n }\n if (arrow === true) {\n return \"triangle\"; // デフォルト\n }\n return arrow.type ?? \"triangle\";\n}\n\ntype StraightLinePoints = { x1: number; y1: number; x2: number; y2: number };\n\ntype StraightLineStyle = Pick<\n LineNode,\n \"color\" | \"lineWidth\" | \"dashType\" | \"beginArrow\" | \"endArrow\"\n>;\n\n/**\n * 始点 (x1, y1) から終点 (x2, y2) への直線を描画する\n */\nexport function addStraightLine(\n ctx: RenderContext,\n { x1, y1, x2, y2 }: StraightLinePoints,\n { color, lineWidth, dashType, beginArrow, endArrow }: StraightLineStyle,\n): void {\n const minX = Math.min(x1, x2);\n const minY = Math.min(y1, y2);\n const lineW = Math.abs(x2 - x1);\n const lineH = Math.abs(y2 - y1);\n\n // 線の方向を判定して flip を決定\n // flipH: 右から左へ向かう線\n // flipV: 下から上へ向かう線\n const flipH = x2 < x1;\n const flipV = y2 < y1;\n\n ctx.slide.addShape(ctx.pptx.ShapeType.line, {\n x: pxToIn(minX),\n y: pxToIn(minY),\n w: pxToIn(lineW),\n h: pxToIn(lineH),\n flipH,\n flipV,\n line: {\n color: color ?? \"000000\",\n width: lineWidth !== undefined ? pxToPt(lineWidth) : 1,\n dashType,\n beginArrowType: resolveArrowType(beginArrow),\n endArrowType: resolveArrowType(endArrow),\n },\n });\n}\n"],"mappings":";;;;;AAcA,SAAgB,iBACd,OAC4E;CAC5E,IAAI,UAAU,KAAA,GACZ;CAEF,IAAI,UAAU,OACZ,OAAO;CAET,IAAI,UAAU,MACZ,OAAO;CAET,OAAO,MAAM,QAAQ;AACvB;;;;AAYA,SAAgB,gBACd,KACA,EAAE,IAAI,IAAI,IAAI,MACd,EAAE,OAAO,WAAW,UAAU,YAAY,YACpC;CACN,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,OAAO,KAAK,IAAI,IAAI,EAAE;CAC5B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAC9B,MAAM,QAAQ,KAAK,IAAI,KAAK,EAAE;CAK9B,MAAM,QAAQ,KAAK;CACnB,MAAM,QAAQ,KAAK;CAEnB,IAAI,MAAM,SAAS,IAAI,KAAK,UAAU,MAAM;EAC1C,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,IAAI;EACd,GAAG,OAAO,KAAK;EACf,GAAG,OAAO,KAAK;EACf;EACA;EACA,MAAM;GACJ,OAAO,SAAS;GAChB,OAAO,cAAc,KAAA,IAAY,OAAO,SAAS,IAAI;GACrD;GACA,gBAAgB,iBAAiB,UAAU;GAC3C,cAAc,iBAAiB,QAAQ;EACzC;CACF,CAAC;AACH"}
@@ -0,0 +1,113 @@
1
+ import { pxToPt } from "../units.js";
2
+ //#region src/renderPptx/utils/visualStyle.ts
3
+ /**
4
+ * 色文字列から "#" を 1 つ取り除き、pptxgenjs が受け付ける HEX 文字列にする。
5
+ * undefined はそのまま返すため `stripHash(color) ?? fallback` の形で使える。
6
+ */
7
+ function stripHash(color) {
8
+ return color?.replace("#", "");
9
+ }
10
+ /**
11
+ * ShadowStyle を pptxgenjs の shadow オプションに変換する
12
+ * type 未指定時は outer をデフォルトとする
13
+ */
14
+ function convertShadow(shadow) {
15
+ if (!shadow) return void 0;
16
+ return {
17
+ type: shadow.type ?? "outer",
18
+ opacity: shadow.opacity,
19
+ blur: shadow.blur,
20
+ angle: shadow.angle,
21
+ offset: shadow.offset,
22
+ color: shadow.color
23
+ };
24
+ }
25
+ /**
26
+ * border が描画対象となる指定 (color / width / dashType のいずれか) を
27
+ * 持つかを判定する
28
+ */
29
+ function hasVisibleBorder(border) {
30
+ return Boolean(border && (border.color !== void 0 || border.width !== void 0 || border.dashType !== void 0));
31
+ }
32
+ const BORDER_SIDES = [
33
+ "top",
34
+ "right",
35
+ "bottom",
36
+ "left"
37
+ ];
38
+ /**
39
+ * 4 辺一律の border と辺ごとの borderTop / borderRight / borderBottom /
40
+ * borderLeft をマージし、描画対象となる辺ごとの BorderStyle を返す。
41
+ *
42
+ * - 辺ごとの指定が 1 つも無い場合は undefined を返し、呼び出し側は
43
+ * 従来の 4 辺一律描画 (shape の line オプション) にフォールバックする
44
+ * - 辺ごとの指定がある場合、各辺は border をベースに辺ごとの指定で
45
+ * フィールド単位に上書きした BorderStyle になる (辺ごとの指定が優先)
46
+ * - マージ結果が描画対象とならない辺 (指定なし) は結果に含まれない
47
+ */
48
+ function resolvePerSideBorders(style) {
49
+ const overrides = {
50
+ top: style.borderTop,
51
+ right: style.borderRight,
52
+ bottom: style.borderBottom,
53
+ left: style.borderLeft
54
+ };
55
+ if (!Object.values(overrides).some(hasVisibleBorder)) return void 0;
56
+ const result = {};
57
+ for (const side of BORDER_SIDES) {
58
+ const merged = {
59
+ ...style.border,
60
+ ...overrides[side]
61
+ };
62
+ if (hasVisibleBorder(merged)) result[side] = merged;
63
+ }
64
+ return result;
65
+ }
66
+ /**
67
+ * BorderStyle を pptxgenjs の line オプションに変換する
68
+ * width はユーザー入力 px、pptxgenjs の line.width は pt
69
+ *
70
+ * @param fallbackColor color 未指定時に使う色。省略時は color を
71
+ * undefined のまま渡し pptxgenjs のデフォルトに任せる
72
+ */
73
+ function convertBorderLine(border, fallbackColor) {
74
+ return {
75
+ color: border.color ?? fallbackColor,
76
+ width: border.width !== void 0 ? pxToPt(border.width) : void 0,
77
+ dashType: border.dashType
78
+ };
79
+ }
80
+ /**
81
+ * ノードの opacity (0-1、1 = 不透明) を pptxgenjs の
82
+ * transparency (0-100、100 = 透明) に変換する
83
+ */
84
+ function opacityToTransparency(opacity) {
85
+ return opacity !== void 0 ? (1 - opacity) * 100 : void 0;
86
+ }
87
+ /**
88
+ * backgroundColor / opacity / グラデーションマーカー色から
89
+ * pptxgenjs の fill オプションを解決する
90
+ *
91
+ * gradientMarker がある場合はマーカー色の単色塗りとして描画し、
92
+ * 出力時の後処理で gradFill に置換される (gradientFills.ts 参照)。
93
+ * opacity はマーカー側ではなく gradFill のカラーストップの alpha で
94
+ * 表現するため、マーカー fill には transparency を付与しない。
95
+ */
96
+ function resolveBackgroundFill(backgroundColor, opacity, gradientMarker) {
97
+ if (gradientMarker) return { color: gradientMarker };
98
+ return {
99
+ color: backgroundColor,
100
+ transparency: opacityToTransparency(opacity)
101
+ };
102
+ }
103
+ /**
104
+ * borderRadius (px) をノードサイズに対する 0-1 の正規化値
105
+ * (pptxgenjs roundRect の rectRadius) に変換する
106
+ */
107
+ function resolveRectRadius(borderRadius, w, h) {
108
+ return borderRadius ? Math.min(borderRadius / Math.min(w, h) * 2, 1) : void 0;
109
+ }
110
+ //#endregion
111
+ export { BORDER_SIDES, convertBorderLine, convertShadow, hasVisibleBorder, resolveBackgroundFill, resolvePerSideBorders, resolveRectRadius, stripHash };
112
+
113
+ //# sourceMappingURL=visualStyle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visualStyle.js","names":[],"sources":["../../../src/renderPptx/utils/visualStyle.ts"],"sourcesContent":["/**\n * 見た目属性 (fill / border / shadow / opacity / borderRadius) を\n * pptxgenjs のオプションへ変換する共通 resolver 群。\n *\n * ノードごとに変換ロジックが重複・乖離すると、XML 上は同じ指定でも\n * 描画結果が異なるリスクがあるため、属性値 → pptxgenjs オプションの\n * 純粋変換をここに集約する。\n *\n * 共通化対象の属性カテゴリ:\n * - fill (背景色 + opacity): resolveBackgroundFill / opacityToTransparency\n * - border / line (枠線): hasVisibleBorder / convertBorderLine\n * - shadow (影): convertShadow\n * - borderRadius (角丸): resolveRectRadius\n *\n * 既存 helper との責務境界:\n * - gradientFills.ts: backgroundGradient のマーカー登録と出力時の gradFill 置換。\n * グラデーションはマーカー色 1 色の単色塗りに帰着するため本モジュールでは\n * 解釈せず、マーカー色を resolveBackgroundFill で単色 fill として扱う。\n * - utils/backgroundBorder.ts: 背景色 → 背景画像 → ボーダーの描画順序の\n * オーケストレーション。個々の属性値の変換は本モジュールに委譲する。\n * - textOptions.ts: テキスト系属性 (font / underline / strike など) の変換。\n */\nimport type { BorderStyle, ShadowStyle } from \"../../types.ts\";\nimport { pxToPt } from \"../units.ts\";\n\n/**\n * 色文字列から \"#\" を 1 つ取り除き、pptxgenjs が受け付ける HEX 文字列にする。\n * undefined はそのまま返すため `stripHash(color) ?? fallback` の形で使える。\n */\nexport function stripHash(color: string | undefined): string | undefined {\n return color?.replace(\"#\", \"\");\n}\n\n/**\n * ShadowStyle を pptxgenjs の shadow オプションに変換する\n * type 未指定時は outer をデフォルトとする\n */\nexport function convertShadow(shadow: ShadowStyle | undefined):\n | {\n type: \"outer\" | \"inner\";\n opacity?: number;\n blur?: number;\n angle?: number;\n offset?: number;\n color?: string;\n }\n | undefined {\n if (!shadow) return undefined;\n return {\n type: shadow.type ?? \"outer\",\n opacity: shadow.opacity,\n blur: shadow.blur,\n angle: shadow.angle,\n offset: shadow.offset,\n color: shadow.color,\n };\n}\n\n/**\n * border が描画対象となる指定 (color / width / dashType のいずれか) を\n * 持つかを判定する\n */\nexport function hasVisibleBorder(\n border: BorderStyle | undefined,\n): border is BorderStyle {\n return Boolean(\n border &&\n (border.color !== undefined ||\n border.width !== undefined ||\n border.dashType !== undefined),\n );\n}\n\nexport const BORDER_SIDES = [\"top\", \"right\", \"bottom\", \"left\"] as const;\nexport type BorderSide = (typeof BORDER_SIDES)[number];\n\nexport type PerSideBorders = Partial<Record<BorderSide, BorderStyle>>;\n\n/**\n * 4 辺一律の border と辺ごとの borderTop / borderRight / borderBottom /\n * borderLeft をマージし、描画対象となる辺ごとの BorderStyle を返す。\n *\n * - 辺ごとの指定が 1 つも無い場合は undefined を返し、呼び出し側は\n * 従来の 4 辺一律描画 (shape の line オプション) にフォールバックする\n * - 辺ごとの指定がある場合、各辺は border をベースに辺ごとの指定で\n * フィールド単位に上書きした BorderStyle になる (辺ごとの指定が優先)\n * - マージ結果が描画対象とならない辺 (指定なし) は結果に含まれない\n */\nexport function resolvePerSideBorders(style: {\n border?: BorderStyle;\n borderTop?: BorderStyle;\n borderRight?: BorderStyle;\n borderBottom?: BorderStyle;\n borderLeft?: BorderStyle;\n}): PerSideBorders | undefined {\n const overrides: Partial<Record<BorderSide, BorderStyle | undefined>> = {\n top: style.borderTop,\n right: style.borderRight,\n bottom: style.borderBottom,\n left: style.borderLeft,\n };\n\n const hasPerSideOverride = Object.values(overrides).some(hasVisibleBorder);\n if (!hasPerSideOverride) return undefined;\n\n const result: PerSideBorders = {};\n for (const side of BORDER_SIDES) {\n const merged = { ...style.border, ...overrides[side] };\n if (hasVisibleBorder(merged)) {\n result[side] = merged;\n }\n }\n return result;\n}\n\n/**\n * BorderStyle を pptxgenjs の line オプションに変換する\n * width はユーザー入力 px、pptxgenjs の line.width は pt\n *\n * @param fallbackColor color 未指定時に使う色。省略時は color を\n * undefined のまま渡し pptxgenjs のデフォルトに任せる\n */\nexport function convertBorderLine(\n border: BorderStyle,\n fallbackColor?: string,\n): { color?: string; width?: number; dashType?: BorderStyle[\"dashType\"] } {\n return {\n color: border.color ?? fallbackColor,\n width: border.width !== undefined ? pxToPt(border.width) : undefined,\n dashType: border.dashType,\n };\n}\n\n/**\n * ノードの opacity (0-1、1 = 不透明) を pptxgenjs の\n * transparency (0-100、100 = 透明) に変換する\n */\nexport function opacityToTransparency(\n opacity: number | undefined,\n): number | undefined {\n return opacity !== undefined ? (1 - opacity) * 100 : undefined;\n}\n\n/**\n * backgroundColor / opacity / グラデーションマーカー色から\n * pptxgenjs の fill オプションを解決する\n *\n * gradientMarker がある場合はマーカー色の単色塗りとして描画し、\n * 出力時の後処理で gradFill に置換される (gradientFills.ts 参照)。\n * opacity はマーカー側ではなく gradFill のカラーストップの alpha で\n * 表現するため、マーカー fill には transparency を付与しない。\n */\nexport function resolveBackgroundFill(\n backgroundColor: string | undefined,\n opacity: number | undefined,\n gradientMarker: string | undefined,\n): { color?: string; transparency?: number } {\n if (gradientMarker) return { color: gradientMarker };\n return {\n color: backgroundColor,\n transparency: opacityToTransparency(opacity),\n };\n}\n\n/**\n * borderRadius (px) をノードサイズに対する 0-1 の正規化値\n * (pptxgenjs roundRect の rectRadius) に変換する\n */\nexport function resolveRectRadius(\n borderRadius: number | undefined,\n w: number,\n h: number,\n): number | undefined {\n return borderRadius\n ? Math.min((borderRadius / Math.min(w, h)) * 2, 1)\n : undefined;\n}\n"],"mappings":";;;;;;AA6BA,SAAgB,UAAU,OAA+C;CACvE,OAAO,OAAO,QAAQ,KAAK,EAAE;AAC/B;;;;;AAMA,SAAgB,cAAc,QAShB;CACZ,IAAI,CAAC,QAAQ,OAAO,KAAA;CACpB,OAAO;EACL,MAAM,OAAO,QAAQ;EACrB,SAAS,OAAO;EAChB,MAAM,OAAO;EACb,OAAO,OAAO;EACd,QAAQ,OAAO;EACf,OAAO,OAAO;CAChB;AACF;;;;;AAMA,SAAgB,iBACd,QACuB;CACvB,OAAO,QACL,WACC,OAAO,UAAU,KAAA,KAChB,OAAO,UAAU,KAAA,KACjB,OAAO,aAAa,KAAA,EACxB;AACF;AAEA,MAAa,eAAe;CAAC;CAAO;CAAS;CAAU;AAAM;;;;;;;;;;;AAe7D,SAAgB,sBAAsB,OAMP;CAC7B,MAAM,YAAkE;EACtE,KAAK,MAAM;EACX,OAAO,MAAM;EACb,QAAQ,MAAM;EACd,MAAM,MAAM;CACd;CAGA,IAAI,CADuB,OAAO,OAAO,SAAS,CAAC,CAAC,KAAK,gBACnC,GAAG,OAAO,KAAA;CAEhC,MAAM,SAAyB,CAAC;CAChC,KAAK,MAAM,QAAQ,cAAc;EAC/B,MAAM,SAAS;GAAE,GAAG,MAAM;GAAQ,GAAG,UAAU;EAAM;EACrD,IAAI,iBAAiB,MAAM,GACzB,OAAO,QAAQ;CAEnB;CACA,OAAO;AACT;;;;;;;;AASA,SAAgB,kBACd,QACA,eACwE;CACxE,OAAO;EACL,OAAO,OAAO,SAAS;EACvB,OAAO,OAAO,UAAU,KAAA,IAAY,OAAO,OAAO,KAAK,IAAI,KAAA;EAC3D,UAAU,OAAO;CACnB;AACF;;;;;AAMA,SAAgB,sBACd,SACoB;CACpB,OAAO,YAAY,KAAA,KAAa,IAAI,WAAW,MAAM,KAAA;AACvD;;;;;;;;;;AAWA,SAAgB,sBACd,iBACA,SACA,gBAC2C;CAC3C,IAAI,gBAAgB,OAAO,EAAE,OAAO,eAAe;CACnD,OAAO;EACL,OAAO;EACP,cAAc,sBAAsB,OAAO;CAC7C;AACF;;;;;AAMA,SAAgB,kBACd,cACA,GACA,GACoB;CACpB,OAAO,eACH,KAAK,IAAK,eAAe,KAAK,IAAI,GAAG,CAAC,IAAK,GAAG,CAAC,IAC/C,KAAA;AACN"}
@@ -0,0 +1,63 @@
1
+ //#region src/shared/boxSpacing.ts
2
+ const EDGES = [
3
+ "top",
4
+ "right",
5
+ "bottom",
6
+ "left"
7
+ ];
8
+ /**
9
+ * box spacing 値を解決済みの per-edge 値に正規化する。
10
+ * number は 4 辺すべて、object は未指定 edge を 0 として解決する。
11
+ */
12
+ function resolveBoxSpacing(value) {
13
+ if (value === void 0) return {
14
+ top: 0,
15
+ right: 0,
16
+ bottom: 0,
17
+ left: 0
18
+ };
19
+ if (typeof value === "number") return {
20
+ top: value,
21
+ right: value,
22
+ bottom: value,
23
+ left: value
24
+ };
25
+ return {
26
+ top: value.top ?? 0,
27
+ right: value.right ?? 0,
28
+ bottom: value.bottom ?? 0,
29
+ left: value.left ?? 0
30
+ };
31
+ }
32
+ /**
33
+ * box spacing 値の各 edge に fn を適用し、入力の shape を保持したまま返す。
34
+ * number は number のまま、object は定義済み edge のみ変換する
35
+ * (未指定 edge を 0 扱いで生やさない。autoFit の縮小処理が最小値クランプを
36
+ * 持つため、未指定 edge に最小値が混入するのを防ぐ)。
37
+ */
38
+ function mapBoxSpacing(value, fn) {
39
+ if (typeof value === "number") {
40
+ const mapped = fn(value);
41
+ return {
42
+ value: mapped,
43
+ changed: mapped !== value
44
+ };
45
+ }
46
+ const mappedValue = {};
47
+ let changed = false;
48
+ for (const edge of EDGES) {
49
+ const edgeValue = value[edge];
50
+ if (edgeValue === void 0) continue;
51
+ const mapped = fn(edgeValue);
52
+ mappedValue[edge] = mapped;
53
+ if (mapped !== edgeValue) changed = true;
54
+ }
55
+ return {
56
+ value: mappedValue,
57
+ changed
58
+ };
59
+ }
60
+ //#endregion
61
+ export { mapBoxSpacing, resolveBoxSpacing };
62
+
63
+ //# sourceMappingURL=boxSpacing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boxSpacing.js","names":[],"sources":["../../src/shared/boxSpacing.ts"],"sourcesContent":["/**\n * box spacing 系属性 (padding / margin / SlideMaster margin) の内部共通 resolver。\n *\n * 対象属性群: `number | { top?, right?, bottom?, left? }` 形式で指定される余白系の\n * layout/style 属性。pipeline の各段階が個別に形式分岐すると解釈ズレの温床になるため、\n * 「入力 XML の値」から「layout/render が使う解決済み per-edge 値」への正規化を\n * 本モジュールに集約する。\n *\n * 利用箇所:\n * - calcYogaLayout: padding / margin の yoga への設定 (resolveBoxSpacing)\n * - renderPptx: contentArea の padding 控除、SlideMaster margin の変換 (resolveBoxSpacing)\n * - autoFit: padding 縮小・一律スケール時の shape 保持変換 (mapBoxSpacing)\n *\n * fill / border / shadow など見た目属性の変換は renderPptx/utils/visualStyle.ts、\n * 複合ノードのスケーリングは renderPptx/utils/scaleToFit.ts が担当する (本モジュールの対象外)。\n */\n\n/**\n * types.ts の paddingSchema / slideMasterMarginSchema と同じ shape。\n * schema 側を変更する場合は本型も同期すること。\n */\nexport type BoxSpacingInput =\n | number\n | {\n top?: number;\n right?: number;\n bottom?: number;\n left?: number;\n };\n\nexport interface ResolvedBoxSpacing {\n top: number;\n right: number;\n bottom: number;\n left: number;\n}\n\nconst EDGES = [\"top\", \"right\", \"bottom\", \"left\"] as const;\n\n/**\n * box spacing 値を解決済みの per-edge 値に正規化する。\n * number は 4 辺すべて、object は未指定 edge を 0 として解決する。\n */\nexport function resolveBoxSpacing(\n value: BoxSpacingInput | undefined,\n): ResolvedBoxSpacing {\n if (value === undefined) {\n return { top: 0, right: 0, bottom: 0, left: 0 };\n }\n if (typeof value === \"number\") {\n return { top: value, right: value, bottom: value, left: value };\n }\n return {\n top: value.top ?? 0,\n right: value.right ?? 0,\n bottom: value.bottom ?? 0,\n left: value.left ?? 0,\n };\n}\n\n/**\n * box spacing 値の各 edge に fn を適用し、入力の shape を保持したまま返す。\n * number は number のまま、object は定義済み edge のみ変換する\n * (未指定 edge を 0 扱いで生やさない。autoFit の縮小処理が最小値クランプを\n * 持つため、未指定 edge に最小値が混入するのを防ぐ)。\n */\nexport function mapBoxSpacing(\n value: BoxSpacingInput,\n fn: (edgeValue: number) => number,\n): { value: BoxSpacingInput; changed: boolean } {\n if (typeof value === \"number\") {\n const mapped = fn(value);\n return { value: mapped, changed: mapped !== value };\n }\n const mappedValue: Exclude<BoxSpacingInput, number> = {};\n let changed = false;\n for (const edge of EDGES) {\n const edgeValue = value[edge];\n if (edgeValue === undefined) {\n continue;\n }\n const mapped = fn(edgeValue);\n mappedValue[edge] = mapped;\n if (mapped !== edgeValue) {\n changed = true;\n }\n }\n return { value: mappedValue, changed };\n}\n"],"mappings":";AAqCA,MAAM,QAAQ;CAAC;CAAO;CAAS;CAAU;AAAM;;;;;AAM/C,SAAgB,kBACd,OACoB;CACpB,IAAI,UAAU,KAAA,GACZ,OAAO;EAAE,KAAK;EAAG,OAAO;EAAG,QAAQ;EAAG,MAAM;CAAE;CAEhD,IAAI,OAAO,UAAU,UACnB,OAAO;EAAE,KAAK;EAAO,OAAO;EAAO,QAAQ;EAAO,MAAM;CAAM;CAEhE,OAAO;EACL,KAAK,MAAM,OAAO;EAClB,OAAO,MAAM,SAAS;EACtB,QAAQ,MAAM,UAAU;EACxB,MAAM,MAAM,QAAQ;CACtB;AACF;;;;;;;AAQA,SAAgB,cACd,OACA,IAC8C;CAC9C,IAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,SAAS,GAAG,KAAK;EACvB,OAAO;GAAE,OAAO;GAAQ,SAAS,WAAW;EAAM;CACpD;CACA,MAAM,cAAgD,CAAC;CACvD,IAAI,UAAU;CACd,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,YAAY,MAAM;EACxB,IAAI,cAAc,KAAA,GAChB;EAEF,MAAM,SAAS,GAAG,SAAS;EAC3B,YAAY,QAAQ;EACpB,IAAI,WAAW,WACb,UAAU;CAEd;CACA,OAAO;EAAE,OAAO;EAAa;CAAQ;AACvC"}
@@ -4,13 +4,7 @@
4
4
  */
5
5
  function walkPOMTree(node, visitor) {
6
6
  visitor(node);
7
- switch (node.type) {
8
- case "vstack":
9
- case "hstack":
10
- case "layer":
11
- for (const child of node.children) walkPOMTree(child, visitor);
12
- break;
13
- }
7
+ if (node.type === "vstack" || node.type === "hstack" || node.type === "layer") for (const child of node.children) walkPOMTree(child, visitor);
14
8
  }
15
9
  //#endregion
16
10
  export { walkPOMTree };
@@ -1 +1 @@
1
- {"version":3,"file":"walkTree.js","names":[],"sources":["../../src/shared/walkTree.ts"],"sourcesContent":["import type { POMNode } from \"../types.ts\";\n\n/**\n * POMNode ツリーを再帰的に走査し、各ノードに visitor を適用する\n */\nexport function walkPOMTree(\n node: POMNode,\n visitor: (node: POMNode) => void,\n): void {\n visitor(node);\n\n switch (node.type) {\n case \"vstack\":\n case \"hstack\":\n case \"layer\":\n for (const child of node.children) {\n walkPOMTree(child, visitor);\n }\n break;\n }\n}\n"],"mappings":";;;;AAKA,SAAgB,YACd,MACA,SACM;CACN,QAAQ,IAAI;CAEZ,QAAQ,KAAK,MAAb;EACE,KAAK;EACL,KAAK;EACL,KAAK;GACH,KAAK,MAAM,SAAS,KAAK,UACvB,YAAY,OAAO,OAAO;GAE5B;CACJ;AACF"}
1
+ {"version":3,"file":"walkTree.js","names":[],"sources":["../../src/shared/walkTree.ts"],"sourcesContent":["import type { POMNode } from \"../types.ts\";\n\n/**\n * POMNode ツリーを再帰的に走査し、各ノードに visitor を適用する\n */\nexport function walkPOMTree(\n node: POMNode,\n visitor: (node: POMNode) => void,\n): void {\n visitor(node);\n\n if (\n node.type === \"vstack\" ||\n node.type === \"hstack\" ||\n node.type === \"layer\"\n ) {\n for (const child of node.children) {\n walkPOMTree(child, visitor);\n }\n }\n}\n"],"mappings":";;;;AAKA,SAAgB,YACd,MACA,SACM;CACN,QAAQ,IAAI;CAEZ,IACE,KAAK,SAAS,YACd,KAAK,SAAS,YACd,KAAK,SAAS,SAEd,KAAK,MAAM,SAAS,KAAK,UACvB,YAAY,OAAO,OAAO;AAGhC"}
@@ -16,7 +16,7 @@ async function toPositioned(pom, ctx, map, parentX = 0, parentY = 0) {
16
16
  const absoluteX = parentX + layout.left;
17
17
  const absoluteY = parentY + layout.top;
18
18
  const def = getNodeDef(pom.type);
19
- if (def.toPositioned) return def.toPositioned(pom, absoluteX, absoluteY, layout, ctx, map);
19
+ if (def.toPositioned) return def.toPositioned(pom, absoluteX, absoluteY, layout, ctx, map, toPositioned);
20
20
  switch (def.category) {
21
21
  case "leaf": return {
22
22
  ...pom,
@@ -1 +1 @@
1
- {"version":3,"file":"toPositioned.js","names":[],"sources":["../../src/toPositioned/toPositioned.ts"],"sourcesContent":["import type { POMNode, PositionedNode } from \"../types.ts\";\nimport type { BuildContext } from \"../buildContext.ts\";\nimport type { LayoutResultMap } from \"../calcYogaLayout/types.ts\";\nimport { getNodeDef } from \"../registry/index.ts\";\n\n/**\n * POMNode ツリーを絶対座標付きの PositionedNode ツリーに変換する\n * @param pom 入力 POMNode\n * @param ctx BuildContext\n * @param map LayoutResultMap(POMNode → 計算済みレイアウト結果のマッピング)\n * @param parentX 親ノードの絶対X座標\n * @param parentY 親ノードの絶対Y座標\n * @returns PositionedNode ツリー\n */\nexport async function toPositioned(\n pom: POMNode,\n ctx: BuildContext,\n map: LayoutResultMap,\n parentX = 0,\n parentY = 0,\n): Promise<PositionedNode> {\n const layout = map.get(pom);\n if (!layout) {\n throw new Error(\"Layout result not found in map for POMNode\");\n }\n const absoluteX = parentX + layout.left;\n const absoluteY = parentY + layout.top;\n\n const def = getNodeDef(pom.type);\n\n // ノード固有のカスタム変換がある場合はそれを使用\n if (def.toPositioned) {\n return def.toPositioned(pom, absoluteX, absoluteY, layout, ctx, map);\n }\n\n // category ベースのデフォルト処理\n switch (def.category) {\n case \"leaf\":\n return {\n ...pom,\n x: absoluteX,\n y: absoluteY,\n w: layout.width,\n h: layout.height,\n } as PositionedNode;\n\n case \"multi-child\": {\n const containerNode = pom as Extract<\n POMNode,\n { type: \"vstack\" | \"hstack\" }\n >;\n return {\n ...containerNode,\n x: absoluteX,\n y: absoluteY,\n w: layout.width,\n h: layout.height,\n children: await Promise.all(\n containerNode.children.map((child) =>\n toPositioned(child, ctx, map, absoluteX, absoluteY),\n ),\n ),\n };\n }\n\n case \"absolute-child\":\n // absolute-child (layer) は必ずカスタム toPositioned を持つべき\n throw new Error(\n `Node type \"${pom.type}\" with category \"absolute-child\" must have a custom toPositioned`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;AAcA,eAAsB,aACpB,KACA,KACA,KACA,UAAU,GACV,UAAU,GACe;CACzB,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,4CAA4C;CAE9D,MAAM,YAAY,UAAU,OAAO;CACnC,MAAM,YAAY,UAAU,OAAO;CAEnC,MAAM,MAAM,WAAW,IAAI,IAAI;CAG/B,IAAI,IAAI,cACN,OAAO,IAAI,aAAa,KAAK,WAAW,WAAW,QAAQ,KAAK,GAAG;CAIrE,QAAQ,IAAI,UAAZ;EACE,KAAK,QACH,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAG;GACH,GAAG,OAAO;GACV,GAAG,OAAO;EACZ;EAEF,KAAK,eAAe;GAClB,MAAM,gBAAgB;GAItB,OAAO;IACL,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG,OAAO;IACV,GAAG,OAAO;IACV,UAAU,MAAM,QAAQ,IACtB,cAAc,SAAS,KAAK,UAC1B,aAAa,OAAO,KAAK,KAAK,WAAW,SAAS,CACpD,CACF;GACF;EACF;EAEA,KAAK,kBAEH,MAAM,IAAI,MACR,cAAc,IAAI,KAAK,iEACzB;CACJ;AACF"}
1
+ {"version":3,"file":"toPositioned.js","names":[],"sources":["../../src/toPositioned/toPositioned.ts"],"sourcesContent":["import type { POMNode, PositionedNode } from \"../types.ts\";\nimport type { BuildContext } from \"../buildContext.ts\";\nimport type { LayoutResultMap } from \"../calcYogaLayout/types.ts\";\nimport { getNodeDef } from \"../registry/index.ts\";\n\n/**\n * POMNode ツリーを絶対座標付きの PositionedNode ツリーに変換する\n * @param pom 入力 POMNode\n * @param ctx BuildContext\n * @param map LayoutResultMap(POMNode → 計算済みレイアウト結果のマッピング)\n * @param parentX 親ノードの絶対X座標\n * @param parentY 親ノードの絶対Y座標\n * @returns PositionedNode ツリー\n */\nexport async function toPositioned(\n pom: POMNode,\n ctx: BuildContext,\n map: LayoutResultMap,\n parentX = 0,\n parentY = 0,\n): Promise<PositionedNode> {\n const layout = map.get(pom);\n if (!layout) {\n throw new Error(\"Layout result not found in map for POMNode\");\n }\n const absoluteX = parentX + layout.left;\n const absoluteY = parentY + layout.top;\n\n const def = getNodeDef(pom.type);\n\n // ノード固有のカスタム変換がある場合はそれを使用\n if (def.toPositioned) {\n return def.toPositioned(\n pom,\n absoluteX,\n absoluteY,\n layout,\n ctx,\n map,\n toPositioned,\n );\n }\n\n // category ベースのデフォルト処理\n switch (def.category) {\n case \"leaf\":\n return {\n ...pom,\n x: absoluteX,\n y: absoluteY,\n w: layout.width,\n h: layout.height,\n } as PositionedNode;\n\n case \"multi-child\": {\n const containerNode = pom as Extract<\n POMNode,\n { type: \"vstack\" | \"hstack\" }\n >;\n return {\n ...containerNode,\n x: absoluteX,\n y: absoluteY,\n w: layout.width,\n h: layout.height,\n children: await Promise.all(\n containerNode.children.map((child) =>\n toPositioned(child, ctx, map, absoluteX, absoluteY),\n ),\n ),\n };\n }\n\n case \"absolute-child\":\n // absolute-child (layer) は必ずカスタム toPositioned を持つべき\n throw new Error(\n `Node type \"${pom.type}\" with category \"absolute-child\" must have a custom toPositioned`,\n );\n }\n}\n"],"mappings":";;;;;;;;;;;;AAcA,eAAsB,aACpB,KACA,KACA,KACA,UAAU,GACV,UAAU,GACe;CACzB,MAAM,SAAS,IAAI,IAAI,GAAG;CAC1B,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,4CAA4C;CAE9D,MAAM,YAAY,UAAU,OAAO;CACnC,MAAM,YAAY,UAAU,OAAO;CAEnC,MAAM,MAAM,WAAW,IAAI,IAAI;CAG/B,IAAI,IAAI,cACN,OAAO,IAAI,aACT,KACA,WACA,WACA,QACA,KACA,KACA,YACF;CAIF,QAAQ,IAAI,UAAZ;EACE,KAAK,QACH,OAAO;GACL,GAAG;GACH,GAAG;GACH,GAAG;GACH,GAAG,OAAO;GACV,GAAG,OAAO;EACZ;EAEF,KAAK,eAAe;GAClB,MAAM,gBAAgB;GAItB,OAAO;IACL,GAAG;IACH,GAAG;IACH,GAAG;IACH,GAAG,OAAO;IACV,GAAG,OAAO;IACV,UAAU,MAAM,QAAQ,IACtB,cAAc,SAAS,KAAK,UAC1B,aAAa,OAAO,KAAK,KAAK,WAAW,SAAS,CACpD,CACF;GACF;EACF;EAEA,KAAK,kBAEH,MAAM,IAAI,MACR,cAAc,IAAI,KAAK,iEACzB;CACJ;AACF"}