@hirokisakabe/pom 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -11
- package/dist/autoFit/autoFit.d.ts +2 -1
- package/dist/autoFit/autoFit.d.ts.map +1 -1
- package/dist/autoFit/autoFit.js +7 -7
- package/dist/autoFit/strategies/reduceFontSize.js +1 -1
- package/dist/autoFit/strategies/reduceGapAndPadding.js +1 -1
- package/dist/autoFit/strategies/reduceTableRowHeight.js +1 -1
- package/dist/autoFit/strategies/uniformScale.js +1 -1
- package/dist/buildContext.d.ts +12 -0
- package/dist/buildContext.d.ts.map +1 -0
- package/dist/buildContext.js +8 -0
- package/dist/buildPptx.d.ts +1 -1
- package/dist/buildPptx.d.ts.map +1 -1
- package/dist/buildPptx.js +15 -15
- package/dist/calcYogaLayout/calcYogaLayout.d.ts +3 -1
- package/dist/calcYogaLayout/calcYogaLayout.d.ts.map +1 -1
- package/dist/calcYogaLayout/calcYogaLayout.js +43 -371
- package/dist/calcYogaLayout/measureText.d.ts +1 -5
- package/dist/calcYogaLayout/measureText.d.ts.map +1 -1
- package/dist/calcYogaLayout/measureText.js +2 -10
- package/dist/icons/renderIcon.d.ts +1 -1
- package/dist/icons/renderIcon.d.ts.map +1 -1
- package/dist/icons/renderIcon.js +3 -4
- package/dist/parseXml/coercionRules.d.ts +35 -0
- package/dist/parseXml/coercionRules.d.ts.map +1 -0
- package/dist/parseXml/coercionRules.js +479 -0
- package/dist/parseXml/inputSchema.d.ts +22 -105
- package/dist/parseXml/inputSchema.d.ts.map +1 -1
- package/dist/parseXml/inputSchema.js +5 -3
- package/dist/parseXml/parseXml.d.ts.map +1 -1
- package/dist/parseXml/parseXml.js +48 -277
- package/dist/registry/definitions/box.d.ts +3 -0
- package/dist/registry/definitions/box.d.ts.map +1 -0
- package/dist/registry/definitions/box.js +6 -0
- package/dist/registry/definitions/chart.d.ts +3 -0
- package/dist/registry/definitions/chart.d.ts.map +1 -0
- package/dist/registry/definitions/chart.js +8 -0
- package/dist/registry/definitions/compositeNodes.d.ts +8 -0
- package/dist/registry/definitions/compositeNodes.d.ts.map +1 -0
- package/dist/registry/definitions/compositeNodes.js +81 -0
- package/dist/registry/definitions/icon.d.ts +3 -0
- package/dist/registry/definitions/icon.d.ts.map +1 -0
- package/dist/registry/definitions/icon.js +50 -0
- package/dist/registry/definitions/image.d.ts +3 -0
- package/dist/registry/definitions/image.d.ts.map +1 -0
- package/dist/registry/definitions/image.js +34 -0
- package/dist/registry/definitions/layer.d.ts +3 -0
- package/dist/registry/definitions/layer.d.ts.map +1 -0
- package/dist/registry/definitions/layer.js +49 -0
- package/dist/registry/definitions/line.d.ts +3 -0
- package/dist/registry/definitions/line.d.ts.map +1 -0
- package/dist/registry/definitions/line.js +26 -0
- package/dist/registry/definitions/list.d.ts +4 -0
- package/dist/registry/definitions/list.d.ts.map +1 -0
- package/dist/registry/definitions/list.js +53 -0
- package/dist/registry/definitions/shape.d.ts +3 -0
- package/dist/registry/definitions/shape.d.ts.map +1 -0
- package/dist/registry/definitions/shape.js +37 -0
- package/dist/registry/definitions/stack.d.ts +4 -0
- package/dist/registry/definitions/stack.d.ts.map +1 -0
- package/dist/registry/definitions/stack.js +78 -0
- package/dist/registry/definitions/table.d.ts +3 -0
- package/dist/registry/definitions/table.d.ts.map +1 -0
- package/dist/registry/definitions/table.js +16 -0
- package/dist/registry/definitions/text.d.ts +3 -0
- package/dist/registry/definitions/text.d.ts.map +1 -0
- package/dist/registry/definitions/text.js +35 -0
- package/dist/registry/index.d.ts +2 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +34 -0
- package/dist/registry/nodeRegistry.d.ts +7 -0
- package/dist/registry/nodeRegistry.d.ts.map +1 -0
- package/dist/registry/nodeRegistry.js +13 -0
- package/dist/registry/types.d.ts +26 -0
- package/dist/registry/types.d.ts.map +1 -0
- package/dist/registry/types.js +1 -0
- package/dist/renderPptx/nodes/icon.d.ts.map +1 -1
- package/dist/renderPptx/nodes/icon.js +22 -4
- package/dist/renderPptx/renderPptx.d.ts +2 -1
- package/dist/renderPptx/renderPptx.d.ts.map +1 -1
- package/dist/renderPptx/renderPptx.js +19 -60
- package/dist/renderPptx/types.d.ts +2 -0
- package/dist/renderPptx/types.d.ts.map +1 -1
- package/dist/renderPptx/utils/backgroundBorder.d.ts.map +1 -1
- package/dist/renderPptx/utils/backgroundBorder.js +1 -1
- package/dist/shared/freeYogaTree.d.ts.map +1 -0
- package/dist/shared/measureImage.d.ts +13 -3
- package/dist/shared/measureImage.d.ts.map +1 -1
- package/dist/shared/measureImage.js +14 -19
- package/dist/shared/walkTree.d.ts.map +1 -0
- package/dist/toPositioned/toPositioned.d.ts +8 -1
- package/dist/toPositioned/toPositioned.d.ts.map +1 -1
- package/dist/toPositioned/toPositioned.js +32 -189
- package/dist/types.d.ts +38 -54
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +11 -1
- package/package.json +3 -3
- package/dist/autoFit/freeYogaTree.d.ts.map +0 -1
- package/dist/autoFit/walkTree.d.ts.map +0 -1
- package/dist/renderPptx/nodes/index.d.ts +0 -15
- package/dist/renderPptx/nodes/index.d.ts.map +0 -1
- package/dist/renderPptx/nodes/index.js +0 -14
- /package/dist/{autoFit → shared}/freeYogaTree.d.ts +0 -0
- /package/dist/{autoFit → shared}/freeYogaTree.js +0 -0
- /package/dist/{autoFit → shared}/walkTree.d.ts +0 -0
- /package/dist/{autoFit → shared}/walkTree.js +0 -0
|
@@ -1,33 +1,21 @@
|
|
|
1
1
|
import { loadYoga } from "yoga-layout/load";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { measureImage, prefetchImageSize } from "../shared/measureImage.js";
|
|
5
|
-
import { calcTableIntrinsicSize } from "../shared/tableUtils.js";
|
|
6
|
-
import { measureProcessArrow, measureTimeline, measureMatrix, measureTree, measureFlow, measurePyramid, } from "./measureCompositeNodes.js";
|
|
7
|
-
/**
|
|
8
|
-
* コンポジットノードの最小スケール閾値。
|
|
9
|
-
* renderPptx/utils/scaleToFit.ts の MIN_SCALE_THRESHOLD と同じ値を維持すること。
|
|
10
|
-
*/
|
|
11
|
-
const MIN_SCALE_THRESHOLD = 0.5;
|
|
12
|
-
/** 制約付きサイズを閾値でクランプする */
|
|
13
|
-
function constrainWithMinScale(intrinsicSize, availableSize) {
|
|
14
|
-
const minSize = intrinsicSize * MIN_SCALE_THRESHOLD;
|
|
15
|
-
return Math.max(minSize, Math.min(intrinsicSize, availableSize));
|
|
16
|
-
}
|
|
2
|
+
import { prefetchImageSize } from "../shared/measureImage.js";
|
|
3
|
+
import { getNodeDef } from "../registry/index.js";
|
|
17
4
|
/**
|
|
18
5
|
* POMNode ツリーを Yoga でレイアウト計算する
|
|
19
6
|
* POMNode ツリーの各ノードに yogaNode プロパティがセットされる
|
|
20
7
|
*
|
|
21
8
|
* @param root 入力 POMNode ツリーのルート
|
|
22
9
|
* @param slideSize スライド全体のサイズ(px)
|
|
10
|
+
* @param ctx BuildContext
|
|
23
11
|
*/
|
|
24
|
-
export async function calcYogaLayout(root, slideSize) {
|
|
12
|
+
export async function calcYogaLayout(root, slideSize, ctx) {
|
|
25
13
|
const Yoga = await getYoga();
|
|
26
14
|
// 事前に全画像のサイズを取得(HTTPS対応のため)
|
|
27
|
-
await prefetchAllImageSizes(root);
|
|
15
|
+
await prefetchAllImageSizes(root, ctx);
|
|
28
16
|
const rootYoga = Yoga.Node.create();
|
|
29
17
|
root.yogaNode = rootYoga;
|
|
30
|
-
await buildPomWithYogaTree(root, rootYoga);
|
|
18
|
+
await buildPomWithYogaTree(root, rootYoga, ctx);
|
|
31
19
|
// スライド全体サイズを指定
|
|
32
20
|
rootYoga.setWidth(slideSize.w);
|
|
33
21
|
rootYoga.setHeight(slideSize.h);
|
|
@@ -36,9 +24,9 @@ export async function calcYogaLayout(root, slideSize) {
|
|
|
36
24
|
/**
|
|
37
25
|
* POMNode ツリー内のすべての画像のサイズを事前取得する
|
|
38
26
|
*/
|
|
39
|
-
async function prefetchAllImageSizes(node) {
|
|
27
|
+
async function prefetchAllImageSizes(node, ctx) {
|
|
40
28
|
const imageSources = collectImageSources(node);
|
|
41
|
-
await Promise.all(imageSources.map((src) => prefetchImageSize(src)));
|
|
29
|
+
await Promise.all(imageSources.map((src) => prefetchImageSize(src, ctx.imageSizeCache, ctx.imageDataCache)));
|
|
42
30
|
}
|
|
43
31
|
/**
|
|
44
32
|
* POMNode ツリー内のすべての画像のsrcを収集する
|
|
@@ -50,20 +38,25 @@ function collectImageSources(node) {
|
|
|
50
38
|
if (n.backgroundImage) {
|
|
51
39
|
sources.push(n.backgroundImage.src);
|
|
52
40
|
}
|
|
53
|
-
|
|
54
|
-
|
|
41
|
+
const def = getNodeDef(n.type);
|
|
42
|
+
// ノード固有の画像ソース収集
|
|
43
|
+
if (def.collectImageSources) {
|
|
44
|
+
sources.push(...def.collectImageSources(n));
|
|
55
45
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
46
|
+
// 子要素の再帰
|
|
47
|
+
switch (def.category) {
|
|
48
|
+
case "single-child": {
|
|
49
|
+
const boxNode = n;
|
|
50
|
+
traverse(boxNode.children);
|
|
51
|
+
break;
|
|
62
52
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
53
|
+
case "multi-child":
|
|
54
|
+
case "absolute-child": {
|
|
55
|
+
const containerNode = n;
|
|
56
|
+
for (const child of containerNode.children) {
|
|
57
|
+
traverse(child);
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
67
60
|
}
|
|
68
61
|
}
|
|
69
62
|
}
|
|
@@ -82,11 +75,11 @@ async function getYoga() {
|
|
|
82
75
|
/**
|
|
83
76
|
* POMNode ツリーを再帰的に走査し、YogaNode ツリーを構築する
|
|
84
77
|
*/
|
|
85
|
-
async function buildPomWithYogaTree(node, parentYoga, parentNode) {
|
|
78
|
+
async function buildPomWithYogaTree(node, parentYoga, ctx, parentNode) {
|
|
86
79
|
const yoga = await getYoga();
|
|
87
80
|
const yn = yoga.Node.create();
|
|
88
81
|
node.yogaNode = yn; // 対応する YogaNode をセット
|
|
89
|
-
await applyStyleToYogaNode(node, yn);
|
|
82
|
+
await applyStyleToYogaNode(node, yn, ctx);
|
|
90
83
|
// HStack/VStack の子要素に flexShrink=1 をデフォルト設定(CSS Flexbox と同じ挙動)
|
|
91
84
|
// 主軸方向で %サイズ + gap がある場合の overflow を防ぐ
|
|
92
85
|
if (parentNode?.type === "hstack" || parentNode?.type === "vstack") {
|
|
@@ -101,38 +94,22 @@ async function buildPomWithYogaTree(node, parentYoga, parentNode) {
|
|
|
101
94
|
yn.setFlexBasis(0);
|
|
102
95
|
}
|
|
103
96
|
parentYoga.insertChild(yn, parentYoga.getChildCount());
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
97
|
+
const def = getNodeDef(node.type);
|
|
98
|
+
switch (def.category) {
|
|
99
|
+
case "single-child": {
|
|
100
|
+
const boxNode = node;
|
|
101
|
+
await buildPomWithYogaTree(boxNode.children, yn, ctx, node);
|
|
107
102
|
break;
|
|
108
103
|
}
|
|
109
|
-
case "
|
|
110
|
-
case "
|
|
111
|
-
|
|
112
|
-
|
|
104
|
+
case "multi-child":
|
|
105
|
+
case "absolute-child": {
|
|
106
|
+
const containerNode = node;
|
|
107
|
+
for (const child of containerNode.children) {
|
|
108
|
+
await buildPomWithYogaTree(child, yn, ctx, node);
|
|
113
109
|
}
|
|
114
110
|
break;
|
|
115
111
|
}
|
|
116
|
-
case "
|
|
117
|
-
// layer の子要素は絶対配置なので、各子要素のサイズ計算のみ行う
|
|
118
|
-
// x, y は toPositioned で適用される
|
|
119
|
-
for (const child of node.children) {
|
|
120
|
-
await buildPomWithYogaTree(child, yn, node);
|
|
121
|
-
}
|
|
122
|
-
break;
|
|
123
|
-
}
|
|
124
|
-
case "text":
|
|
125
|
-
case "image":
|
|
126
|
-
case "table":
|
|
127
|
-
case "shape":
|
|
128
|
-
case "timeline":
|
|
129
|
-
case "matrix":
|
|
130
|
-
case "tree":
|
|
131
|
-
case "flow":
|
|
132
|
-
case "processArrow":
|
|
133
|
-
case "pyramid":
|
|
134
|
-
case "line":
|
|
135
|
-
case "icon":
|
|
112
|
+
case "leaf":
|
|
136
113
|
// 子要素なし
|
|
137
114
|
break;
|
|
138
115
|
}
|
|
@@ -140,7 +117,7 @@ async function buildPomWithYogaTree(node, parentYoga, parentNode) {
|
|
|
140
117
|
/**
|
|
141
118
|
* node のスタイルを YogaNode に適用する
|
|
142
119
|
*/
|
|
143
|
-
async function applyStyleToYogaNode(node, yn) {
|
|
120
|
+
async function applyStyleToYogaNode(node, yn, ctx) {
|
|
144
121
|
const yoga = await getYoga();
|
|
145
122
|
// デフォルト: 縦並び
|
|
146
123
|
yn.setFlexDirection(yoga.FLEX_DIRECTION_COLUMN);
|
|
@@ -265,314 +242,9 @@ async function applyStyleToYogaNode(node, yn) {
|
|
|
265
242
|
break;
|
|
266
243
|
}
|
|
267
244
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
case "vstack": {
|
|
273
|
-
yn.setFlexDirection(yoga.FLEX_DIRECTION_COLUMN);
|
|
274
|
-
applyFlexProperties(node, yn, yoga);
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
case "hstack": {
|
|
278
|
-
yn.setFlexDirection(yoga.FLEX_DIRECTION_ROW);
|
|
279
|
-
applyFlexProperties(node, yn, yoga);
|
|
280
|
-
break;
|
|
281
|
-
}
|
|
282
|
-
case "text":
|
|
283
|
-
{
|
|
284
|
-
const text = node.text;
|
|
285
|
-
const fontSizePx = node.fontSize ?? 24;
|
|
286
|
-
const fontFamily = "Noto Sans JP";
|
|
287
|
-
const fontWeight = node.bold ? "bold" : "normal";
|
|
288
|
-
const lineHeight = 1.3;
|
|
289
|
-
yn.setMeasureFunc((width, widthMode) => {
|
|
290
|
-
const maxWidthPx = (() => {
|
|
291
|
-
switch (widthMode) {
|
|
292
|
-
case yoga.MEASURE_MODE_UNDEFINED:
|
|
293
|
-
return Number.POSITIVE_INFINITY;
|
|
294
|
-
case yoga.MEASURE_MODE_EXACTLY:
|
|
295
|
-
case yoga.MEASURE_MODE_AT_MOST:
|
|
296
|
-
return width;
|
|
297
|
-
}
|
|
298
|
-
})();
|
|
299
|
-
const { widthPx, heightPx } = measureText(text, maxWidthPx, {
|
|
300
|
-
fontFamily,
|
|
301
|
-
fontSizePx,
|
|
302
|
-
lineHeight,
|
|
303
|
-
fontWeight,
|
|
304
|
-
});
|
|
305
|
-
return {
|
|
306
|
-
width: widthPx,
|
|
307
|
-
height: heightPx,
|
|
308
|
-
};
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
break;
|
|
312
|
-
case "ul":
|
|
313
|
-
case "ol":
|
|
314
|
-
{
|
|
315
|
-
const combinedText = node.items.map((item) => item.text).join("\n");
|
|
316
|
-
const fontSizePx = node.fontSize ?? 24;
|
|
317
|
-
const fontFamily = "Noto Sans JP";
|
|
318
|
-
const fontWeight = node.bold ? "bold" : "normal";
|
|
319
|
-
const spacingMultiple = node.lineHeight ?? 1.3;
|
|
320
|
-
// PowerPoint の lineHeight はフォントメトリクス(ascent + descent)に
|
|
321
|
-
// 対する倍率。fontSizePx × fontMetricsRatio × spacingMultiple で計算する。
|
|
322
|
-
const fontMetricsRatio = measureFontLineHeightRatio(fontWeight);
|
|
323
|
-
const lineHeight = fontMetricsRatio * spacingMultiple;
|
|
324
|
-
// バレット/番号のインデント幅(pptxgenjs DEF_BULLET_MARGIN = 27pt = 36px @96dpi)
|
|
325
|
-
const bulletIndentPx = 36;
|
|
326
|
-
yn.setMeasureFunc((width, widthMode) => {
|
|
327
|
-
const maxWidthPx = (() => {
|
|
328
|
-
switch (widthMode) {
|
|
329
|
-
case yoga.MEASURE_MODE_UNDEFINED:
|
|
330
|
-
return Number.POSITIVE_INFINITY;
|
|
331
|
-
case yoga.MEASURE_MODE_EXACTLY:
|
|
332
|
-
case yoga.MEASURE_MODE_AT_MOST:
|
|
333
|
-
return width;
|
|
334
|
-
}
|
|
335
|
-
})();
|
|
336
|
-
// バレットインデント分を除いたテキスト利用可能幅で計測
|
|
337
|
-
const textMaxWidthPx = Math.max(0, maxWidthPx - bulletIndentPx);
|
|
338
|
-
const { widthPx, heightPx } = measureText(combinedText, textMaxWidthPx, {
|
|
339
|
-
fontFamily,
|
|
340
|
-
fontSizePx,
|
|
341
|
-
lineHeight,
|
|
342
|
-
fontWeight,
|
|
343
|
-
});
|
|
344
|
-
return {
|
|
345
|
-
width: widthPx + bulletIndentPx,
|
|
346
|
-
height: heightPx,
|
|
347
|
-
};
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
break;
|
|
351
|
-
case "image":
|
|
352
|
-
{
|
|
353
|
-
const src = node.src;
|
|
354
|
-
yn.setMeasureFunc(() => {
|
|
355
|
-
// 画像の実際のサイズを取得
|
|
356
|
-
const { widthPx, heightPx } = measureImage(src);
|
|
357
|
-
return {
|
|
358
|
-
width: widthPx,
|
|
359
|
-
height: heightPx,
|
|
360
|
-
};
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
break;
|
|
364
|
-
case "icon":
|
|
365
|
-
{
|
|
366
|
-
const size = node.size ?? 24;
|
|
367
|
-
yn.setMeasureFunc(() => ({
|
|
368
|
-
width: size,
|
|
369
|
-
height: size,
|
|
370
|
-
}));
|
|
371
|
-
}
|
|
372
|
-
break;
|
|
373
|
-
case "table":
|
|
374
|
-
{
|
|
375
|
-
yn.setMeasureFunc(() => {
|
|
376
|
-
const { width, height } = calcTableIntrinsicSize(node);
|
|
377
|
-
return {
|
|
378
|
-
width,
|
|
379
|
-
height,
|
|
380
|
-
};
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
break;
|
|
384
|
-
case "shape":
|
|
385
|
-
{
|
|
386
|
-
if (node.text) {
|
|
387
|
-
// テキストがある場合、テキストサイズを測定
|
|
388
|
-
const text = node.text;
|
|
389
|
-
const fontSizePx = node.fontSize ?? 24;
|
|
390
|
-
const fontFamily = node.fontFamily ?? "Noto Sans JP";
|
|
391
|
-
const fontWeight = node.bold ? "bold" : "normal";
|
|
392
|
-
const lineHeight = node.lineHeight ?? 1.3;
|
|
393
|
-
yn.setMeasureFunc((width, widthMode) => {
|
|
394
|
-
const maxWidthPx = (() => {
|
|
395
|
-
switch (widthMode) {
|
|
396
|
-
case yoga.MEASURE_MODE_UNDEFINED:
|
|
397
|
-
return Number.POSITIVE_INFINITY;
|
|
398
|
-
case yoga.MEASURE_MODE_EXACTLY:
|
|
399
|
-
case yoga.MEASURE_MODE_AT_MOST:
|
|
400
|
-
return width;
|
|
401
|
-
}
|
|
402
|
-
})();
|
|
403
|
-
const { widthPx, heightPx } = measureText(text, maxWidthPx, {
|
|
404
|
-
fontFamily,
|
|
405
|
-
fontSizePx,
|
|
406
|
-
lineHeight,
|
|
407
|
-
fontWeight,
|
|
408
|
-
});
|
|
409
|
-
return {
|
|
410
|
-
width: widthPx,
|
|
411
|
-
height: heightPx,
|
|
412
|
-
};
|
|
413
|
-
});
|
|
414
|
-
}
|
|
415
|
-
// テキストがない場合は、明示的にサイズが指定されていることを期待
|
|
416
|
-
}
|
|
417
|
-
break;
|
|
418
|
-
case "processArrow":
|
|
419
|
-
{
|
|
420
|
-
yn.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
421
|
-
const intrinsic = measureProcessArrow(node);
|
|
422
|
-
return {
|
|
423
|
-
width: widthMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
424
|
-
? constrainWithMinScale(intrinsic.width, width)
|
|
425
|
-
: intrinsic.width,
|
|
426
|
-
height: heightMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
427
|
-
? constrainWithMinScale(intrinsic.height, height)
|
|
428
|
-
: intrinsic.height,
|
|
429
|
-
};
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
break;
|
|
433
|
-
case "pyramid":
|
|
434
|
-
{
|
|
435
|
-
yn.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
436
|
-
const intrinsic = measurePyramid(node);
|
|
437
|
-
return {
|
|
438
|
-
width: widthMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
439
|
-
? constrainWithMinScale(intrinsic.width, width)
|
|
440
|
-
: intrinsic.width,
|
|
441
|
-
height: heightMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
442
|
-
? constrainWithMinScale(intrinsic.height, height)
|
|
443
|
-
: intrinsic.height,
|
|
444
|
-
};
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
break;
|
|
448
|
-
case "timeline":
|
|
449
|
-
{
|
|
450
|
-
yn.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
451
|
-
const intrinsic = measureTimeline(node);
|
|
452
|
-
return {
|
|
453
|
-
width: widthMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
454
|
-
? constrainWithMinScale(intrinsic.width, width)
|
|
455
|
-
: intrinsic.width,
|
|
456
|
-
height: heightMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
457
|
-
? constrainWithMinScale(intrinsic.height, height)
|
|
458
|
-
: intrinsic.height,
|
|
459
|
-
};
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
break;
|
|
463
|
-
case "matrix":
|
|
464
|
-
{
|
|
465
|
-
yn.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
466
|
-
const intrinsic = measureMatrix(node);
|
|
467
|
-
return {
|
|
468
|
-
width: widthMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
469
|
-
? constrainWithMinScale(intrinsic.width, width)
|
|
470
|
-
: intrinsic.width,
|
|
471
|
-
height: heightMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
472
|
-
? constrainWithMinScale(intrinsic.height, height)
|
|
473
|
-
: intrinsic.height,
|
|
474
|
-
};
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
break;
|
|
478
|
-
case "tree":
|
|
479
|
-
{
|
|
480
|
-
yn.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
481
|
-
const intrinsic = measureTree(node);
|
|
482
|
-
return {
|
|
483
|
-
width: widthMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
484
|
-
? constrainWithMinScale(intrinsic.width, width)
|
|
485
|
-
: intrinsic.width,
|
|
486
|
-
height: heightMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
487
|
-
? constrainWithMinScale(intrinsic.height, height)
|
|
488
|
-
: intrinsic.height,
|
|
489
|
-
};
|
|
490
|
-
});
|
|
491
|
-
}
|
|
492
|
-
break;
|
|
493
|
-
case "flow":
|
|
494
|
-
{
|
|
495
|
-
yn.setMeasureFunc((width, widthMode, height, heightMode) => {
|
|
496
|
-
const intrinsic = measureFlow(node);
|
|
497
|
-
return {
|
|
498
|
-
width: widthMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
499
|
-
? constrainWithMinScale(intrinsic.width, width)
|
|
500
|
-
: intrinsic.width,
|
|
501
|
-
height: heightMode !== yoga.MEASURE_MODE_UNDEFINED
|
|
502
|
-
? constrainWithMinScale(intrinsic.height, height)
|
|
503
|
-
: intrinsic.height,
|
|
504
|
-
};
|
|
505
|
-
});
|
|
506
|
-
}
|
|
507
|
-
break;
|
|
508
|
-
case "line":
|
|
509
|
-
// line ノードは絶対座標を使用するため、Yoga レイアウトではサイズ 0 として扱う
|
|
510
|
-
yn.setWidth(0);
|
|
511
|
-
yn.setHeight(0);
|
|
512
|
-
break;
|
|
513
|
-
case "layer":
|
|
514
|
-
// layer は子を絶対配置するコンテナ
|
|
515
|
-
// サイズは明示的に指定されることを期待
|
|
516
|
-
break;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
/**
|
|
520
|
-
* vstack/hstack 共通の Flex プロパティを適用する
|
|
521
|
-
*/
|
|
522
|
-
function applyFlexProperties(node, yn, yoga) {
|
|
523
|
-
if (node.gap !== undefined) {
|
|
524
|
-
yn.setGap(yoga.GUTTER_ROW, node.gap);
|
|
525
|
-
yn.setGap(yoga.GUTTER_COLUMN, node.gap);
|
|
526
|
-
}
|
|
527
|
-
if (node.alignItems !== undefined) {
|
|
528
|
-
switch (node.alignItems) {
|
|
529
|
-
case "start":
|
|
530
|
-
yn.setAlignItems(yoga.ALIGN_FLEX_START);
|
|
531
|
-
break;
|
|
532
|
-
case "center":
|
|
533
|
-
yn.setAlignItems(yoga.ALIGN_CENTER);
|
|
534
|
-
break;
|
|
535
|
-
case "end":
|
|
536
|
-
yn.setAlignItems(yoga.ALIGN_FLEX_END);
|
|
537
|
-
break;
|
|
538
|
-
case "stretch":
|
|
539
|
-
yn.setAlignItems(yoga.ALIGN_STRETCH);
|
|
540
|
-
break;
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
if (node.justifyContent !== undefined) {
|
|
544
|
-
switch (node.justifyContent) {
|
|
545
|
-
case "start":
|
|
546
|
-
yn.setJustifyContent(yoga.JUSTIFY_FLEX_START);
|
|
547
|
-
break;
|
|
548
|
-
case "center":
|
|
549
|
-
yn.setJustifyContent(yoga.JUSTIFY_CENTER);
|
|
550
|
-
break;
|
|
551
|
-
case "end":
|
|
552
|
-
yn.setJustifyContent(yoga.JUSTIFY_FLEX_END);
|
|
553
|
-
break;
|
|
554
|
-
case "spaceBetween":
|
|
555
|
-
yn.setJustifyContent(yoga.JUSTIFY_SPACE_BETWEEN);
|
|
556
|
-
break;
|
|
557
|
-
case "spaceAround":
|
|
558
|
-
yn.setJustifyContent(yoga.JUSTIFY_SPACE_AROUND);
|
|
559
|
-
break;
|
|
560
|
-
case "spaceEvenly":
|
|
561
|
-
yn.setJustifyContent(yoga.JUSTIFY_SPACE_EVENLY);
|
|
562
|
-
break;
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
if (node.flexWrap !== undefined) {
|
|
566
|
-
switch (node.flexWrap) {
|
|
567
|
-
case "nowrap":
|
|
568
|
-
yn.setFlexWrap(yoga.WRAP_NO_WRAP);
|
|
569
|
-
break;
|
|
570
|
-
case "wrap":
|
|
571
|
-
yn.setFlexWrap(yoga.WRAP_WRAP);
|
|
572
|
-
break;
|
|
573
|
-
case "wrapReverse":
|
|
574
|
-
yn.setFlexWrap(yoga.WRAP_WRAP_REVERSE);
|
|
575
|
-
break;
|
|
576
|
-
}
|
|
245
|
+
// ノード固有のスタイル適用(measureFunc 等)
|
|
246
|
+
const def = getNodeDef(node.type);
|
|
247
|
+
if (def.applyYogaStyle) {
|
|
248
|
+
await def.applyYogaStyle(node, yn, yoga, ctx);
|
|
577
249
|
}
|
|
578
250
|
}
|
|
@@ -5,14 +5,10 @@ type MeasureOptions = {
|
|
|
5
5
|
lineHeight?: number;
|
|
6
6
|
};
|
|
7
7
|
export type TextMeasurementMode = "opentype" | "fallback" | "auto";
|
|
8
|
-
/**
|
|
9
|
-
* テキスト計測モードを設定する
|
|
10
|
-
*/
|
|
11
|
-
export declare function setTextMeasurementMode(mode: TextMeasurementMode): void;
|
|
12
8
|
/**
|
|
13
9
|
* テキストを折り返し付きでレイアウトし、そのサイズを測定する
|
|
14
10
|
*/
|
|
15
|
-
export declare function measureText(text: string, maxWidthPx: number, opts: MeasureOptions): {
|
|
11
|
+
export declare function measureText(text: string, maxWidthPx: number, opts: MeasureOptions, mode?: TextMeasurementMode): {
|
|
16
12
|
widthPx: number;
|
|
17
13
|
heightPx: number;
|
|
18
14
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"measureText.d.ts","sourceRoot":"","sources":["../../src/calcYogaLayout/measureText.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"measureText.d.ts","sourceRoot":"","sources":["../../src/calcYogaLayout/measureText.ts"],"names":[],"mappings":"AAEA,KAAK,cAAc,GAAG;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;AA6HnE;;GAEG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,cAAc,EACpB,IAAI,GAAE,mBAA4B,GACjC;IACD,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAmBA"}
|
|
@@ -94,14 +94,6 @@ function calculateResult(lines, opts) {
|
|
|
94
94
|
// 端数切り上げ+余裕分 10px を足す
|
|
95
95
|
return { widthPx: widthPx + 10, heightPx };
|
|
96
96
|
}
|
|
97
|
-
// 現在のテキスト計測モード
|
|
98
|
-
let currentMode = "auto";
|
|
99
|
-
/**
|
|
100
|
-
* テキスト計測モードを設定する
|
|
101
|
-
*/
|
|
102
|
-
export function setTextMeasurementMode(mode) {
|
|
103
|
-
currentMode = mode;
|
|
104
|
-
}
|
|
105
97
|
/**
|
|
106
98
|
* fontWeight を "normal" | "bold" に正規化する
|
|
107
99
|
*/
|
|
@@ -114,10 +106,10 @@ function normalizeFontWeight(weight) {
|
|
|
114
106
|
/**
|
|
115
107
|
* テキストを折り返し付きでレイアウトし、そのサイズを測定する
|
|
116
108
|
*/
|
|
117
|
-
export function measureText(text, maxWidthPx, opts) {
|
|
109
|
+
export function measureText(text, maxWidthPx, opts, mode = "auto") {
|
|
118
110
|
// 計測方法を決定
|
|
119
111
|
const shouldUseFallback = (() => {
|
|
120
|
-
switch (
|
|
112
|
+
switch (mode) {
|
|
121
113
|
case "opentype":
|
|
122
114
|
return false;
|
|
123
115
|
case "fallback":
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare function rasterizeIcon(name: string, size: number, color: string): string;
|
|
1
|
+
export declare function rasterizeIcon(name: string, size: number, color: string, cache: Map<string, string>): string;
|
|
2
2
|
//# sourceMappingURL=renderIcon.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderIcon.d.ts","sourceRoot":"","sources":["../../src/icons/renderIcon.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"renderIcon.d.ts","sourceRoot":"","sources":["../../src/icons/renderIcon.ts"],"names":[],"mappings":"AAWA,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GACzB,MAAM,CAYR"}
|
package/dist/icons/renderIcon.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Resvg } from "@resvg/resvg-js";
|
|
2
2
|
import { ICON_DATA } from "./iconData.js";
|
|
3
|
-
const rasterCache = new Map();
|
|
4
3
|
function buildIconSvg(name, size, color) {
|
|
5
4
|
const pathData = ICON_DATA[name];
|
|
6
5
|
if (!pathData) {
|
|
@@ -8,9 +7,9 @@ function buildIconSvg(name, size, color) {
|
|
|
8
7
|
}
|
|
9
8
|
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="${color}" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">${pathData}</svg>`;
|
|
10
9
|
}
|
|
11
|
-
export function rasterizeIcon(name, size, color) {
|
|
10
|
+
export function rasterizeIcon(name, size, color, cache) {
|
|
12
11
|
const key = `${name}|${size}|${color}`;
|
|
13
|
-
const cached =
|
|
12
|
+
const cached = cache.get(key);
|
|
14
13
|
if (cached)
|
|
15
14
|
return cached;
|
|
16
15
|
const svg = buildIconSvg(name, size, color);
|
|
@@ -18,6 +17,6 @@ export function rasterizeIcon(name, size, color) {
|
|
|
18
17
|
const pngData = resvg.render();
|
|
19
18
|
const pngBuffer = pngData.asPng();
|
|
20
19
|
const result = `image/png;base64,${Buffer.from(pngBuffer).toString("base64")}`;
|
|
21
|
-
|
|
20
|
+
cache.set(key, result);
|
|
22
21
|
return result;
|
|
23
22
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 明示的な型変換ルール定義
|
|
3
|
+
*
|
|
4
|
+
* Zod の内部構造(_def)に依存せず、XML 属性値の文字列→適切な型への変換ルールを
|
|
5
|
+
* 静的に定義する。各ノードタイプ・子要素タイプごとに変換テーブルを持つ。
|
|
6
|
+
*/
|
|
7
|
+
export type CoercionRule = "number" | "boolean" | "string" | "json" | {
|
|
8
|
+
type: "literal";
|
|
9
|
+
value: string | number | boolean;
|
|
10
|
+
} | {
|
|
11
|
+
type: "union";
|
|
12
|
+
options: CoercionRule[];
|
|
13
|
+
} | {
|
|
14
|
+
type: "object";
|
|
15
|
+
shape: Record<string, CoercionRule>;
|
|
16
|
+
};
|
|
17
|
+
export declare function coerceWithRule(value: string, rule: CoercionRule): {
|
|
18
|
+
value: unknown;
|
|
19
|
+
error: string | null;
|
|
20
|
+
};
|
|
21
|
+
export declare function coerceUnionWithRules(value: string, options: CoercionRule[]): unknown;
|
|
22
|
+
export declare function coerceFallback(value: string): unknown;
|
|
23
|
+
/**
|
|
24
|
+
* CoercionRule からオブジェクト型の shape を取得する。
|
|
25
|
+
* dot notation の展開で使用。
|
|
26
|
+
*/
|
|
27
|
+
export declare function getObjectShapeFromRule(rule: CoercionRule): Record<string, CoercionRule> | undefined;
|
|
28
|
+
/**
|
|
29
|
+
* boolean と object の union かどうかを判定する。
|
|
30
|
+
* endArrow="true" と endArrow.type="triangle" の共存を許可するために使用。
|
|
31
|
+
*/
|
|
32
|
+
export declare function isBooleanObjectUnionRule(rule: CoercionRule): boolean;
|
|
33
|
+
export declare const NODE_COERCION_MAP: Record<string, Record<string, CoercionRule>>;
|
|
34
|
+
export declare const CHILD_ELEMENT_COERCION_MAP: Record<string, Record<string, CoercionRule>>;
|
|
35
|
+
//# sourceMappingURL=coercionRules.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coercionRules.d.ts","sourceRoot":"","sources":["../../src/parseXml/coercionRules.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,SAAS,GACT,QAAQ,GACR,MAAM,GACN;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAA;CAAE,CAAC;AAI5D,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,YAAY,GACjB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAyD1C;AAED,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,YAAY,EAAE,GACtB,OAAO,CAuCT;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAarD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,YAAY,GACjB,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,SAAS,CAY1C;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,CAQpE;AA6HD,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAkJ1E,CAAC;AAGF,eAAO,MAAM,0BAA0B,EAAE,MAAM,CAC7C,MAAM,EACN,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CA6E7B,CAAC"}
|