@hirokisakabe/pom 10.0.0 → 10.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +1 -1
  2. package/dist/autoFit/autoFit.js +55 -15
  3. package/dist/autoFit/autoFit.js.map +1 -1
  4. package/dist/autoFit/strategies/reduceFontSize.js.map +1 -1
  5. package/dist/buildContext.js +4 -4
  6. package/dist/buildContext.js.map +1 -1
  7. package/dist/buildPptx.d.ts +3 -2
  8. package/dist/buildPptx.d.ts.map +1 -1
  9. package/dist/buildPptx.js +1 -1
  10. package/dist/buildPptx.js.map +1 -1
  11. package/dist/calcYogaLayout/calcYogaLayout.js.map +1 -1
  12. package/dist/calcYogaLayout/fontLoader.d.ts +13 -0
  13. package/dist/calcYogaLayout/fontLoader.d.ts.map +1 -0
  14. package/dist/calcYogaLayout/fontLoader.js +70 -3
  15. package/dist/calcYogaLayout/fontLoader.js.map +1 -1
  16. package/dist/calcYogaLayout/measureText.d.ts.map +1 -1
  17. package/dist/calcYogaLayout/measureText.js +6 -6
  18. package/dist/calcYogaLayout/measureText.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/extractSlideMastersAsPptx.d.ts.map +1 -1
  23. package/dist/extractThemeTokensFromPptx.d.ts +0 -1
  24. package/dist/extractThemeTokensFromPptx.d.ts.map +1 -1
  25. package/dist/icons/renderIcon.js +12 -10
  26. package/dist/icons/renderIcon.js.map +1 -1
  27. package/dist/index.d.ts +2 -1
  28. package/dist/parseXml/coercionRules.js.map +1 -1
  29. package/dist/parseXml/parseXml.d.ts +0 -1
  30. package/dist/parseXml/parseXml.d.ts.map +1 -1
  31. package/dist/parseXml/parseXml.js.map +1 -1
  32. package/dist/parseXml/serializeXml.d.ts +0 -1
  33. package/dist/parseXml/serializeXml.d.ts.map +1 -1
  34. package/dist/parseXml/serializeXml.js.map +1 -1
  35. package/dist/registry/definitions/icon.js +1 -1
  36. package/dist/registry/definitions/list.js +1 -1
  37. package/dist/registry/definitions/list.js.map +1 -1
  38. package/dist/registry/definitions/shape.js +1 -1
  39. package/dist/registry/definitions/shape.js.map +1 -1
  40. package/dist/registry/definitions/text.js +1 -1
  41. package/dist/registry/definitions/text.js.map +1 -1
  42. package/dist/renderPptx/authoringContext.js +101 -0
  43. package/dist/renderPptx/authoringContext.js.map +1 -0
  44. package/dist/renderPptx/{pptxAuthoring.js → glimpseAdapter.js} +83 -152
  45. package/dist/renderPptx/glimpseAdapter.js.map +1 -0
  46. package/dist/renderPptx/nodes/arrow.js +49 -7
  47. package/dist/renderPptx/nodes/arrow.js.map +1 -1
  48. package/dist/renderPptx/nodes/chart.js +2 -2
  49. package/dist/renderPptx/nodes/chart.js.map +1 -1
  50. package/dist/renderPptx/nodes/icon.js +1 -1
  51. package/dist/renderPptx/nodes/icon.js.map +1 -1
  52. package/dist/renderPptx/nodes/list.js +11 -19
  53. package/dist/renderPptx/nodes/list.js.map +1 -1
  54. package/dist/renderPptx/nodes/shape.js +18 -19
  55. package/dist/renderPptx/nodes/shape.js.map +1 -1
  56. package/dist/renderPptx/nodes/table.js +12 -21
  57. package/dist/renderPptx/nodes/table.js.map +1 -1
  58. package/dist/renderPptx/nodes/text.js +16 -1
  59. package/dist/renderPptx/nodes/text.js.map +1 -1
  60. package/dist/renderPptx/renderPptx.js +93 -40
  61. package/dist/renderPptx/renderPptx.js.map +1 -1
  62. package/dist/renderPptx/utils/connectorSites.js +58 -0
  63. package/dist/renderPptx/utils/connectorSites.js.map +1 -0
  64. package/dist/renderPptx/utils/glimpsePicture.js +2 -4
  65. package/dist/renderPptx/utils/glimpsePicture.js.map +1 -1
  66. package/dist/renderPptx/utils/glimpseShape.js +3 -3
  67. package/dist/renderPptx/utils/glimpseShape.js.map +1 -1
  68. package/dist/renderPptx/utils/glimpseTextBox.js +3 -30
  69. package/dist/renderPptx/utils/glimpseTextBox.js.map +1 -1
  70. package/dist/renderPptx/utils/straightLine.js.map +1 -1
  71. package/dist/renderPptx/writablePptx.d.ts +1 -1
  72. package/dist/renderPptx/writablePptx.d.ts.map +1 -1
  73. package/dist/types.d.ts +0 -1
  74. package/dist/types.d.ts.map +1 -1
  75. package/dist/types.js +1 -1
  76. package/package.json +10 -6
  77. package/dist/renderPptx/pptxAuthoring.js.map +0 -1
@@ -1,5 +1,4 @@
1
1
  import { POMNode } from "../types.js";
2
-
3
2
  //#region src/parseXml/serializeXml.d.ts
4
3
  /**
5
4
  * POMNode 配列を XML 文字列に変換する。
@@ -1 +1 @@
1
- {"version":3,"file":"serializeXml.d.ts","names":[],"sources":["../../src/parseXml/serializeXml.ts"],"mappings":";;;;;AAsJA;;;;AAA6C;;;;;;;;;;iBAA7B,YAAA,CAAa,KAAgB,EAAT,OAAO"}
1
+ {"version":3,"file":"serializeXml.d.ts","names":[],"sources":["../../src/parseXml/serializeXml.ts"],"mappings":";;;;;;;;;;;;;;;;;;iBAsJgB,aAAa,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"serializeXml.js","names":[],"sources":["../../src/parseXml/serializeXml.ts"],"sourcesContent":["import type { POMNode } from \"../types.ts\";\nimport { getNodeMetadata } from \"../registry/nodeMetadata.ts\";\nimport {\n INLINE_BOOLEAN_FORMATS,\n INLINE_LINK_TAG,\n INLINE_MARK_TAG,\n INLINE_SPAN_TAG,\n type TextRun,\n} from \"../registry/xmlChildRules.ts\";\n\n// runs と svgContent は専用の直列化パスで処理する\nconst SKIP_KEYS = new Set([\"type\", \"children\", \"runs\", \"svgContent\"]);\n\nfunction escapeAttrValue(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction escapeXmlContent(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction serializePrimitive(value: string | number | boolean): string {\n if (typeof value === \"string\") return escapeAttrValue(value);\n if (typeof value === \"number\") return String(value);\n return value ? \"true\" : \"false\";\n}\n\nfunction serializeAttrs(node: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(node)) {\n if (SKIP_KEYS.has(key) || value === undefined) continue;\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n for (const [subKey, subValue] of Object.entries(\n value as Record<string, unknown>,\n )) {\n if (subValue !== undefined) {\n parts.push(\n `${key}.${subKey}=\"${serializePrimitive(subValue as string | number | boolean)}\"`,\n );\n }\n }\n } else if (Array.isArray(value)) {\n parts.push(`${key}=\"${escapeAttrValue(JSON.stringify(value))}\"`);\n } else if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n parts.push(`${key}=\"${serializePrimitive(value)}\"`);\n }\n }\n return parts.length > 0 ? \" \" + parts.join(\" \") : \"\";\n}\n\nfunction serializeRun(run: TextRun): string {\n let content = escapeXmlContent(run.text);\n\n if (run.href) {\n content = `<${INLINE_LINK_TAG} href=\"${escapeAttrValue(run.href)}\">${content}</${INLINE_LINK_TAG}>`;\n }\n if (run.highlight) {\n content = `<${INLINE_MARK_TAG} color=\"${escapeAttrValue(run.highlight)}\">${content}</${INLINE_MARK_TAG}>`;\n }\n const spanAttrs: string[] = [];\n if (run.color) spanAttrs.push(`color=\"${escapeAttrValue(run.color)}\"`);\n if (run.fontFamily)\n spanAttrs.push(`fontFamily=\"${escapeAttrValue(run.fontFamily)}\"`);\n if (run.fontSize !== undefined) spanAttrs.push(`fontSize=\"${run.fontSize}\"`);\n if (run.letterSpacing !== undefined)\n spanAttrs.push(`letterSpacing=\"${run.letterSpacing}\"`);\n if (spanAttrs.length > 0) {\n content = `<${INLINE_SPAN_TAG} ${spanAttrs.join(\" \")}>${content}</${INLINE_SPAN_TAG}>`;\n }\n // INLINE_BOOLEAN_FORMATS は外側→内側のネスト順なので、内側から順に包む\n for (let i = INLINE_BOOLEAN_FORMATS.length - 1; i >= 0; i--) {\n const { tag, property } = INLINE_BOOLEAN_FORMATS[i];\n if (run[property]) content = `<${tag}>${content}</${tag}>`;\n }\n return content;\n}\n\nfunction serializeRuns(runs: TextRun[]): string {\n return runs.map(serializeRun).join(\"\");\n}\n\nfunction serializeNode(node: POMNode, depth: number): string {\n const indent = \" \".repeat(depth);\n const def = getNodeMetadata(node.type);\n const tag = def.tagName;\n const nodeRecord = node as Record<string, unknown>;\n\n if (def.childPolicy.kind === \"pom-children\") {\n const children = (nodeRecord.children as POMNode[]) ?? [];\n const attrStr = serializeAttrs(nodeRecord);\n if (children.length === 0) {\n return `${indent}<${tag}${attrStr} />`;\n }\n const childrenStr = children\n .map((c) => serializeNode(c, depth + 1))\n .join(\"\\n\");\n return `${indent}<${tag}${attrStr}>\\n${childrenStr}\\n${indent}</${tag}>`;\n }\n\n if (node.type === \"svg\") {\n const svgContent = (nodeRecord.svgContent as string) ?? \"\";\n const attrStr = serializeAttrs(nodeRecord);\n return `${indent}<${tag}${attrStr}>\\n${svgContent}\\n${indent}</${tag}>`;\n }\n\n // Text / Shape: runs があればインライン child element として直列化し装飾を保持する\n if (\n def.supportsInlineRuns &&\n Array.isArray(nodeRecord.runs) &&\n (nodeRecord.runs as unknown[]).length > 0\n ) {\n const runs = nodeRecord.runs as TextRun[];\n // runs がある場合、text は runs から復元できるため属性からも除外する\n const attrsWithoutText = { ...nodeRecord, text: undefined };\n const attrStr = serializeAttrs(attrsWithoutText);\n const inlineContent = serializeRuns(runs);\n return `${indent}<${tag}${attrStr}>${inlineContent}</${tag}>`;\n }\n\n const attrStr = serializeAttrs(nodeRecord);\n return `${indent}<${tag}${attrStr} />`;\n}\n\n/**\n * POMNode 配列を XML 文字列に変換する。\n *\n * parseXml の逆操作として機能する。runs(インライン装飾)は\n * B/I/A/U/S/Sub/Sup/Mark/Span タグとして child element に直列化されるため、\n * テキストの装飾情報も保持される。\n *\n * @example\n * ```typescript\n * import { parseXml, serializeXml } from \"@hirokisakabe/pom\";\n *\n * const nodes = parseXml(xml);\n * // ... ノードの並び替えなど ...\n * const newXml = serializeXml(nodes);\n * ```\n */\nexport function serializeXml(nodes: POMNode[]): string {\n return nodes\n .map((node) => `<Slide>\\n${serializeNode(node, 1)}\\n</Slide>`)\n .join(\"\\n\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"serializeXml.js","names":[],"sources":["../../src/parseXml/serializeXml.ts"],"sourcesContent":["import type { POMNode } from \"../types.ts\";\nimport { getNodeMetadata } from \"../registry/nodeMetadata.ts\";\nimport {\n INLINE_BOOLEAN_FORMATS,\n INLINE_LINK_TAG,\n INLINE_MARK_TAG,\n INLINE_SPAN_TAG,\n type TextRun,\n} from \"../registry/xmlChildRules.ts\";\n\n// runs と svgContent は専用の直列化パスで処理する\nconst SKIP_KEYS = new Set([\"type\", \"children\", \"runs\", \"svgContent\"]);\n\nfunction escapeAttrValue(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction escapeXmlContent(value: string): string {\n return value\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n}\n\nfunction serializePrimitive(value: string | number | boolean): string {\n if (typeof value === \"string\") return escapeAttrValue(value);\n if (typeof value === \"number\") return String(value);\n return value ? \"true\" : \"false\";\n}\n\nfunction serializeAttrs(node: Record<string, unknown>): string {\n const parts: string[] = [];\n for (const [key, value] of Object.entries(node)) {\n if (SKIP_KEYS.has(key) || value === undefined) continue;\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n for (const [subKey, subValue] of Object.entries(\n value as Record<string, unknown>,\n )) {\n if (subValue !== undefined) {\n parts.push(\n `${key}.${subKey}=\"${serializePrimitive(subValue as string | number | boolean)}\"`,\n );\n }\n }\n } else if (Array.isArray(value)) {\n parts.push(`${key}=\"${escapeAttrValue(JSON.stringify(value))}\"`);\n } else if (\n typeof value === \"string\" ||\n typeof value === \"number\" ||\n typeof value === \"boolean\"\n ) {\n parts.push(`${key}=\"${serializePrimitive(value)}\"`);\n }\n }\n return parts.length > 0 ? \" \" + parts.join(\" \") : \"\";\n}\n\nfunction serializeRun(run: TextRun): string {\n let content = escapeXmlContent(run.text);\n\n if (run.href) {\n content = `<${INLINE_LINK_TAG} href=\"${escapeAttrValue(run.href)}\">${content}</${INLINE_LINK_TAG}>`;\n }\n if (run.highlight) {\n content = `<${INLINE_MARK_TAG} color=\"${escapeAttrValue(run.highlight)}\">${content}</${INLINE_MARK_TAG}>`;\n }\n const spanAttrs: string[] = [];\n if (run.color) spanAttrs.push(`color=\"${escapeAttrValue(run.color)}\"`);\n if (run.fontFamily)\n spanAttrs.push(`fontFamily=\"${escapeAttrValue(run.fontFamily)}\"`);\n if (run.fontSize !== undefined) spanAttrs.push(`fontSize=\"${run.fontSize}\"`);\n if (run.letterSpacing !== undefined)\n spanAttrs.push(`letterSpacing=\"${run.letterSpacing}\"`);\n if (spanAttrs.length > 0) {\n content = `<${INLINE_SPAN_TAG} ${spanAttrs.join(\" \")}>${content}</${INLINE_SPAN_TAG}>`;\n }\n // INLINE_BOOLEAN_FORMATS は外側→内側のネスト順なので、内側から順に包む\n for (let i = INLINE_BOOLEAN_FORMATS.length - 1; i >= 0; i--) {\n const { tag, property } = INLINE_BOOLEAN_FORMATS[i];\n if (run[property]) content = `<${tag}>${content}</${tag}>`;\n }\n return content;\n}\n\nfunction serializeRuns(runs: TextRun[]): string {\n return runs.map(serializeRun).join(\"\");\n}\n\nfunction serializeNode(node: POMNode, depth: number): string {\n const indent = \" \".repeat(depth);\n const def = getNodeMetadata(node.type);\n const tag = def.tagName;\n const nodeRecord = node as Record<string, unknown>;\n\n if (def.childPolicy.kind === \"pom-children\") {\n const children = (nodeRecord.children as POMNode[]) ?? [];\n const attrStr = serializeAttrs(nodeRecord);\n if (children.length === 0) {\n return `${indent}<${tag}${attrStr} />`;\n }\n const childrenStr = children\n .map((c) => serializeNode(c, depth + 1))\n .join(\"\\n\");\n return `${indent}<${tag}${attrStr}>\\n${childrenStr}\\n${indent}</${tag}>`;\n }\n\n if (node.type === \"svg\") {\n const svgContent = (nodeRecord.svgContent as string) ?? \"\";\n const attrStr = serializeAttrs(nodeRecord);\n return `${indent}<${tag}${attrStr}>\\n${svgContent}\\n${indent}</${tag}>`;\n }\n\n // Text / Shape: runs があればインライン child element として直列化し装飾を保持する\n if (\n def.supportsInlineRuns &&\n Array.isArray(nodeRecord.runs) &&\n (nodeRecord.runs as unknown[]).length > 0\n ) {\n const runs = nodeRecord.runs as TextRun[];\n // runs がある場合、text は runs から復元できるため属性からも除外する\n const attrsWithoutText = { ...nodeRecord, text: undefined };\n const attrStr = serializeAttrs(attrsWithoutText);\n const inlineContent = serializeRuns(runs);\n return `${indent}<${tag}${attrStr}>${inlineContent}</${tag}>`;\n }\n\n const attrStr = serializeAttrs(nodeRecord);\n return `${indent}<${tag}${attrStr} />`;\n}\n\n/**\n * POMNode 配列を XML 文字列に変換する。\n *\n * parseXml の逆操作として機能する。runs(インライン装飾)は\n * B/I/A/U/S/Sub/Sup/Mark/Span タグとして child element に直列化されるため、\n * テキストの装飾情報も保持される。\n *\n * @example\n * ```typescript\n * import { parseXml, serializeXml } from \"@hirokisakabe/pom\";\n *\n * const nodes = parseXml(xml);\n * // ... ノードの並び替えなど ...\n * const newXml = serializeXml(nodes);\n * ```\n */\nexport function serializeXml(nodes: POMNode[]): string {\n return nodes\n .map((node) => `<Slide>\\n${serializeNode(node, 1)}\\n</Slide>`)\n .join(\"\\n\");\n}\n"],"mappings":";;;AAWA,MAAM,4BAAY,IAAI,IAAI;CAAC;CAAQ;CAAY;CAAQ;AAAY,CAAC;AAEpE,SAAS,gBAAgB,OAAuB;CAC9C,OAAO,MACJ,QAAQ,MAAM,OAAO,CAAC,CACtB,QAAQ,MAAM,QAAQ,CAAC,CACvB,QAAQ,MAAM,MAAM,CAAC,CACrB,QAAQ,MAAM,MAAM;AACzB;AAEA,SAAS,iBAAiB,OAAuB;CAC/C,OAAO,MACJ,QAAQ,MAAM,OAAO,CAAC,CACtB,QAAQ,MAAM,MAAM,CAAC,CACrB,QAAQ,MAAM,MAAM;AACzB;AAEA,SAAS,mBAAmB,OAA0C;CACpE,IAAI,OAAO,UAAU,UAAU,OAAO,gBAAgB,KAAK;CAC3D,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;CAClD,OAAO,QAAQ,SAAS;AAC1B;AAEA,SAAS,eAAe,MAAuC;CAC7D,MAAM,QAAkB,CAAC;CACzB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG;EAC/C,IAAI,UAAU,IAAI,GAAG,KAAK,UAAU,KAAA,GAAW;EAC/C,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK,GAChE;QAAA,MAAM,CAAC,QAAQ,aAAa,OAAO,QACtC,KACF,GACE,IAAI,aAAa,KAAA,GACf,MAAM,KACJ,GAAG,IAAI,GAAG,OAAO,IAAI,mBAAmB,QAAqC,EAAE,EACjF;EAAA,OAGC,IAAI,MAAM,QAAQ,KAAK,GAC5B,MAAM,KAAK,GAAG,IAAI,IAAI,gBAAgB,KAAK,UAAU,KAAK,CAAC,EAAE,EAAE;OAC1D,IACL,OAAO,UAAU,YACjB,OAAO,UAAU,YACjB,OAAO,UAAU,WAEjB,MAAM,KAAK,GAAG,IAAI,IAAI,mBAAmB,KAAK,EAAE,EAAE;CAEtD;CACA,OAAO,MAAM,SAAS,IAAI,MAAM,MAAM,KAAK,GAAG,IAAI;AACpD;AAEA,SAAS,aAAa,KAAsB;CAC1C,IAAI,UAAU,iBAAiB,IAAI,IAAI;CAEvC,IAAI,IAAI,MACN,UAAU,YAA6B,gBAAgB,IAAI,IAAI,EAAE,IAAI,QAAQ;CAE/E,IAAI,IAAI,WACN,UAAU,IAAI,gBAAgB,UAAU,gBAAgB,IAAI,SAAS,EAAE,IAAI,QAAQ,IAAI,gBAAgB;CAEzG,MAAM,YAAsB,CAAC;CAC7B,IAAI,IAAI,OAAO,UAAU,KAAK,UAAU,gBAAgB,IAAI,KAAK,EAAE,EAAE;CACrE,IAAI,IAAI,YACN,UAAU,KAAK,eAAe,gBAAgB,IAAI,UAAU,EAAE,EAAE;CAClE,IAAI,IAAI,aAAa,KAAA,GAAW,UAAU,KAAK,aAAa,IAAI,SAAS,EAAE;CAC3E,IAAI,IAAI,kBAAkB,KAAA,GACxB,UAAU,KAAK,kBAAkB,IAAI,cAAc,EAAE;CACvD,IAAI,UAAU,SAAS,GACrB,UAAU,IAAI,gBAAgB,GAAG,UAAU,KAAK,GAAG,EAAE,GAAG,QAAQ,IAAI,gBAAgB;CAGtF,KAAK,IAAI,IAAI,uBAAuB,SAAS,GAAG,KAAK,GAAG,KAAK;EAC3D,MAAM,EAAE,KAAK,aAAa,uBAAuB;EACjD,IAAI,IAAI,WAAW,UAAU,IAAI,IAAI,GAAG,QAAQ,IAAI,IAAI;CAC1D;CACA,OAAO;AACT;AAEA,SAAS,cAAc,MAAyB;CAC9C,OAAO,KAAK,IAAI,YAAY,CAAC,CAAC,KAAK,EAAE;AACvC;AAEA,SAAS,cAAc,MAAe,OAAuB;CAC3D,MAAM,SAAS,KAAK,OAAO,KAAK;CAChC,MAAM,MAAM,gBAAgB,KAAK,IAAI;CACrC,MAAM,MAAM,IAAI;CAChB,MAAM,aAAa;CAEnB,IAAI,IAAI,YAAY,SAAS,gBAAgB;EAC3C,MAAM,WAAY,WAAW,YAA0B,CAAC;EACxD,MAAM,UAAU,eAAe,UAAU;EACzC,IAAI,SAAS,WAAW,GACtB,OAAO,GAAG,OAAO,GAAG,MAAM,QAAQ;EAKpC,OAAO,GAAG,OAAO,GAAG,MAAM,QAAQ,KAHd,SACjB,KAAK,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,CACvC,KAAK,IACyC,EAAE,IAAI,OAAO,IAAI,IAAI;CACxE;CAEA,IAAI,KAAK,SAAS,OAAO;EACvB,MAAM,aAAc,WAAW,cAAyB;EAExD,OAAO,GAAG,OAAO,GAAG,MADJ,eAAe,UACC,EAAE,KAAK,WAAW,IAAI,OAAO,IAAI,IAAI;CACvE;CAGA,IACE,IAAI,sBACJ,MAAM,QAAQ,WAAW,IAAI,KAC5B,WAAW,KAAmB,SAAS,GACxC;EACA,MAAM,OAAO,WAAW;EAKxB,OAAO,GAAG,OAAO,GAAG,MAFJ,eAAe;GADJ,GAAG;GAAY,MAAM,KAAA;EACF,CAEd,EAAE,GADZ,cAAc,IACa,EAAE,IAAI,IAAI;CAC7D;CAGA,OAAO,GAAG,OAAO,GAAG,MADJ,eAAe,UACC,EAAE;AACpC;;;;;;;;;;;;;;;;;AAkBA,SAAgB,aAAa,OAA0B;CACrD,OAAO,MACJ,KAAK,SAAS,YAAY,cAAc,MAAM,CAAC,EAAE,WAAW,CAAC,CAC7D,KAAK,IAAI;AACd"}
@@ -1,5 +1,5 @@
1
- import { getNodeMetadata } from "../nodeMetadata.js";
2
1
  import { getContentArea } from "../../renderPptx/utils/contentArea.js";
2
+ import { getNodeMetadata } from "../nodeMetadata.js";
3
3
  import { rasterizeIcon } from "../../icons/renderIcon.js";
4
4
  import "../../icons/index.js";
5
5
  import { renderIconNode } from "../../renderPptx/nodes/icon.js";
@@ -28,7 +28,7 @@ function applyListYogaStyle(node, yn, yoga, ctx) {
28
28
  fontSizePx,
29
29
  lineHeight,
30
30
  fontWeight
31
- }, ctx.textMeasurementMode);
31
+ }, ctx.textMeasurementMode, ctx.fontRegistry);
32
32
  return {
33
33
  width: widthPx + bulletIndentPx,
34
34
  height: heightPx
@@ -1 +1 @@
1
- {"version":3,"file":"list.js","names":[],"sources":["../../../src/registry/definitions/list.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport type { NodeDefinition, Yoga } from \"../types.ts\";\nimport type { Node as YogaNode } from \"yoga-layout\";\nimport { measureText } from \"../../calcYogaLayout/measureText.ts\";\nimport { measureFontLineHeightRatio } from \"../../calcYogaLayout/fontLoader.ts\";\nimport type { BuildContext } from \"../../buildContext.ts\";\nimport { renderUlNode, renderOlNode } from \"../../renderPptx/nodes/list.ts\";\nimport { getNodeMetadata } from \"../nodeMetadata.ts\";\n\nfunction applyListYogaStyle(\n node: POMNode,\n yn: YogaNode,\n yoga: Yoga,\n ctx: BuildContext,\n) {\n const n = node as Extract<POMNode, { type: \"ul\" | \"ol\" }>;\n const combinedText = n.items.map((item) => item.text).join(\"\\n\");\n const baseFontSizePx = n.fontSize ?? 24;\n // Li 単位の fontSize 上書きと、Li 内 <Span fontSize=\"...\"> による run 単位\n // 上書きを両方考慮した最大値で計測する。単一 fontSize でしか計測できない\n // 制約に対する保守的な見積もりで、横方向は過剰評価になるが縦方向 clipping\n // を防ぐ。\n const fontSizePx = Math.max(\n baseFontSizePx,\n ...n.items.flatMap((item) => [\n item.fontSize ?? baseFontSizePx,\n ...(item.runs?.map(\n (r) => r.fontSize ?? item.fontSize ?? baseFontSizePx,\n ) ?? []),\n ]),\n );\n const fontFamily = n.fontFamily ?? \"Noto Sans JP\";\n const fontWeight = n.bold ? \"bold\" : \"normal\";\n const spacingMultiple = n.lineHeight ?? 1.3;\n\n const fontMetricsRatio = measureFontLineHeightRatio(fontWeight);\n const lineHeight = fontMetricsRatio * spacingMultiple;\n\n // バレット/番号の互換インデント幅(27pt = 36px @96dpi)\n const bulletIndentPx = 36;\n\n yn.setMeasureFunc((width, widthMode) => {\n const maxWidthPx = (() => {\n switch (widthMode) {\n case yoga.MEASURE_MODE_UNDEFINED:\n return Number.POSITIVE_INFINITY;\n case yoga.MEASURE_MODE_EXACTLY:\n case yoga.MEASURE_MODE_AT_MOST:\n return width;\n default:\n return Number.POSITIVE_INFINITY;\n }\n })();\n\n const textMaxWidthPx = Math.max(0, maxWidthPx - bulletIndentPx);\n\n const { widthPx, heightPx } = measureText(\n combinedText,\n textMaxWidthPx,\n {\n fontFamily,\n fontSizePx,\n lineHeight,\n fontWeight,\n },\n ctx.textMeasurementMode,\n );\n\n return {\n width: widthPx + bulletIndentPx,\n height: heightPx,\n };\n });\n}\n\nexport const ulNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"ul\"),\n applyYogaStyle: applyListYogaStyle,\n render(node, ctx) {\n renderUlNode(node as Extract<typeof node, { type: \"ul\" }>, ctx);\n },\n};\n\nexport const olNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"ol\"),\n applyYogaStyle: applyListYogaStyle,\n render(node, ctx) {\n renderOlNode(node as Extract<typeof node, { type: \"ol\" }>, ctx);\n },\n};\n"],"mappings":";;;;;AASA,SAAS,mBACP,MACA,IACA,MACA,KACA;CACA,MAAM,IAAI;CACV,MAAM,eAAe,EAAE,MAAM,KAAK,SAAS,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI;CAC/D,MAAM,iBAAiB,EAAE,YAAY;CAKrC,MAAM,aAAa,KAAK,IACtB,gBACA,GAAG,EAAE,MAAM,SAAS,SAAS,CAC3B,KAAK,YAAY,gBACjB,GAAI,KAAK,MAAM,KACZ,MAAM,EAAE,YAAY,KAAK,YAAY,cACxC,KAAK,CAAC,CACR,CAAC,CACH;CACA,MAAM,aAAa,EAAE,cAAc;CACnC,MAAM,aAAa,EAAE,OAAO,SAAS;CACrC,MAAM,kBAAkB,EAAE,cAAc;CAGxC,MAAM,aADmB,2BAA2B,UAClB,IAAI;CAGtC,MAAM,iBAAiB;CAEvB,GAAG,gBAAgB,OAAO,cAAc;EACtC,MAAM,oBAAoB;GACxB,QAAQ,WAAR;IACE,KAAK,KAAK,wBACR,OAAO,OAAO;IAChB,KAAK,KAAK;IACV,KAAK,KAAK,sBACR,OAAO;IACT,SACE,OAAO,OAAO;GAClB;EACF,EAAA,CAAG;EAEH,MAAM,iBAAiB,KAAK,IAAI,GAAG,aAAa,cAAc;EAE9D,MAAM,EAAE,SAAS,aAAa,YAC5B,cACA,gBACA;GACE;GACA;GACA;GACA;EACF,GACA,IAAI,mBACN;EAEA,OAAO;GACL,OAAO,UAAU;GACjB,QAAQ;EACV;CACF,CAAC;AACH;AAEA,MAAa,YAA4B;CACvC,GAAG,gBAAgB,IAAI;CACvB,gBAAgB;CAChB,OAAO,MAAM,KAAK;EAChB,aAAa,MAA8C,GAAG;CAChE;AACF;AAEA,MAAa,YAA4B;CACvC,GAAG,gBAAgB,IAAI;CACvB,gBAAgB;CAChB,OAAO,MAAM,KAAK;EAChB,aAAa,MAA8C,GAAG;CAChE;AACF"}
1
+ {"version":3,"file":"list.js","names":[],"sources":["../../../src/registry/definitions/list.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport type { NodeDefinition, Yoga } from \"../types.ts\";\nimport type { Node as YogaNode } from \"yoga-layout\";\nimport { measureText } from \"../../calcYogaLayout/measureText.ts\";\nimport { measureFontLineHeightRatio } from \"../../calcYogaLayout/fontLoader.ts\";\nimport type { BuildContext } from \"../../buildContext.ts\";\nimport { renderUlNode, renderOlNode } from \"../../renderPptx/nodes/list.ts\";\nimport { getNodeMetadata } from \"../nodeMetadata.ts\";\n\nfunction applyListYogaStyle(\n node: POMNode,\n yn: YogaNode,\n yoga: Yoga,\n ctx: BuildContext,\n) {\n const n = node as Extract<POMNode, { type: \"ul\" | \"ol\" }>;\n const combinedText = n.items.map((item) => item.text).join(\"\\n\");\n const baseFontSizePx = n.fontSize ?? 24;\n // Li 単位の fontSize 上書きと、Li 内 <Span fontSize=\"...\"> による run 単位\n // 上書きを両方考慮した最大値で計測する。単一 fontSize でしか計測できない\n // 制約に対する保守的な見積もりで、横方向は過剰評価になるが縦方向 clipping\n // を防ぐ。\n const fontSizePx = Math.max(\n baseFontSizePx,\n ...n.items.flatMap((item) => [\n item.fontSize ?? baseFontSizePx,\n ...(item.runs?.map(\n (r) => r.fontSize ?? item.fontSize ?? baseFontSizePx,\n ) ?? []),\n ]),\n );\n const fontFamily = n.fontFamily ?? \"Noto Sans JP\";\n const fontWeight = n.bold ? \"bold\" : \"normal\";\n const spacingMultiple = n.lineHeight ?? 1.3;\n\n const fontMetricsRatio = measureFontLineHeightRatio(fontWeight);\n const lineHeight = fontMetricsRatio * spacingMultiple;\n\n // バレット/番号の互換インデント幅(27pt = 36px @96dpi)\n const bulletIndentPx = 36;\n\n yn.setMeasureFunc((width, widthMode) => {\n const maxWidthPx = (() => {\n switch (widthMode) {\n case yoga.MEASURE_MODE_UNDEFINED:\n return Number.POSITIVE_INFINITY;\n case yoga.MEASURE_MODE_EXACTLY:\n case yoga.MEASURE_MODE_AT_MOST:\n return width;\n default:\n return Number.POSITIVE_INFINITY;\n }\n })();\n\n const textMaxWidthPx = Math.max(0, maxWidthPx - bulletIndentPx);\n\n const { widthPx, heightPx } = measureText(\n combinedText,\n textMaxWidthPx,\n {\n fontFamily,\n fontSizePx,\n lineHeight,\n fontWeight,\n },\n ctx.textMeasurementMode,\n ctx.fontRegistry,\n );\n\n return {\n width: widthPx + bulletIndentPx,\n height: heightPx,\n };\n });\n}\n\nexport const ulNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"ul\"),\n applyYogaStyle: applyListYogaStyle,\n render(node, ctx) {\n renderUlNode(node as Extract<typeof node, { type: \"ul\" }>, ctx);\n },\n};\n\nexport const olNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"ol\"),\n applyYogaStyle: applyListYogaStyle,\n render(node, ctx) {\n renderOlNode(node as Extract<typeof node, { type: \"ol\" }>, ctx);\n },\n};\n"],"mappings":";;;;;AASA,SAAS,mBACP,MACA,IACA,MACA,KACA;CACA,MAAM,IAAI;CACV,MAAM,eAAe,EAAE,MAAM,KAAK,SAAS,KAAK,IAAI,CAAC,CAAC,KAAK,IAAI;CAC/D,MAAM,iBAAiB,EAAE,YAAY;CAKrC,MAAM,aAAa,KAAK,IACtB,gBACA,GAAG,EAAE,MAAM,SAAS,SAAS,CAC3B,KAAK,YAAY,gBACjB,GAAI,KAAK,MAAM,KACZ,MAAM,EAAE,YAAY,KAAK,YAAY,cACxC,KAAK,CAAC,CACR,CAAC,CACH;CACA,MAAM,aAAa,EAAE,cAAc;CACnC,MAAM,aAAa,EAAE,OAAO,SAAS;CACrC,MAAM,kBAAkB,EAAE,cAAc;CAGxC,MAAM,aADmB,2BAA2B,UAClB,IAAI;CAGtC,MAAM,iBAAiB;CAEvB,GAAG,gBAAgB,OAAO,cAAc;EACtC,MAAM,oBAAoB;GACxB,QAAQ,WAAR;IACE,KAAK,KAAK,wBACR,OAAO,OAAO;IAChB,KAAK,KAAK;IACV,KAAK,KAAK,sBACR,OAAO;IACT,SACE,OAAO,OAAO;GAClB;EACF,EAAA,CAAG;EAEH,MAAM,iBAAiB,KAAK,IAAI,GAAG,aAAa,cAAc;EAE9D,MAAM,EAAE,SAAS,aAAa,YAC5B,cACA,gBACA;GACE;GACA;GACA;GACA;EACF,GACA,IAAI,qBACJ,IAAI,YACN;EAEA,OAAO;GACL,OAAO,UAAU;GACjB,QAAQ;EACV;CACF,CAAC;AACH;AAEA,MAAa,YAA4B;CACvC,GAAG,gBAAgB,IAAI;CACvB,gBAAgB;CAChB,OAAO,MAAM,KAAK;EAChB,aAAa,MAA8C,GAAG;CAChE;AACF;AAEA,MAAa,YAA4B;CACvC,GAAG,gBAAgB,IAAI;CACvB,gBAAgB;CAChB,OAAO,MAAM,KAAK;EAChB,aAAa,MAA8C,GAAG;CAChE;AACF"}
@@ -26,7 +26,7 @@ const shapeNodeDef = {
26
26
  fontSizePx,
27
27
  lineHeight,
28
28
  fontWeight
29
- }, ctx.textMeasurementMode);
29
+ }, ctx.textMeasurementMode, ctx.fontRegistry);
30
30
  return {
31
31
  width: widthPx,
32
32
  height: heightPx
@@ -1 +1 @@
1
- {"version":3,"file":"shape.js","names":[],"sources":["../../../src/registry/definitions/shape.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport type { NodeDefinition, Yoga } from \"../types.ts\";\nimport type { Node as YogaNode } from \"yoga-layout\";\nimport { measureText } from \"../../calcYogaLayout/measureText.ts\";\nimport type { BuildContext } from \"../../buildContext.ts\";\nimport { renderShapeNode } from \"../../renderPptx/nodes/shape.ts\";\nimport { getNodeMetadata } from \"../nodeMetadata.ts\";\n\nexport const shapeNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"shape\"),\n applyYogaStyle(node: POMNode, yn: YogaNode, yoga: Yoga, ctx: BuildContext) {\n const n = node as Extract<POMNode, { type: \"shape\" }>;\n if (n.text) {\n const text = n.text;\n const fontSizePx = n.fontSize ?? 24;\n const fontFamily = n.fontFamily ?? \"Noto Sans JP\";\n const fontWeight = n.bold ? \"bold\" : \"normal\";\n const lineHeight = n.lineHeight ?? 1.3;\n\n yn.setMeasureFunc((width, widthMode) => {\n const maxWidthPx = (() => {\n switch (widthMode) {\n case yoga.MEASURE_MODE_UNDEFINED:\n return Number.POSITIVE_INFINITY;\n case yoga.MEASURE_MODE_EXACTLY:\n case yoga.MEASURE_MODE_AT_MOST:\n return width;\n default:\n return Number.POSITIVE_INFINITY;\n }\n })();\n\n const { widthPx, heightPx } = measureText(\n text,\n maxWidthPx,\n {\n fontFamily,\n fontSizePx,\n lineHeight,\n fontWeight,\n },\n ctx.textMeasurementMode,\n );\n\n return { width: widthPx, height: heightPx };\n });\n }\n },\n render(node, ctx) {\n renderShapeNode(node as Extract<typeof node, { type: \"shape\" }>, ctx);\n },\n};\n"],"mappings":";;;;AAQA,MAAa,eAA+B;CAC1C,GAAG,gBAAgB,OAAO;CAC1B,eAAe,MAAe,IAAc,MAAY,KAAmB;EACzE,MAAM,IAAI;EACV,IAAI,EAAE,MAAM;GACV,MAAM,OAAO,EAAE;GACf,MAAM,aAAa,EAAE,YAAY;GACjC,MAAM,aAAa,EAAE,cAAc;GACnC,MAAM,aAAa,EAAE,OAAO,SAAS;GACrC,MAAM,aAAa,EAAE,cAAc;GAEnC,GAAG,gBAAgB,OAAO,cAAc;IACtC,MAAM,oBAAoB;KACxB,QAAQ,WAAR;MACE,KAAK,KAAK,wBACR,OAAO,OAAO;MAChB,KAAK,KAAK;MACV,KAAK,KAAK,sBACR,OAAO;MACT,SACE,OAAO,OAAO;KAClB;IACF,EAAA,CAAG;IAEH,MAAM,EAAE,SAAS,aAAa,YAC5B,MACA,YACA;KACE;KACA;KACA;KACA;IACF,GACA,IAAI,mBACN;IAEA,OAAO;KAAE,OAAO;KAAS,QAAQ;IAAS;GAC5C,CAAC;EACH;CACF;CACA,OAAO,MAAM,KAAK;EAChB,gBAAgB,MAAiD,GAAG;CACtE;AACF"}
1
+ {"version":3,"file":"shape.js","names":[],"sources":["../../../src/registry/definitions/shape.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport type { NodeDefinition, Yoga } from \"../types.ts\";\nimport type { Node as YogaNode } from \"yoga-layout\";\nimport { measureText } from \"../../calcYogaLayout/measureText.ts\";\nimport type { BuildContext } from \"../../buildContext.ts\";\nimport { renderShapeNode } from \"../../renderPptx/nodes/shape.ts\";\nimport { getNodeMetadata } from \"../nodeMetadata.ts\";\n\nexport const shapeNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"shape\"),\n applyYogaStyle(node: POMNode, yn: YogaNode, yoga: Yoga, ctx: BuildContext) {\n const n = node as Extract<POMNode, { type: \"shape\" }>;\n if (n.text) {\n const text = n.text;\n const fontSizePx = n.fontSize ?? 24;\n const fontFamily = n.fontFamily ?? \"Noto Sans JP\";\n const fontWeight = n.bold ? \"bold\" : \"normal\";\n const lineHeight = n.lineHeight ?? 1.3;\n\n yn.setMeasureFunc((width, widthMode) => {\n const maxWidthPx = (() => {\n switch (widthMode) {\n case yoga.MEASURE_MODE_UNDEFINED:\n return Number.POSITIVE_INFINITY;\n case yoga.MEASURE_MODE_EXACTLY:\n case yoga.MEASURE_MODE_AT_MOST:\n return width;\n default:\n return Number.POSITIVE_INFINITY;\n }\n })();\n\n const { widthPx, heightPx } = measureText(\n text,\n maxWidthPx,\n {\n fontFamily,\n fontSizePx,\n lineHeight,\n fontWeight,\n },\n ctx.textMeasurementMode,\n ctx.fontRegistry,\n );\n\n return { width: widthPx, height: heightPx };\n });\n }\n },\n render(node, ctx) {\n renderShapeNode(node as Extract<typeof node, { type: \"shape\" }>, ctx);\n },\n};\n"],"mappings":";;;;AAQA,MAAa,eAA+B;CAC1C,GAAG,gBAAgB,OAAO;CAC1B,eAAe,MAAe,IAAc,MAAY,KAAmB;EACzE,MAAM,IAAI;EACV,IAAI,EAAE,MAAM;GACV,MAAM,OAAO,EAAE;GACf,MAAM,aAAa,EAAE,YAAY;GACjC,MAAM,aAAa,EAAE,cAAc;GACnC,MAAM,aAAa,EAAE,OAAO,SAAS;GACrC,MAAM,aAAa,EAAE,cAAc;GAEnC,GAAG,gBAAgB,OAAO,cAAc;IACtC,MAAM,oBAAoB;KACxB,QAAQ,WAAR;MACE,KAAK,KAAK,wBACR,OAAO,OAAO;MAChB,KAAK,KAAK;MACV,KAAK,KAAK,sBACR,OAAO;MACT,SACE,OAAO,OAAO;KAClB;IACF,EAAA,CAAG;IAEH,MAAM,EAAE,SAAS,aAAa,YAC5B,MACA,YACA;KACE;KACA;KACA;KACA;IACF,GACA,IAAI,qBACJ,IAAI,YACN;IAEA,OAAO;KAAE,OAAO;KAAS,QAAQ;IAAS;GAC5C,CAAC;EACH;CACF;CACA,OAAO,MAAM,KAAK;EAChB,gBAAgB,MAAiD,GAAG;CACtE;AACF"}
@@ -28,7 +28,7 @@ const textNodeDef = {
28
28
  lineHeight,
29
29
  fontWeight,
30
30
  letterSpacingPx
31
- }, ctx.textMeasurementMode);
31
+ }, ctx.textMeasurementMode, ctx.fontRegistry);
32
32
  return {
33
33
  width: widthPx,
34
34
  height: heightPx
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":[],"sources":["../../../src/registry/definitions/text.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport type { NodeDefinition, Yoga } from \"../types.ts\";\nimport type { Node as YogaNode } from \"yoga-layout\";\nimport { measureText } from \"../../calcYogaLayout/measureText.ts\";\nimport type { BuildContext } from \"../../buildContext.ts\";\nimport { renderTextNode } from \"../../renderPptx/nodes/text.ts\";\nimport { getNodeMetadata } from \"../nodeMetadata.ts\";\n\nexport const textNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"text\"),\n applyYogaStyle(node: POMNode, yn: YogaNode, yoga: Yoga, ctx: BuildContext) {\n const n = node as Extract<POMNode, { type: \"text\" }>;\n const text = n.text;\n const baseFontSizePx = n.fontSize ?? 24;\n // runs に fontSize override がある場合は最大値で計測する(描画は run 単位で\n // 各自の fontSize が適用されるが、計測関数は単一 fontSize しか扱えないので\n // 最大値を採用して縦方向の clipping を防ぐ。\n // 横方向は最大値だと過剰評価になるが、典型ケース (大きな数字 + 小さい単位)\n // では小さい unit 部分が短く影響は軽微で、安全側に倒す)\n const fontSizePx = Math.max(\n baseFontSizePx,\n ...(n.runs?.map((r) => r.fontSize ?? baseFontSizePx) ?? []),\n );\n const fontFamily = n.fontFamily ?? \"Noto Sans JP\";\n const fontWeight = n.bold ? \"bold\" : \"normal\";\n const lineHeight = n.lineHeight ?? 1.3;\n const letterSpacingPx = n.letterSpacing;\n\n yn.setMeasureFunc((width, widthMode) => {\n const maxWidthPx = (() => {\n switch (widthMode) {\n case yoga.MEASURE_MODE_UNDEFINED:\n return Number.POSITIVE_INFINITY;\n case yoga.MEASURE_MODE_EXACTLY:\n case yoga.MEASURE_MODE_AT_MOST:\n return width;\n default:\n return Number.POSITIVE_INFINITY;\n }\n })();\n\n const { widthPx, heightPx } = measureText(\n text,\n maxWidthPx,\n {\n fontFamily,\n fontSizePx,\n lineHeight,\n fontWeight,\n letterSpacingPx,\n },\n ctx.textMeasurementMode,\n );\n\n return { width: widthPx, height: heightPx };\n });\n },\n render(node, ctx) {\n renderTextNode(node as Extract<typeof node, { type: \"text\" }>, ctx);\n },\n};\n"],"mappings":";;;;AAQA,MAAa,cAA8B;CACzC,GAAG,gBAAgB,MAAM;CACzB,eAAe,MAAe,IAAc,MAAY,KAAmB;EACzE,MAAM,IAAI;EACV,MAAM,OAAO,EAAE;EACf,MAAM,iBAAiB,EAAE,YAAY;EAMrC,MAAM,aAAa,KAAK,IACtB,gBACA,GAAI,EAAE,MAAM,KAAK,MAAM,EAAE,YAAY,cAAc,KAAK,CAAC,CAC3D;EACA,MAAM,aAAa,EAAE,cAAc;EACnC,MAAM,aAAa,EAAE,OAAO,SAAS;EACrC,MAAM,aAAa,EAAE,cAAc;EACnC,MAAM,kBAAkB,EAAE;EAE1B,GAAG,gBAAgB,OAAO,cAAc;GACtC,MAAM,oBAAoB;IACxB,QAAQ,WAAR;KACE,KAAK,KAAK,wBACR,OAAO,OAAO;KAChB,KAAK,KAAK;KACV,KAAK,KAAK,sBACR,OAAO;KACT,SACE,OAAO,OAAO;IAClB;GACF,EAAA,CAAG;GAEH,MAAM,EAAE,SAAS,aAAa,YAC5B,MACA,YACA;IACE;IACA;IACA;IACA;IACA;GACF,GACA,IAAI,mBACN;GAEA,OAAO;IAAE,OAAO;IAAS,QAAQ;GAAS;EAC5C,CAAC;CACH;CACA,OAAO,MAAM,KAAK;EAChB,eAAe,MAAgD,GAAG;CACpE;AACF"}
1
+ {"version":3,"file":"text.js","names":[],"sources":["../../../src/registry/definitions/text.ts"],"sourcesContent":["import type { POMNode } from \"../../types.ts\";\nimport type { NodeDefinition, Yoga } from \"../types.ts\";\nimport type { Node as YogaNode } from \"yoga-layout\";\nimport { measureText } from \"../../calcYogaLayout/measureText.ts\";\nimport type { BuildContext } from \"../../buildContext.ts\";\nimport { renderTextNode } from \"../../renderPptx/nodes/text.ts\";\nimport { getNodeMetadata } from \"../nodeMetadata.ts\";\n\nexport const textNodeDef: NodeDefinition = {\n ...getNodeMetadata(\"text\"),\n applyYogaStyle(node: POMNode, yn: YogaNode, yoga: Yoga, ctx: BuildContext) {\n const n = node as Extract<POMNode, { type: \"text\" }>;\n const text = n.text;\n const baseFontSizePx = n.fontSize ?? 24;\n // runs に fontSize override がある場合は最大値で計測する(描画は run 単位で\n // 各自の fontSize が適用されるが、計測関数は単一 fontSize しか扱えないので\n // 最大値を採用して縦方向の clipping を防ぐ。\n // 横方向は最大値だと過剰評価になるが、典型ケース (大きな数字 + 小さい単位)\n // では小さい unit 部分が短く影響は軽微で、安全側に倒す)\n const fontSizePx = Math.max(\n baseFontSizePx,\n ...(n.runs?.map((r) => r.fontSize ?? baseFontSizePx) ?? []),\n );\n const fontFamily = n.fontFamily ?? \"Noto Sans JP\";\n const fontWeight = n.bold ? \"bold\" : \"normal\";\n const lineHeight = n.lineHeight ?? 1.3;\n const letterSpacingPx = n.letterSpacing;\n\n yn.setMeasureFunc((width, widthMode) => {\n const maxWidthPx = (() => {\n switch (widthMode) {\n case yoga.MEASURE_MODE_UNDEFINED:\n return Number.POSITIVE_INFINITY;\n case yoga.MEASURE_MODE_EXACTLY:\n case yoga.MEASURE_MODE_AT_MOST:\n return width;\n default:\n return Number.POSITIVE_INFINITY;\n }\n })();\n\n const { widthPx, heightPx } = measureText(\n text,\n maxWidthPx,\n {\n fontFamily,\n fontSizePx,\n lineHeight,\n fontWeight,\n letterSpacingPx,\n },\n ctx.textMeasurementMode,\n ctx.fontRegistry,\n );\n\n return { width: widthPx, height: heightPx };\n });\n },\n render(node, ctx) {\n renderTextNode(node as Extract<typeof node, { type: \"text\" }>, ctx);\n },\n};\n"],"mappings":";;;;AAQA,MAAa,cAA8B;CACzC,GAAG,gBAAgB,MAAM;CACzB,eAAe,MAAe,IAAc,MAAY,KAAmB;EACzE,MAAM,IAAI;EACV,MAAM,OAAO,EAAE;EACf,MAAM,iBAAiB,EAAE,YAAY;EAMrC,MAAM,aAAa,KAAK,IACtB,gBACA,GAAI,EAAE,MAAM,KAAK,MAAM,EAAE,YAAY,cAAc,KAAK,CAAC,CAC3D;EACA,MAAM,aAAa,EAAE,cAAc;EACnC,MAAM,aAAa,EAAE,OAAO,SAAS;EACrC,MAAM,aAAa,EAAE,cAAc;EACnC,MAAM,kBAAkB,EAAE;EAE1B,GAAG,gBAAgB,OAAO,cAAc;GACtC,MAAM,oBAAoB;IACxB,QAAQ,WAAR;KACE,KAAK,KAAK,wBACR,OAAO,OAAO;KAChB,KAAK,KAAK;KACV,KAAK,KAAK,sBACR,OAAO;KACT,SACE,OAAO,OAAO;IAClB;GACF,EAAA,CAAG;GAEH,MAAM,EAAE,SAAS,aAAa,YAC5B,MACA,YACA;IACE;IACA;IACA;IACA;IACA;GACF,GACA,IAAI,qBACJ,IAAI,YACN;GAEA,OAAO;IAAE,OAAO;IAAS,QAAQ;GAAS;EAC5C,CAAC;CACH;CACA,OAAO,MAAM,KAAK;EAChB,eAAe,MAAgD,GAAG;CACpE;AACF"}
@@ -0,0 +1,101 @@
1
+ import { createPptxAuthoringSession } from "@pptx-glimpse/document";
2
+ //#region src/renderPptx/authoringContext.ts
3
+ /** Mutable state needed only while authoring a PPTX. */
4
+ var PptxAuthoringContext = class {
5
+ useLayoutTextMargins;
6
+ session;
7
+ currentTargetHandle;
8
+ currentTarget;
9
+ textCount = 0;
10
+ shapeCount = 0;
11
+ pictureCount = 0;
12
+ tableCount = 0;
13
+ chartCount = 0;
14
+ connectorCount = 0;
15
+ constructor(source, useLayoutTextMargins = false) {
16
+ this.useLayoutTextMargins = useLayoutTextMargins;
17
+ this.session = createPptxAuthoringSession(source);
18
+ const firstSlideHandle = source.slides[0]?.handle;
19
+ if (firstSlideHandle) this.selectTarget(firstSlideHandle);
20
+ }
21
+ selectTarget(handle) {
22
+ this.currentTargetHandle = handle;
23
+ this.currentTarget = this.session.target(handle);
24
+ }
25
+ get source() {
26
+ return this.session.source;
27
+ }
28
+ addEmptySlideFromLayout(input) {
29
+ return this.session.addEmptySlideFromLayout(input);
30
+ }
31
+ get target() {
32
+ if (!this.currentTarget) throw new Error("glimpse slide or master is not selected");
33
+ return this.currentTarget;
34
+ }
35
+ addTextBox(input, name) {
36
+ return this.target.addTextBox({
37
+ ...input,
38
+ name: name ?? `Text ${++this.textCount}`
39
+ });
40
+ }
41
+ addShape(input, name) {
42
+ return this.target.addShape({
43
+ ...input,
44
+ name: name ?? `Shape ${++this.shapeCount}`
45
+ });
46
+ }
47
+ addConnector(input, name) {
48
+ return this.target.addConnector({
49
+ ...input,
50
+ name: name ?? `Connector ${++this.connectorCount}`
51
+ });
52
+ }
53
+ currentTargetShapeHandles() {
54
+ return this.currentTargetShapes().map((shape) => {
55
+ if (!shape.handle) throw new Error("authored shape handle was not found");
56
+ return shape.handle;
57
+ });
58
+ }
59
+ reorderCurrentTargetShapes(handles) {
60
+ this.target.reorderShapes(handles);
61
+ }
62
+ addPicture(input, name) {
63
+ this.target.addPicture({
64
+ ...input,
65
+ name: name ?? `Picture ${++this.pictureCount}`
66
+ });
67
+ }
68
+ addTable(input, name) {
69
+ this.target.addTable({
70
+ ...input,
71
+ name: name ?? `Table ${++this.tableCount}`
72
+ });
73
+ }
74
+ addChart(input, name) {
75
+ this.target.addChart({
76
+ ...input,
77
+ name: name ?? `Chart ${++this.chartCount}`
78
+ });
79
+ }
80
+ addSlideNumber(input) {
81
+ this.target.addSlideNumber(input);
82
+ }
83
+ setSlideBackground(background) {
84
+ this.target.setSlideBackground(background);
85
+ }
86
+ currentTargetShapes() {
87
+ const partPath = this.currentTargetHandle?.partPath;
88
+ if (!partPath) throw new Error("glimpse slide or master is not selected");
89
+ const target = [
90
+ ...this.source.slides,
91
+ ...this.source.slideLayouts,
92
+ ...this.source.slideMasters
93
+ ].find((candidate) => candidate.partPath === partPath);
94
+ if (!target) throw new Error("glimpse authoring target was not found");
95
+ return target.shapes;
96
+ }
97
+ };
98
+ //#endregion
99
+ export { PptxAuthoringContext };
100
+
101
+ //# sourceMappingURL=authoringContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authoringContext.js","names":[],"sources":["../../src/renderPptx/authoringContext.ts"],"sourcesContent":["import {\n createPptxAuthoringSession,\n type AddChartInput,\n type AddConnectorInput,\n type AddEmptySlideFromLayoutInput,\n type AddPictureInput,\n type AddShapeInput,\n type AddSlideNumberInput,\n type AddTableInput,\n type AddTextBoxInput,\n type PptxAuthoringSession,\n type PptxAuthoringTarget,\n type PptxSourceModel,\n type SourceHandle,\n type SourceShapeNode,\n} from \"@pptx-glimpse/document\";\n\n/** Mutable state needed only while authoring a PPTX. */\nexport class PptxAuthoringContext {\n private readonly session: PptxAuthoringSession;\n private currentTargetHandle: SourceHandle | undefined;\n private currentTarget: PptxAuthoringTarget | undefined;\n private textCount = 0;\n private shapeCount = 0;\n private pictureCount = 0;\n private tableCount = 0;\n private chartCount = 0;\n private connectorCount = 0;\n\n constructor(\n source: PptxSourceModel,\n readonly useLayoutTextMargins = false,\n ) {\n this.session = createPptxAuthoringSession(source);\n const firstSlideHandle = source.slides[0]?.handle;\n if (firstSlideHandle) this.selectTarget(firstSlideHandle);\n }\n\n selectTarget(handle: SourceHandle): void {\n this.currentTargetHandle = handle;\n this.currentTarget = this.session.target(handle);\n }\n\n get source(): PptxSourceModel {\n return this.session.source;\n }\n\n addEmptySlideFromLayout(input: AddEmptySlideFromLayoutInput): SourceHandle {\n return this.session.addEmptySlideFromLayout(input);\n }\n\n private get target(): PptxAuthoringTarget {\n if (!this.currentTarget)\n throw new Error(\"glimpse slide or master is not selected\");\n return this.currentTarget;\n }\n\n addTextBox(input: AddTextBoxInput, name?: string): SourceHandle {\n return this.target.addTextBox({\n ...input,\n name: name ?? `Text ${++this.textCount}`,\n });\n }\n\n addShape(input: AddShapeInput, name?: string): SourceHandle {\n return this.target.addShape({\n ...input,\n name: name ?? `Shape ${++this.shapeCount}`,\n });\n }\n\n addConnector(input: AddConnectorInput, name?: string): SourceHandle {\n return this.target.addConnector({\n ...input,\n name: name ?? `Connector ${++this.connectorCount}`,\n });\n }\n\n currentTargetShapeHandles(): readonly SourceHandle[] {\n return this.currentTargetShapes().map((shape) => {\n if (!shape.handle) throw new Error(\"authored shape handle was not found\");\n return shape.handle;\n });\n }\n\n reorderCurrentTargetShapes(handles: readonly SourceHandle[]): void {\n this.target.reorderShapes(handles);\n }\n\n addPicture(input: AddPictureInput, name?: string): void {\n this.target.addPicture({\n ...input,\n name: name ?? `Picture ${++this.pictureCount}`,\n });\n }\n\n addTable(input: AddTableInput, name?: string): void {\n this.target.addTable({\n ...input,\n name: name ?? `Table ${++this.tableCount}`,\n });\n }\n\n addChart(input: AddChartInput, name?: string): void {\n this.target.addChart({\n ...input,\n name: name ?? `Chart ${++this.chartCount}`,\n });\n }\n\n addSlideNumber(input: AddSlideNumberInput): void {\n this.target.addSlideNumber(input);\n }\n\n setSlideBackground(\n background: Parameters<PptxAuthoringTarget[\"setSlideBackground\"]>[0],\n ): void {\n this.target.setSlideBackground(background);\n }\n\n private currentTargetShapes(): readonly SourceShapeNode[] {\n const partPath = this.currentTargetHandle?.partPath;\n if (!partPath) throw new Error(\"glimpse slide or master is not selected\");\n const target = [\n ...this.source.slides,\n ...this.source.slideLayouts,\n ...this.source.slideMasters,\n ].find((candidate) => candidate.partPath === partPath);\n if (!target) throw new Error(\"glimpse authoring target was not found\");\n return target.shapes;\n }\n}\n"],"mappings":";;;AAkBA,IAAa,uBAAb,MAAkC;CAarB;CAZX;CACA;CACA;CACA,YAAoB;CACpB,aAAqB;CACrB,eAAuB;CACvB,aAAqB;CACrB,aAAqB;CACrB,iBAAyB;CAEzB,YACE,QACA,uBAAgC,OAChC;EADS,KAAA,uBAAA;EAET,KAAK,UAAU,2BAA2B,MAAM;EAChD,MAAM,mBAAmB,OAAO,OAAO,EAAE,EAAE;EAC3C,IAAI,kBAAkB,KAAK,aAAa,gBAAgB;CAC1D;CAEA,aAAa,QAA4B;EACvC,KAAK,sBAAsB;EAC3B,KAAK,gBAAgB,KAAK,QAAQ,OAAO,MAAM;CACjD;CAEA,IAAI,SAA0B;EAC5B,OAAO,KAAK,QAAQ;CACtB;CAEA,wBAAwB,OAAmD;EACzE,OAAO,KAAK,QAAQ,wBAAwB,KAAK;CACnD;CAEA,IAAY,SAA8B;EACxC,IAAI,CAAC,KAAK,eACR,MAAM,IAAI,MAAM,yCAAyC;EAC3D,OAAO,KAAK;CACd;CAEA,WAAW,OAAwB,MAA6B;EAC9D,OAAO,KAAK,OAAO,WAAW;GAC5B,GAAG;GACH,MAAM,QAAQ,QAAQ,EAAE,KAAK;EAC/B,CAAC;CACH;CAEA,SAAS,OAAsB,MAA6B;EAC1D,OAAO,KAAK,OAAO,SAAS;GAC1B,GAAG;GACH,MAAM,QAAQ,SAAS,EAAE,KAAK;EAChC,CAAC;CACH;CAEA,aAAa,OAA0B,MAA6B;EAClE,OAAO,KAAK,OAAO,aAAa;GAC9B,GAAG;GACH,MAAM,QAAQ,aAAa,EAAE,KAAK;EACpC,CAAC;CACH;CAEA,4BAAqD;EACnD,OAAO,KAAK,oBAAoB,CAAC,CAAC,KAAK,UAAU;GAC/C,IAAI,CAAC,MAAM,QAAQ,MAAM,IAAI,MAAM,qCAAqC;GACxE,OAAO,MAAM;EACf,CAAC;CACH;CAEA,2BAA2B,SAAwC;EACjE,KAAK,OAAO,cAAc,OAAO;CACnC;CAEA,WAAW,OAAwB,MAAqB;EACtD,KAAK,OAAO,WAAW;GACrB,GAAG;GACH,MAAM,QAAQ,WAAW,EAAE,KAAK;EAClC,CAAC;CACH;CAEA,SAAS,OAAsB,MAAqB;EAClD,KAAK,OAAO,SAAS;GACnB,GAAG;GACH,MAAM,QAAQ,SAAS,EAAE,KAAK;EAChC,CAAC;CACH;CAEA,SAAS,OAAsB,MAAqB;EAClD,KAAK,OAAO,SAAS;GACnB,GAAG;GACH,MAAM,QAAQ,SAAS,EAAE,KAAK;EAChC,CAAC;CACH;CAEA,eAAe,OAAkC;EAC/C,KAAK,OAAO,eAAe,KAAK;CAClC;CAEA,mBACE,YACM;EACN,KAAK,OAAO,mBAAmB,UAAU;CAC3C;CAEA,sBAA0D;EACxD,MAAM,WAAW,KAAK,qBAAqB;EAC3C,IAAI,CAAC,UAAU,MAAM,IAAI,MAAM,yCAAyC;EACxE,MAAM,SAAS;GACb,GAAG,KAAK,OAAO;GACf,GAAG,KAAK,OAAO;GACf,GAAG,KAAK,OAAO;EACjB,CAAC,CAAC,MAAM,cAAc,UAAU,aAAa,QAAQ;EACrD,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,wCAAwC;EACrE,OAAO,OAAO;CAChB;AACF"}
@@ -1,8 +1,8 @@
1
1
  import { parseGradient, parseLinearGradient } from "../shared/gradient.js";
2
2
  import { EMU_PER_IN, pxToEmu, pxToPt } from "./units.js";
3
3
  import { createTextOptions, resolveSubSup } from "./textOptions.js";
4
- import { addChart, addPicture, addShape, addTable, addTextBox, asEmu, asHundredthPt, asOoxmlAngle, asOoxmlPercent, asPt, createPptx, setSlideBackground } from "@pptx-glimpse/document";
5
- //#region src/renderPptx/pptxAuthoring.ts
4
+ import { asEmu, asHundredthPt, asOoxmlAngle, asOoxmlPercent, asPt } from "@pptx-glimpse/document";
5
+ //#region src/renderPptx/glimpseAdapter.ts
6
6
  function cleanHex(color) {
7
7
  const hex = color?.replace(/^#/, "").toUpperCase();
8
8
  return hex?.length === 3 ? [...hex].map((character) => character.repeat(2)).join("") : hex;
@@ -69,9 +69,6 @@ function toTextGradientInput(value) {
69
69
  }))
70
70
  };
71
71
  }
72
- function stripUndefined(value) {
73
- return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== void 0));
74
- }
75
72
  function resolveUnderline(node, run) {
76
73
  if (run?.underline !== void 0) return run.underline;
77
74
  if (node.underline !== void 0) return node.underline;
@@ -80,28 +77,59 @@ function resolveUnderline(node, run) {
80
77
  function buildRunProperties(node, run, gradientFill) {
81
78
  const fontSizePx = run?.fontSize ?? node.fontSize ?? 24;
82
79
  const subSup = run ? resolveSubSup(run, node) : node;
83
- return stripUndefined({
84
- fontFace: run?.fontFamily ?? node.fontFamily ?? "Noto Sans JP",
85
- fontSize: asPt(pxToPt(fontSizePx)),
86
- color: gradientFill ? void 0 : toColorInput(run?.color ?? node.color),
80
+ return createGlimpseRunProperties({
81
+ fontFace: run?.fontFamily ?? node.fontFamily,
82
+ fontSize: fontSizePx,
83
+ color: run?.color ?? node.color,
87
84
  gradientFill,
88
85
  bold: run?.bold ?? node.bold,
89
86
  italic: run?.italic ?? node.italic,
90
- underline: toUnderlineInput(resolveUnderline(node, run)),
87
+ underline: resolveUnderline(node, run),
91
88
  strike: run?.strike ?? node.strike,
92
- baseline: toBaselineInput(subSup.subscript, subSup.superscript),
93
- highlight: toColorInput(run?.highlight ?? node.highlight),
94
- glow: toGlowInput(node.glow),
95
- outline: toOutlineInput(node.outline),
96
- charSpacing: toCharSpacing(run?.letterSpacing ?? node.letterSpacing)
89
+ subscript: subSup.subscript,
90
+ superscript: subSup.superscript,
91
+ highlight: run?.highlight ?? node.highlight,
92
+ glow: node.glow,
93
+ outline: node.outline,
94
+ letterSpacing: run?.letterSpacing ?? node.letterSpacing
97
95
  });
98
96
  }
97
+ function createGlimpseRunProperties(style) {
98
+ return {
99
+ fontFace: style.fontFace ?? "Noto Sans JP",
100
+ fontSize: asPt(pxToPt(style.fontSize ?? 24)),
101
+ color: style.gradientFill ? void 0 : toColorInput(style.color),
102
+ gradientFill: style.gradientFill,
103
+ bold: style.bold,
104
+ italic: style.italic,
105
+ underline: toUnderlineInput(style.underline),
106
+ strike: style.strike,
107
+ baseline: toBaselineInput(style.subscript, style.superscript),
108
+ highlight: toColorInput(style.highlight),
109
+ glow: toGlowInput(style.glow),
110
+ outline: toOutlineInput(style.outline),
111
+ charSpacing: toCharSpacing(style.letterSpacing)
112
+ };
113
+ }
114
+ function createGlimpseShapeRunProperties(style) {
115
+ return {
116
+ ...createGlimpseRunProperties(style),
117
+ baseline: style.subscript ? "subscript" : style.superscript ? "superscript" : void 0
118
+ };
119
+ }
120
+ function createGlimpseTableRunProperties(style) {
121
+ return {
122
+ ...createGlimpseRunProperties(style),
123
+ fontFace: style.fontFace,
124
+ color: cleanHex(style.color)
125
+ };
126
+ }
99
127
  function buildParagraphs(node) {
100
128
  const gradientFill = toTextGradientInput(node.textGradient);
101
129
  const sourceRuns = node.runs && node.runs.length > 0 ? node.runs.map((run) => ({
102
130
  text: run.text,
103
131
  properties: buildRunProperties(node, run, gradientFill),
104
- href: run.href
132
+ hyperlink: run.href
105
133
  })) : [{
106
134
  text: node.text ?? "",
107
135
  properties: buildRunProperties(node, void 0, gradientFill)
@@ -127,10 +155,28 @@ function buildParagraphs(node) {
127
155
  runs: runs.map((run) => ({
128
156
  text: run.text,
129
157
  properties: run.properties,
130
- hyperlink: run.href
158
+ hyperlink: run.hyperlink
131
159
  }))
132
160
  }));
133
161
  }
162
+ function createTextNodeInput(node, useLayoutTextMargins) {
163
+ const textOptions = createTextOptions(node);
164
+ return {
165
+ offsetX: asEmu(Math.round(textOptions.x * EMU_PER_IN)),
166
+ offsetY: asEmu(Math.round(textOptions.y * EMU_PER_IN)),
167
+ width: asEmu(Math.round(textOptions.w * EMU_PER_IN)),
168
+ height: asEmu(Math.round(textOptions.h * EMU_PER_IN)),
169
+ rotation: node.rotate === void 0 ? void 0 : asOoxmlAngle(Math.round(node.rotate * 6e4)),
170
+ body: useLayoutTextMargins ? void 0 : {
171
+ anchor: "top",
172
+ marginLeft: asEmu(0),
173
+ marginRight: asEmu(0),
174
+ marginTop: asEmu(0),
175
+ marginBottom: asEmu(0)
176
+ },
177
+ paragraphs: buildParagraphs(node)
178
+ };
179
+ }
134
180
  function toGradientFill(value, opacity) {
135
181
  const gradient = parseGradient(value);
136
182
  if (!gradient) return void 0;
@@ -238,144 +284,29 @@ function enrichShapeInput(input, options) {
238
284
  flipVertical: options?.flipV ?? input.flipVertical
239
285
  };
240
286
  }
241
- function applyHyperlinks(input, hyperlinks) {
242
- if (!hyperlinks?.some(Boolean) || !input.paragraphs) return input;
243
- let index = 0;
287
+ function enrichPictureInput(input, shadow) {
244
288
  return {
245
289
  ...input,
246
- paragraphs: input.paragraphs.map((paragraph) => ({
247
- ...paragraph,
248
- runs: paragraph.runs.map((run) => ({
249
- ...run,
250
- hyperlink: hyperlinks[index++]
251
- }))
252
- }))
290
+ effects: toShadowEffects(shadow)
291
+ };
292
+ }
293
+ function toSlideBackgroundGradient(backgroundGradient, opacity) {
294
+ const fill = toGradientFill(backgroundGradient, opacity);
295
+ if (!fill || fill.kind !== "gradient") return void 0;
296
+ return fill.gradientType === "linear" ? {
297
+ kind: "gradient",
298
+ gradientType: "linear",
299
+ stops: fill.stops,
300
+ angle: fill.angle ?? asOoxmlAngle(0)
301
+ } : {
302
+ kind: "gradient",
303
+ gradientType: "radial",
304
+ stops: fill.stops,
305
+ centerX: fill.centerX,
306
+ centerY: fill.centerY
253
307
  };
254
308
  }
255
- var PptxAuthoringRegistry = class {
256
- currentSource;
257
- currentSlideHandle;
258
- useLayoutTextMargins = false;
259
- textCount = 0;
260
- shapeCount = 0;
261
- pictureCount = 0;
262
- tableCount = 0;
263
- chartCount = 0;
264
- constructor() {
265
- const source = createPptx();
266
- this.currentSource = source;
267
- this.currentSlideHandle = source.slides[0]?.handle;
268
- }
269
- initialize(source, useLayoutTextMargins = false) {
270
- this.currentSource = source;
271
- this.useLayoutTextMargins = useLayoutTextMargins;
272
- }
273
- selectSlide(handle) {
274
- this.currentSlideHandle = handle;
275
- }
276
- get source() {
277
- if (!this.currentSource) throw new Error("glimpse authoring is not initialized");
278
- return this.currentSource;
279
- }
280
- get entries() {
281
- return (this.source.edits ?? []).flatMap((edit) => (edit.kind === "addTextBox" || edit.kind === "addShape") && "xml" in edit ? [{
282
- kind: "shape",
283
- xml: edit.xml
284
- }] : []);
285
- }
286
- replaceSource(source) {
287
- this.currentSource = source;
288
- }
289
- get target() {
290
- if (!this.currentSlideHandle) throw new Error("glimpse slide is not selected");
291
- return this.currentSlideHandle;
292
- }
293
- register(node) {
294
- const textOptions = createTextOptions(node);
295
- this.registerTextBox({
296
- offsetX: asEmu(Math.round(textOptions.x * EMU_PER_IN)),
297
- offsetY: asEmu(Math.round(textOptions.y * EMU_PER_IN)),
298
- width: asEmu(Math.round(textOptions.w * EMU_PER_IN)),
299
- height: asEmu(Math.round(textOptions.h * EMU_PER_IN)),
300
- rotation: node.rotate === void 0 ? void 0 : asOoxmlAngle(Math.round(node.rotate * 6e4)),
301
- body: this.useLayoutTextMargins ? void 0 : {
302
- anchor: "top",
303
- marginLeft: asEmu(0),
304
- marginRight: asEmu(0),
305
- marginTop: asEmu(0),
306
- marginBottom: asEmu(0)
307
- },
308
- paragraphs: buildParagraphs(node)
309
- });
310
- }
311
- registerTextBox(input, options) {
312
- const name = options?.name ?? `Text ${++this.textCount}`;
313
- this.currentSource = addTextBox(this.source, this.target, applyHyperlinks({
314
- ...input,
315
- name
316
- }, options?.hyperlinks));
317
- }
318
- registerShape(input, options) {
319
- const name = options?.name ?? `Shape ${++this.shapeCount}`;
320
- this.currentSource = addShape(this.source, this.target, enrichShapeInput({
321
- ...input,
322
- name
323
- }, options));
324
- }
325
- registerPicture(input, options) {
326
- const name = options?.name ?? `Picture ${++this.pictureCount}`;
327
- this.currentSource = addPicture(this.source, this.target, {
328
- ...input,
329
- name,
330
- effects: toShadowEffects(options?.shadow)
331
- });
332
- }
333
- registerTable(input, options) {
334
- const name = options?.name ?? `Table ${++this.tableCount}`;
335
- this.currentSource = addTable(this.source, this.target, {
336
- ...input,
337
- name
338
- });
339
- }
340
- registerChart(input, options) {
341
- const name = options?.name ?? `Chart ${++this.chartCount}`;
342
- this.currentSource = addChart(this.source, this.target, {
343
- ...input,
344
- name
345
- });
346
- }
347
- setSlideBackgroundGradient(backgroundGradient, opacity) {
348
- const fill = toGradientFill(backgroundGradient, opacity);
349
- if (!fill || fill.kind !== "gradient") return false;
350
- const background = fill.gradientType === "linear" ? {
351
- kind: "gradient",
352
- gradientType: "linear",
353
- stops: fill.stops,
354
- angle: fill.angle ?? asOoxmlAngle(0)
355
- } : {
356
- kind: "gradient",
357
- gradientType: "radial",
358
- stops: fill.stops,
359
- centerX: fill.centerX,
360
- centerY: fill.centerY
361
- };
362
- this.currentSource = setSlideBackground(this.source, this.target, background);
363
- return true;
364
- }
365
- setSlideBackgroundSolid(color) {
366
- this.currentSource = setSlideBackground(this.source, this.target, {
367
- kind: "solid",
368
- color: toColorInput(color)
369
- });
370
- }
371
- setSlideBackgroundImage(bytes) {
372
- this.currentSource = setSlideBackground(this.source, this.target, {
373
- kind: "image",
374
- bytes
375
- });
376
- }
377
- };
378
309
  //#endregion
379
- export { PptxAuthoringRegistry, cleanHex, toColorInput };
310
+ export { cleanHex, createGlimpseRunProperties, createGlimpseShapeRunProperties, createGlimpseTableRunProperties, createTextNodeInput, enrichPictureInput, enrichShapeInput, toColorInput, toSlideBackgroundGradient };
380
311
 
381
- //# sourceMappingURL=pptxAuthoring.js.map
312
+ //# sourceMappingURL=glimpseAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glimpseAdapter.js","names":[],"sources":["../../src/renderPptx/glimpseAdapter.ts"],"sourcesContent":["import {\n asEmu,\n asHundredthPt,\n asOoxmlAngle,\n asOoxmlPercent,\n asPt,\n type AddPictureInput,\n type AddShapeColorInput,\n type AddShapeCustomGeometryPathCommandInput,\n type AddShapeEffectsInput,\n type AddShapeFillInput,\n type AddShapeGeometryInput,\n type AddShapeInput,\n type AddShapeOutlineInput,\n type AddShapeRunPropertiesInput,\n type AddTableRunPropertiesInput,\n type AddTextBoxGradientFillInput,\n type AddTextBoxInput,\n type AddTextBoxParagraphInput,\n type AddTextBoxRunPropertiesInput,\n} from \"@pptx-glimpse/document\";\nimport { parseGradient, parseLinearGradient } from \"../shared/gradient.ts\";\nimport type {\n BorderStyle,\n PositionedNode,\n ShadowStyle,\n TextGlow,\n TextOutline,\n Underline,\n} from \"../types.ts\";\nimport { createTextOptions, resolveSubSup } from \"./textOptions.ts\";\nimport { EMU_PER_IN, pxToEmu, pxToPt } from \"./units.ts\";\n\n/** Pure POM style / geometry conversions for glimpse authoring inputs. */\n\ntype TextPositionedNode = Extract<PositionedNode, { type: \"text\" }>;\n\ninterface GlimpseTextRun {\n text: string;\n properties: AddTextBoxRunPropertiesInput;\n hyperlink?: string;\n}\n\nexport type GlimpseTextRunStyle = {\n fontSize?: number;\n fontFace?: string;\n color?: string;\n bold?: boolean;\n italic?: boolean;\n underline?: Underline;\n strike?: boolean;\n subscript?: boolean;\n superscript?: boolean;\n highlight?: string;\n glow?: TextGlow;\n outline?: TextOutline;\n letterSpacing?: number;\n gradientFill?: AddTextBoxGradientFillInput;\n};\n\nexport function cleanHex(color: string | undefined): string | undefined {\n const hex = color?.replace(/^#/, \"\").toUpperCase();\n return hex?.length === 3\n ? [...hex].map((character) => character.repeat(2)).join(\"\")\n : hex;\n}\n\nexport function toColorInput(\n color: string | undefined,\n opacity?: number,\n): AddShapeColorInput | undefined {\n const hex = cleanHex(color);\n if (!hex) return undefined;\n return {\n kind: \"srgb\",\n hex,\n transforms:\n opacity === undefined\n ? undefined\n : [\n {\n kind: \"alpha\",\n value: asOoxmlPercent(Math.round(opacity * 100000)),\n },\n ],\n };\n}\n\nfunction toUnderlineInput(underline: Underline | undefined) {\n if (underline === undefined || underline === false) return undefined;\n if (underline === true) return true;\n return {\n style: underline.style,\n color: toColorInput(underline.color),\n };\n}\n\nfunction toBaselineInput(\n subscript: boolean | undefined,\n superscript: boolean | undefined,\n) {\n if (subscript) {\n return {\n type: \"percent\" as const,\n value: asOoxmlPercent(-40000),\n };\n }\n if (superscript) {\n return {\n type: \"percent\" as const,\n value: asOoxmlPercent(30000),\n };\n }\n return undefined;\n}\n\nfunction toGlowInput(glow: TextGlow | undefined) {\n if (!glow) return undefined;\n return {\n radius: asEmu(Math.round(pxToEmu(glow.size ?? 8))),\n color: toColorInput(glow.color ?? \"FFFFFF\", glow.opacity ?? 0.75)!,\n };\n}\n\nfunction toOutlineInput(outline: TextOutline | undefined) {\n if (!outline) return undefined;\n return {\n width: asEmu(Math.round(pxToEmu(outline.size ?? 1))),\n color: toColorInput(outline.color ?? \"FFFFFF\"),\n };\n}\n\nfunction toCharSpacing(letterSpacingPx: number | undefined) {\n if (letterSpacingPx === undefined) return undefined;\n return Math.round(pxToPt(letterSpacingPx) * 100);\n}\n\nfunction toTextGradientInput(\n value: string | undefined,\n): AddTextBoxGradientFillInput | undefined {\n if (!value) return undefined;\n const linear = parseLinearGradient(value);\n if (!linear) return undefined;\n const dmlAngle = (((linear.angle - 90) % 360) + 360) % 360;\n return {\n gradientType: \"linear\",\n angle: asOoxmlAngle(Math.round(dmlAngle * 60000)),\n stops: linear.stops.map((stop) => ({\n position: asOoxmlPercent(Math.round(stop.position * 1000)),\n color: toColorInput(stop.color)!,\n })),\n };\n}\n\nfunction resolveUnderline(\n node: TextPositionedNode,\n run: NonNullable<TextPositionedNode[\"runs\"]>[number] | undefined,\n): Underline | undefined {\n if (run?.underline !== undefined) return run.underline;\n if (node.underline !== undefined) return node.underline;\n return run?.href ? true : undefined;\n}\n\nfunction buildRunProperties(\n node: TextPositionedNode,\n run: NonNullable<TextPositionedNode[\"runs\"]>[number] | undefined,\n gradientFill: AddTextBoxGradientFillInput | undefined,\n): AddTextBoxRunPropertiesInput {\n const fontSizePx = run?.fontSize ?? node.fontSize ?? 24;\n const subSup = run ? resolveSubSup(run, node) : node;\n return createGlimpseRunProperties({\n fontFace: run?.fontFamily ?? node.fontFamily,\n fontSize: fontSizePx,\n color: run?.color ?? node.color,\n gradientFill,\n bold: run?.bold ?? node.bold,\n italic: run?.italic ?? node.italic,\n underline: resolveUnderline(node, run),\n strike: run?.strike ?? node.strike,\n subscript: subSup.subscript,\n superscript: subSup.superscript,\n highlight: run?.highlight ?? node.highlight,\n glow: node.glow,\n outline: node.outline,\n letterSpacing: run?.letterSpacing ?? node.letterSpacing,\n });\n}\n\nexport function createGlimpseRunProperties(\n style: GlimpseTextRunStyle,\n): AddTextBoxRunPropertiesInput {\n return {\n fontFace: style.fontFace ?? \"Noto Sans JP\",\n fontSize: asPt(pxToPt(style.fontSize ?? 24)),\n color: style.gradientFill ? undefined : toColorInput(style.color),\n gradientFill: style.gradientFill,\n bold: style.bold,\n italic: style.italic,\n underline: toUnderlineInput(style.underline),\n strike: style.strike,\n baseline: toBaselineInput(style.subscript, style.superscript),\n highlight: toColorInput(style.highlight),\n glow: toGlowInput(style.glow),\n outline: toOutlineInput(style.outline),\n charSpacing: toCharSpacing(style.letterSpacing),\n };\n}\n\nexport function createGlimpseShapeRunProperties(\n style: GlimpseTextRunStyle,\n): AddShapeRunPropertiesInput {\n const properties = createGlimpseRunProperties(style);\n return {\n ...properties,\n baseline: style.subscript\n ? \"subscript\"\n : style.superscript\n ? \"superscript\"\n : undefined,\n };\n}\n\nexport function createGlimpseTableRunProperties(\n style: GlimpseTextRunStyle,\n): AddTableRunPropertiesInput {\n const properties = createGlimpseRunProperties(style);\n return {\n ...properties,\n fontFace: style.fontFace,\n color: cleanHex(style.color),\n };\n}\n\nfunction buildParagraphs(node: TextPositionedNode): AddTextBoxParagraphInput[] {\n const gradientFill = toTextGradientInput(node.textGradient);\n const sourceRuns: GlimpseTextRun[] =\n node.runs && node.runs.length > 0\n ? node.runs.map((run) => ({\n text: run.text,\n properties: buildRunProperties(node, run, gradientFill),\n hyperlink: run.href,\n }))\n : [\n {\n text: node.text ?? \"\",\n properties: buildRunProperties(node, undefined, gradientFill),\n },\n ];\n const paragraphRuns: GlimpseTextRun[][] = [[]];\n for (const run of sourceRuns) {\n const lines = run.text.replace(/\\r*\\n/g, \"\\n\").split(\"\\n\");\n lines.forEach((line, index) => {\n if (index > 0) paragraphRuns.push([]);\n paragraphRuns.at(-1)?.push({ ...run, text: line });\n });\n }\n const lineHeight = node.lineHeight ?? 1.3;\n const fontSizePx = node.fontSize ?? 24;\n return paragraphRuns.map((runs) => ({\n properties: {\n align: node.textAlign,\n marginLeft: asEmu(0),\n indent: asEmu(0),\n bullet: { type: \"none\" },\n lineSpacing: asHundredthPt(\n Math.round(pxToPt(fontSizePx * lineHeight) * 100),\n ),\n },\n runs: runs.map((run) => ({\n text: run.text,\n properties: run.properties,\n hyperlink: run.hyperlink,\n })),\n }));\n}\n\nexport function createTextNodeInput(\n node: TextPositionedNode,\n useLayoutTextMargins: boolean,\n): AddTextBoxInput {\n const textOptions = createTextOptions(node);\n return {\n offsetX: asEmu(Math.round(textOptions.x * EMU_PER_IN)),\n offsetY: asEmu(Math.round(textOptions.y * EMU_PER_IN)),\n width: asEmu(Math.round(textOptions.w * EMU_PER_IN)),\n height: asEmu(Math.round(textOptions.h * EMU_PER_IN)),\n rotation:\n node.rotate === undefined\n ? undefined\n : asOoxmlAngle(Math.round(node.rotate * 60000)),\n body: useLayoutTextMargins\n ? undefined\n : {\n anchor: \"top\",\n marginLeft: asEmu(0),\n marginRight: asEmu(0),\n marginTop: asEmu(0),\n marginBottom: asEmu(0),\n },\n paragraphs: buildParagraphs(node),\n };\n}\n\nexport type CustomGeometryXmlInput = {\n width: number;\n height: number;\n points: readonly ({ x: number; y: number } | { close: true })[];\n};\n\nexport type GlimpseShapeXmlOptions = {\n fillColor?: string;\n fillOpacity?: number;\n backgroundGradient?: string;\n outlineGradient?: string;\n outlineOpacity?: number;\n glow?: TextGlow;\n shadow?: ShadowStyle;\n rectRadius?: number;\n dashType?: BorderStyle[\"dashType\"];\n flipH?: boolean;\n flipV?: boolean;\n zeroWidth?: boolean;\n zeroHeight?: boolean;\n customGeometry?: CustomGeometryXmlInput;\n};\n\nfunction toGradientFill(\n value: string,\n opacity?: number,\n): AddShapeFillInput | undefined {\n const gradient = parseGradient(value);\n if (!gradient) return undefined;\n const stops = gradient.value.stops.map((stop) => ({\n position: asOoxmlPercent(Math.round(stop.position * 1000)),\n color: toColorInput(stop.color, opacity)!,\n }));\n if (gradient.kind === \"linear\") {\n const dmlAngle = (((gradient.value.angle - 90) % 360) + 360) % 360;\n return {\n kind: \"gradient\",\n gradientType: \"linear\",\n angle: asOoxmlAngle(Math.round(dmlAngle * 60000)),\n stops,\n };\n }\n return {\n kind: \"gradient\",\n gradientType: \"radial\",\n centerX: asOoxmlPercent(Math.round(gradient.value.centerX * 1000)),\n centerY: asOoxmlPercent(Math.round(gradient.value.centerY * 1000)),\n stops,\n };\n}\n\nfunction withFillOpacity(\n fill: AddShapeFillInput | undefined,\n opacity: number | undefined,\n): AddShapeFillInput | undefined {\n if (!fill || opacity === undefined || fill.kind !== \"solid\") return fill;\n return {\n ...fill,\n color: toColorInput(fill.color.hex, opacity)!,\n };\n}\n\nfunction toShadowEffects(\n shadow: ShadowStyle | undefined,\n): AddShapeEffectsInput | undefined {\n if (!shadow) return undefined;\n const common = {\n blurRadius: asEmu(Math.round((shadow.blur ?? 3) * 12700)),\n distance: asEmu(Math.round((shadow.offset ?? 23000 / 12700) * 12700)),\n direction: asOoxmlAngle(Math.round((shadow.angle ?? 90) * 60000)),\n color: toColorInput(shadow.color ?? \"000000\", shadow.opacity ?? 0.35)!,\n };\n return shadow.type === \"inner\"\n ? { innerShadow: common }\n : {\n outerShadow: {\n ...common,\n alignment: \"bl\",\n rotateWithShape: true,\n },\n };\n}\n\nfunction customGeometry(\n input: CustomGeometryXmlInput,\n): AddShapeGeometryInput | undefined {\n const commands: AddShapeCustomGeometryPathCommandInput[] = [];\n let moved = false;\n for (const point of input.points) {\n if (\"close\" in point) {\n if (moved) commands.push({ kind: \"close\" });\n continue;\n }\n commands.push({\n kind: moved ? \"lineTo\" : \"moveTo\",\n x: Math.round(point.x * EMU_PER_IN),\n y: Math.round(point.y * EMU_PER_IN),\n });\n moved = true;\n }\n if (!moved) return undefined;\n return {\n kind: \"custom\",\n paths: [\n {\n width: Math.round(input.width * EMU_PER_IN),\n height: Math.round(input.height * EMU_PER_IN),\n commands,\n },\n ],\n };\n}\n\nexport function enrichShapeInput(\n input: AddShapeInput,\n options: GlimpseShapeXmlOptions | undefined,\n): AddShapeInput {\n const preset = input.geometry.kind === \"preset\" ? input.geometry.preset : \"\";\n const geometry = options?.customGeometry\n ? (customGeometry(options.customGeometry) ?? input.geometry)\n : preset === \"roundRect\" && options?.rectRadius !== undefined\n ? {\n ...input.geometry,\n adjustValues: {\n adj: Math.round(options.rectRadius * 50000),\n },\n }\n : input.geometry;\n const gradientFill = options?.backgroundGradient\n ? toGradientFill(options.backgroundGradient, options.fillOpacity)\n : undefined;\n const outlineGradient = options?.outlineGradient\n ? toGradientFill(\n options.outlineGradient,\n options.outlineOpacity ?? options.fillOpacity,\n )\n : undefined;\n const outline: AddShapeOutlineInput | undefined = input.outline\n ? {\n ...input.outline,\n fill:\n outlineGradient ??\n withFillOpacity(input.outline.fill, options?.outlineOpacity),\n dash: options?.dashType ?? input.outline.dash,\n }\n : outlineGradient\n ? { fill: outlineGradient }\n : undefined;\n const glow = options?.glow\n ? {\n radius: asEmu(Math.round(pxToEmu(options.glow.size ?? 8))),\n color: toColorInput(\n options.glow.color ?? \"FFFFFF\",\n options.glow.opacity ?? 0.75,\n )!,\n }\n : input.effects?.glow;\n const effects: AddShapeEffectsInput = {\n ...input.effects,\n ...toShadowEffects(options?.shadow),\n ...(glow ? { glow } : {}),\n };\n const width =\n preset === \"line\" && options?.zeroWidth ? asEmu(0) : input.width;\n let height =\n preset === \"line\" && options?.zeroHeight ? asEmu(0) : input.height;\n if (preset === \"line\" && width === 0 && height === 0) height = asEmu(1);\n return {\n ...input,\n geometry,\n width,\n height,\n fill: gradientFill ?? withFillOpacity(input.fill, options?.fillOpacity),\n outline,\n effects: Object.keys(effects).length > 0 ? effects : undefined,\n flipHorizontal: options?.flipH ?? input.flipHorizontal,\n flipVertical: options?.flipV ?? input.flipVertical,\n };\n}\n\nexport function enrichPictureInput(\n input: AddPictureInput,\n shadow: ShadowStyle | undefined,\n): AddPictureInput {\n return {\n ...input,\n effects: toShadowEffects(shadow),\n };\n}\n\nexport function toSlideBackgroundGradient(\n backgroundGradient: string,\n opacity?: number,\n) {\n const fill = toGradientFill(backgroundGradient, opacity);\n if (!fill || fill.kind !== \"gradient\") return undefined;\n return fill.gradientType === \"linear\"\n ? {\n kind: \"gradient\" as const,\n gradientType: \"linear\" as const,\n stops: fill.stops,\n angle: fill.angle ?? asOoxmlAngle(0),\n }\n : {\n kind: \"gradient\" as const,\n gradientType: \"radial\" as const,\n stops: fill.stops,\n centerX: fill.centerX,\n centerY: fill.centerY,\n };\n}\n"],"mappings":"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"}