postext 1.47.0 → 1.48.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 (332) hide show
  1. package/dist/__tests__/bundle/designOverflowPin.test.js +1 -1
  2. package/dist/__tests__/bundle/gridBreakRulesPin.test.js +2 -2
  3. package/dist/__tests__/bundle/shapingLanguagePin.test.js +3 -3
  4. package/dist/__tests__/bundle/taskBoxPin.test.js +1 -1
  5. package/dist/__tests__/bundle.test.js +1 -1
  6. package/dist/__tests__/codeBlocks.test.js +1 -1
  7. package/dist/__tests__/composed/cardShapes.test.d.ts +2 -0
  8. package/dist/__tests__/composed/cardShapes.test.d.ts.map +1 -0
  9. package/dist/__tests__/composed/cardShapes.test.js +82 -0
  10. package/dist/__tests__/composed/cardShapes.test.js.map +1 -0
  11. package/dist/__tests__/composed/connectors.test.d.ts +2 -0
  12. package/dist/__tests__/composed/connectors.test.d.ts.map +1 -0
  13. package/dist/__tests__/composed/connectors.test.js +349 -0
  14. package/dist/__tests__/composed/connectors.test.js.map +1 -0
  15. package/dist/__tests__/composed/decorationSidePoints.test.d.ts +2 -0
  16. package/dist/__tests__/composed/decorationSidePoints.test.d.ts.map +1 -0
  17. package/dist/__tests__/composed/decorationSidePoints.test.js +164 -0
  18. package/dist/__tests__/composed/decorationSidePoints.test.js.map +1 -0
  19. package/dist/__tests__/composed/fit.test.js +2 -1
  20. package/dist/__tests__/composed/fit.test.js.map +1 -1
  21. package/dist/__tests__/composed/fixtures/connectors.d.ts +33 -0
  22. package/dist/__tests__/composed/fixtures/connectors.d.ts.map +1 -0
  23. package/dist/__tests__/composed/fixtures/connectors.js +142 -0
  24. package/dist/__tests__/composed/fixtures/connectors.js.map +1 -0
  25. package/dist/__tests__/composed/fixtures/grid.d.ts +32 -0
  26. package/dist/__tests__/composed/fixtures/grid.d.ts.map +1 -0
  27. package/dist/__tests__/composed/fixtures/grid.js +53 -0
  28. package/dist/__tests__/composed/fixtures/grid.js.map +1 -0
  29. package/dist/__tests__/composed/fixtures/legendMap.d.ts +24 -0
  30. package/dist/__tests__/composed/fixtures/legendMap.d.ts.map +1 -0
  31. package/dist/__tests__/composed/fixtures/legendMap.js +117 -0
  32. package/dist/__tests__/composed/fixtures/legendMap.js.map +1 -0
  33. package/dist/__tests__/composed/fixtures/mapParts.d.ts +58 -0
  34. package/dist/__tests__/composed/fixtures/mapParts.d.ts.map +1 -0
  35. package/dist/__tests__/composed/fixtures/mapParts.js +192 -0
  36. package/dist/__tests__/composed/fixtures/mapParts.js.map +1 -0
  37. package/dist/__tests__/composed/fixtures/modules.d.ts +55 -0
  38. package/dist/__tests__/composed/fixtures/modules.d.ts.map +1 -0
  39. package/dist/__tests__/composed/fixtures/modules.js +123 -0
  40. package/dist/__tests__/composed/fixtures/modules.js.map +1 -0
  41. package/dist/__tests__/composed/grid.test.d.ts +2 -0
  42. package/dist/__tests__/composed/grid.test.d.ts.map +1 -0
  43. package/dist/__tests__/composed/grid.test.js +357 -0
  44. package/dist/__tests__/composed/grid.test.js.map +1 -0
  45. package/dist/__tests__/composed/groups.test.js +6 -3
  46. package/dist/__tests__/composed/groups.test.js.map +1 -1
  47. package/dist/__tests__/composed/labelLegend.test.d.ts +2 -0
  48. package/dist/__tests__/composed/labelLegend.test.d.ts.map +1 -0
  49. package/dist/__tests__/composed/labelLegend.test.js +268 -0
  50. package/dist/__tests__/composed/labelLegend.test.js.map +1 -0
  51. package/dist/__tests__/composed/labelsChecks.test.js.map +1 -1
  52. package/dist/__tests__/composed/leaders.test.d.ts +2 -0
  53. package/dist/__tests__/composed/leaders.test.d.ts.map +1 -0
  54. package/dist/__tests__/composed/leaders.test.js +372 -0
  55. package/dist/__tests__/composed/leaders.test.js.map +1 -0
  56. package/dist/__tests__/composed/modules.test.d.ts +2 -0
  57. package/dist/__tests__/composed/modules.test.d.ts.map +1 -0
  58. package/dist/__tests__/composed/modules.test.js +352 -0
  59. package/dist/__tests__/composed/modules.test.js.map +1 -0
  60. package/dist/__tests__/composed/overConnectors.test.d.ts +2 -0
  61. package/dist/__tests__/composed/overConnectors.test.d.ts.map +1 -0
  62. package/dist/__tests__/composed/overConnectors.test.js +232 -0
  63. package/dist/__tests__/composed/overConnectors.test.js.map +1 -0
  64. package/dist/__tests__/composed/overlap.test.d.ts +2 -0
  65. package/dist/__tests__/composed/overlap.test.d.ts.map +1 -0
  66. package/dist/__tests__/composed/overlap.test.js +339 -0
  67. package/dist/__tests__/composed/overlap.test.js.map +1 -0
  68. package/dist/__tests__/composedTemplates.test.js +1 -1
  69. package/dist/__tests__/design/boxShape.test.d.ts +2 -0
  70. package/dist/__tests__/design/boxShape.test.d.ts.map +1 -0
  71. package/dist/__tests__/design/boxShape.test.js +126 -0
  72. package/dist/__tests__/design/boxShape.test.js.map +1 -0
  73. package/dist/__tests__/design/boxShapePaint.test.d.ts +2 -0
  74. package/dist/__tests__/design/boxShapePaint.test.d.ts.map +1 -0
  75. package/dist/__tests__/design/boxShapePaint.test.js +130 -0
  76. package/dist/__tests__/design/boxShapePaint.test.js.map +1 -0
  77. package/dist/__tests__/design/openerBottomAnchor.test.js.map +1 -1
  78. package/dist/__tests__/design/pathBlock.test.d.ts +2 -0
  79. package/dist/__tests__/design/pathBlock.test.d.ts.map +1 -0
  80. package/dist/__tests__/design/pathBlock.test.js +194 -0
  81. package/dist/__tests__/design/pathBlock.test.js.map +1 -0
  82. package/dist/__tests__/design/pathElement.test.d.ts +2 -0
  83. package/dist/__tests__/design/pathElement.test.d.ts.map +1 -0
  84. package/dist/__tests__/design/pathElement.test.js +257 -0
  85. package/dist/__tests__/design/pathElement.test.js.map +1 -0
  86. package/dist/__tests__/design/svgPath.test.d.ts +2 -0
  87. package/dist/__tests__/design/svgPath.test.d.ts.map +1 -0
  88. package/dist/__tests__/design/svgPath.test.js +144 -0
  89. package/dist/__tests__/design/svgPath.test.js.map +1 -0
  90. package/dist/__tests__/exports.test.js +52 -0
  91. package/dist/__tests__/exports.test.js.map +1 -1
  92. package/dist/__tests__/hardBreaks.test.js +1 -1
  93. package/dist/__tests__/headingInlineMarks.test.js +1 -1
  94. package/dist/__tests__/labelGlyphPaint.test.d.ts +2 -0
  95. package/dist/__tests__/labelGlyphPaint.test.d.ts.map +1 -0
  96. package/dist/__tests__/labelGlyphPaint.test.js +86 -0
  97. package/dist/__tests__/labelGlyphPaint.test.js.map +1 -0
  98. package/dist/__tests__/mathSizeMigration.test.js +2 -2
  99. package/dist/__tests__/migrate/labelsOnPictures.test.js +1 -1
  100. package/dist/__tests__/migrate/labelsOnPictures.test.js.map +1 -1
  101. package/dist/__tests__/parse/containers.test.js +1 -1
  102. package/dist/__tests__/parse/containers.test.js.map +1 -1
  103. package/dist/__tests__/pipeline/calloutInlineResourceGap.test.js +1 -1
  104. package/dist/__tests__/pipeline/calloutLabelGlyph.test.d.ts +2 -0
  105. package/dist/__tests__/pipeline/calloutLabelGlyph.test.d.ts.map +1 -0
  106. package/dist/__tests__/pipeline/calloutLabelGlyph.test.js +198 -0
  107. package/dist/__tests__/pipeline/calloutLabelGlyph.test.js.map +1 -0
  108. package/dist/__tests__/pipeline/calloutShapes.test.d.ts +2 -0
  109. package/dist/__tests__/pipeline/calloutShapes.test.d.ts.map +1 -0
  110. package/dist/__tests__/pipeline/calloutShapes.test.js +159 -0
  111. package/dist/__tests__/pipeline/calloutShapes.test.js.map +1 -0
  112. package/dist/__tests__/pipeline/calloutSplitMinLinesChild.test.js +1 -1
  113. package/dist/__tests__/pipeline/colonListRoom.test.js +1 -1
  114. package/dist/__tests__/pipeline/compoundBreaks.test.js +1 -1
  115. package/dist/__tests__/pipeline/dashBreaks.test.js +1 -1
  116. package/dist/__tests__/pipeline/headingSplitOrphans.test.js +1 -1
  117. package/dist/__tests__/pipeline/inlineFigureSpace.test.js +1 -1
  118. package/dist/__tests__/pipeline/paragraphContainerTail.test.js +1 -1
  119. package/dist/__tests__/pipeline/raggedOptimal.test.js +1 -1
  120. package/dist/__tests__/verseLines.test.js +1 -1
  121. package/dist/bundle/configVersion.d.ts +12 -3
  122. package/dist/bundle/configVersion.d.ts.map +1 -1
  123. package/dist/bundle/configVersion.js +16 -5
  124. package/dist/bundle/configVersion.js.map +1 -1
  125. package/dist/canvas-backend/blockRender.js +3 -3
  126. package/dist/canvas-backend/blockRender.js.map +1 -1
  127. package/dist/canvas-backend/composed.d.ts +4 -2
  128. package/dist/canvas-backend/composed.d.ts.map +1 -1
  129. package/dist/canvas-backend/composed.js +12 -7
  130. package/dist/canvas-backend/composed.js.map +1 -1
  131. package/dist/canvas-backend/headerFooter.d.ts +17 -1
  132. package/dist/canvas-backend/headerFooter.d.ts.map +1 -1
  133. package/dist/canvas-backend/headerFooter.js +64 -1
  134. package/dist/canvas-backend/headerFooter.js.map +1 -1
  135. package/dist/canvas-backend/index.d.ts.map +1 -1
  136. package/dist/canvas-backend/index.js +7 -1
  137. package/dist/canvas-backend/index.js.map +1 -1
  138. package/dist/canvas-backend/renderResourceBlock.d.ts.map +1 -1
  139. package/dist/canvas-backend/renderResourceBlock.js +17 -6
  140. package/dist/canvas-backend/renderResourceBlock.js.map +1 -1
  141. package/dist/canvas-backend/swatch.d.ts +20 -1
  142. package/dist/canvas-backend/swatch.d.ts.map +1 -1
  143. package/dist/canvas-backend/swatch.js +51 -1
  144. package/dist/canvas-backend/swatch.js.map +1 -1
  145. package/dist/comics/layoutPage.d.ts.map +1 -1
  146. package/dist/comics/layoutPage.js +6 -1
  147. package/dist/comics/layoutPage.js.map +1 -1
  148. package/dist/composed/continuation.d.ts +10 -2
  149. package/dist/composed/continuation.d.ts.map +1 -1
  150. package/dist/composed/continuation.js +10 -2
  151. package/dist/composed/continuation.js.map +1 -1
  152. package/dist/composed/document.d.ts +45 -1
  153. package/dist/composed/document.d.ts.map +1 -1
  154. package/dist/composed/document.js +76 -17
  155. package/dist/composed/document.js.map +1 -1
  156. package/dist/composed/labelText.d.ts +6 -2
  157. package/dist/composed/labelText.d.ts.map +1 -1
  158. package/dist/composed/labelText.js +19 -3
  159. package/dist/composed/labelText.js.map +1 -1
  160. package/dist/composed/labels.d.ts +57 -3
  161. package/dist/composed/labels.d.ts.map +1 -1
  162. package/dist/composed/labels.js +261 -12
  163. package/dist/composed/labels.js.map +1 -1
  164. package/dist/composed/modules.d.ts +30 -0
  165. package/dist/composed/modules.d.ts.map +1 -0
  166. package/dist/composed/modules.js +194 -0
  167. package/dist/composed/modules.js.map +1 -0
  168. package/dist/composed/overlap.d.ts +52 -0
  169. package/dist/composed/overlap.d.ts.map +1 -0
  170. package/dist/composed/overlap.js +611 -0
  171. package/dist/composed/overlap.js.map +1 -0
  172. package/dist/composed/paint.d.ts +28 -5
  173. package/dist/composed/paint.d.ts.map +1 -1
  174. package/dist/composed/paint.js +26 -5
  175. package/dist/composed/paint.js.map +1 -1
  176. package/dist/composed/reflowLog.d.ts +6 -1
  177. package/dist/composed/reflowLog.d.ts.map +1 -1
  178. package/dist/composed/reflowLog.js +43 -0
  179. package/dist/composed/reflowLog.js.map +1 -1
  180. package/dist/composed/repeat.d.ts +66 -0
  181. package/dist/composed/repeat.d.ts.map +1 -0
  182. package/dist/composed/repeat.js +217 -0
  183. package/dist/composed/repeat.js.map +1 -0
  184. package/dist/composed/slotChecks.d.ts +1 -1
  185. package/dist/composed/slotChecks.d.ts.map +1 -1
  186. package/dist/composed/slotChecks.js +114 -8
  187. package/dist/composed/slotChecks.js.map +1 -1
  188. package/dist/composed/sourceMap.d.ts.map +1 -1
  189. package/dist/composed/sourceMap.js +16 -4
  190. package/dist/composed/sourceMap.js.map +1 -1
  191. package/dist/composed/spread.d.ts.map +1 -1
  192. package/dist/composed/spread.js +6 -2
  193. package/dist/composed/spread.js.map +1 -1
  194. package/dist/composed/templates.d.ts +22 -2
  195. package/dist/composed/templates.d.ts.map +1 -1
  196. package/dist/composed/templates.js +159 -9
  197. package/dist/composed/templates.js.map +1 -1
  198. package/dist/composed/types.d.ts +140 -7
  199. package/dist/composed/types.d.ts.map +1 -1
  200. package/dist/composed/validate.d.ts +1 -1
  201. package/dist/composed/validate.d.ts.map +1 -1
  202. package/dist/composed/validate.js +101 -4
  203. package/dist/composed/validate.js.map +1 -1
  204. package/dist/composed/wrap.d.ts.map +1 -1
  205. package/dist/composed/wrap.js +95 -17
  206. package/dist/composed/wrap.js.map +1 -1
  207. package/dist/configWarnings.d.ts +7 -1
  208. package/dist/configWarnings.d.ts.map +1 -1
  209. package/dist/configWarnings.js +275 -4
  210. package/dist/configWarnings.js.map +1 -1
  211. package/dist/contrast.d.ts.map +1 -1
  212. package/dist/contrast.js +8 -0
  213. package/dist/contrast.js.map +1 -1
  214. package/dist/defaults/calloutStyles.d.ts +10 -1
  215. package/dist/defaults/calloutStyles.d.ts.map +1 -1
  216. package/dist/defaults/calloutStyles.js +46 -7
  217. package/dist/defaults/calloutStyles.js.map +1 -1
  218. package/dist/defaults/headerFooter.d.ts.map +1 -1
  219. package/dist/defaults/headerFooter.js +38 -0
  220. package/dist/defaults/headerFooter.js.map +1 -1
  221. package/dist/design/boxShape.d.ts +101 -0
  222. package/dist/design/boxShape.d.ts.map +1 -0
  223. package/dist/design/boxShape.js +398 -0
  224. package/dist/design/boxShape.js.map +1 -0
  225. package/dist/design/connector.d.ts +75 -0
  226. package/dist/design/connector.d.ts.map +1 -0
  227. package/dist/design/connector.js +325 -0
  228. package/dist/design/connector.js.map +1 -0
  229. package/dist/design/layout.d.ts +56 -3
  230. package/dist/design/layout.d.ts.map +1 -1
  231. package/dist/design/layout.js +214 -12
  232. package/dist/design/layout.js.map +1 -1
  233. package/dist/design/logicalEdges.d.ts +7 -0
  234. package/dist/design/logicalEdges.d.ts.map +1 -1
  235. package/dist/design/logicalEdges.js +28 -0
  236. package/dist/design/logicalEdges.js.map +1 -1
  237. package/dist/design/pathBlock.d.ts +69 -0
  238. package/dist/design/pathBlock.d.ts.map +1 -0
  239. package/dist/design/pathBlock.js +286 -0
  240. package/dist/design/pathBlock.js.map +1 -0
  241. package/dist/design/svgPath.d.ts +48 -0
  242. package/dist/design/svgPath.d.ts.map +1 -0
  243. package/dist/design/svgPath.js +402 -0
  244. package/dist/design/svgPath.js.map +1 -0
  245. package/dist/fonts/usage.d.ts +5 -0
  246. package/dist/fonts/usage.d.ts.map +1 -1
  247. package/dist/fonts/usage.js +36 -3
  248. package/dist/fonts/usage.js.map +1 -1
  249. package/dist/html-backend.d.ts.map +1 -1
  250. package/dist/html-backend.js +127 -22
  251. package/dist/html-backend.js.map +1 -1
  252. package/dist/index.d.ts +19 -9
  253. package/dist/index.d.ts.map +1 -1
  254. package/dist/index.js +13 -5
  255. package/dist/index.js.map +1 -1
  256. package/dist/measure/cache.js +1 -1
  257. package/dist/measure/cache.js.map +1 -1
  258. package/dist/measure/inlineIcon.d.ts +34 -0
  259. package/dist/measure/inlineIcon.d.ts.map +1 -0
  260. package/dist/measure/inlineIcon.js +89 -0
  261. package/dist/measure/inlineIcon.js.map +1 -0
  262. package/dist/measure/rich.d.ts +2 -1
  263. package/dist/measure/rich.d.ts.map +1 -1
  264. package/dist/measure/rich.js +6 -0
  265. package/dist/measure/rich.js.map +1 -1
  266. package/dist/migrate/pageDesign.d.ts.map +1 -1
  267. package/dist/migrate/pageDesign.js +4 -2
  268. package/dist/migrate/pageDesign.js.map +1 -1
  269. package/dist/migrate/textToMarkdown.js +2 -0
  270. package/dist/migrate/textToMarkdown.js.map +1 -1
  271. package/dist/parse/blockParser.d.ts.map +1 -1
  272. package/dist/parse/blockParser.js +171 -20
  273. package/dist/parse/blockParser.js.map +1 -1
  274. package/dist/parse/index.d.ts +1 -1
  275. package/dist/parse/index.d.ts.map +1 -1
  276. package/dist/parse/index.js.map +1 -1
  277. package/dist/parse/inlineFormatting.d.ts +11 -3
  278. package/dist/parse/inlineFormatting.d.ts.map +1 -1
  279. package/dist/parse/inlineFormatting.js +63 -5
  280. package/dist/parse/inlineFormatting.js.map +1 -1
  281. package/dist/parse/inlineSnippet.d.ts +2 -1
  282. package/dist/parse/inlineSnippet.d.ts.map +1 -1
  283. package/dist/parse/inlineSnippet.js +3 -2
  284. package/dist/parse/inlineSnippet.js.map +1 -1
  285. package/dist/parse/sourceMapping.d.ts.map +1 -1
  286. package/dist/parse/sourceMapping.js +8 -1
  287. package/dist/parse/sourceMapping.js.map +1 -1
  288. package/dist/parse/types.d.ts +71 -1
  289. package/dist/parse/types.d.ts.map +1 -1
  290. package/dist/pipeline/build.d.ts.map +1 -1
  291. package/dist/pipeline/build.js +23 -11
  292. package/dist/pipeline/build.js.map +1 -1
  293. package/dist/pipeline/buildMeasurement.d.ts.map +1 -1
  294. package/dist/pipeline/buildMeasurement.js +23 -11
  295. package/dist/pipeline/buildMeasurement.js.map +1 -1
  296. package/dist/pipeline/calloutLayout.d.ts.map +1 -1
  297. package/dist/pipeline/calloutLayout.js +142 -32
  298. package/dist/pipeline/calloutLayout.js.map +1 -1
  299. package/dist/pipeline/composedLayout.d.ts +1 -33
  300. package/dist/pipeline/composedLayout.d.ts.map +1 -1
  301. package/dist/pipeline/composedLayout.js +526 -36
  302. package/dist/pipeline/composedLayout.js.map +1 -1
  303. package/dist/pipeline/contentWarnings.d.ts.map +1 -1
  304. package/dist/pipeline/contentWarnings.js +46 -1
  305. package/dist/pipeline/contentWarnings.js.map +1 -1
  306. package/dist/pipeline/continuation.d.ts.map +1 -1
  307. package/dist/pipeline/continuation.js +3 -2
  308. package/dist/pipeline/continuation.js.map +1 -1
  309. package/dist/pipeline/headerFooter.d.ts +19 -1
  310. package/dist/pipeline/headerFooter.d.ts.map +1 -1
  311. package/dist/pipeline/headerFooter.js +145 -5
  312. package/dist/pipeline/headerFooter.js.map +1 -1
  313. package/dist/pipeline/partPalette.d.ts.map +1 -1
  314. package/dist/pipeline/partPalette.js +40 -1
  315. package/dist/pipeline/partPalette.js.map +1 -1
  316. package/dist/pipeline/resourceLayout.d.ts +1 -1
  317. package/dist/pipeline/resourceLayout.d.ts.map +1 -1
  318. package/dist/pipeline/resourceLayout.js +44 -15
  319. package/dist/pipeline/resourceLayout.js.map +1 -1
  320. package/dist/preflight.d.ts.map +1 -1
  321. package/dist/preflight.js +36 -1
  322. package/dist/preflight.js.map +1 -1
  323. package/dist/types.d.ts +305 -22
  324. package/dist/types.d.ts.map +1 -1
  325. package/dist/vdt.d.ts +384 -11
  326. package/dist/vdt.d.ts.map +1 -1
  327. package/dist/vdt.js.map +1 -1
  328. package/package.json +1 -1
  329. package/dist/composed/round2Types.d.ts +0 -185
  330. package/dist/composed/round2Types.d.ts.map +0 -1
  331. package/dist/composed/round2Types.js +0 -2
  332. package/dist/composed/round2Types.js.map +0 -1
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Modules (#1062): a topic page built from a page shell (a title and a
3
+ * modules group) and three module templates a series of books could share:
4
+ * a box with a tab and a photo beside its text (`caja`), a tree of three
5
+ * frames over a tinted ground (`arbol`), and a 2 × 2 photo grid with its own
6
+ * heading (`fotos`, a grid that repeats a photo and its caption). The words
7
+ * are written for this fixture, in Spanish and English (the Spanish box is
8
+ * longer, so it pushes the modules after it down); the pictures are the
9
+ * solid placeholders of `fixtures/page8`.
10
+ */
11
+ import type { PostextConfig, Resource } from '../../../types';
12
+ import type { PageTemplate } from '../../../composed/types';
13
+ export declare const mm: (value: number) => {
14
+ value: number;
15
+ unit: "mm";
16
+ };
17
+ export declare const MODULE_RESOURCES: Resource[];
18
+ /** The page shell: the title, then the modules one under another. */
19
+ export declare const TOPIC_TEMPLATE: PageTemplate;
20
+ /** A box with a tab over its text and a photo beside it. */
21
+ export declare const BOX_MODULE: PageTemplate;
22
+ /** A tree of three: a root over two branches, on a tinted ground. */
23
+ export declare const TREE_MODULE: PageTemplate;
24
+ /** A 2 × 2 photo grid under a heading of its own. */
25
+ export declare const PHOTOS_MODULE: PageTemplate;
26
+ export declare const MODULE_CONFIG: PostextConfig;
27
+ /** The words of the topic page in each language. */
28
+ export declare const TOPIC_WORDS: {
29
+ es: {
30
+ title: string;
31
+ tab: string;
32
+ box: string[];
33
+ tree: string[];
34
+ photos: string;
35
+ captions: string[];
36
+ };
37
+ en: {
38
+ title: string;
39
+ tab: string;
40
+ box: string[];
41
+ tree: string[];
42
+ photos: string;
43
+ captions: string[];
44
+ };
45
+ };
46
+ export type TopicLocale = keyof typeof TOPIC_WORDS;
47
+ /** The box module's block. */
48
+ export declare const boxModule: (lang: TopicLocale, attrs?: string) => string;
49
+ /** The tree module's block. */
50
+ export declare const treeModule: (lang: TopicLocale, attrs?: string) => string;
51
+ /** The photo grid module's block: its heading, then one card per photo. */
52
+ export declare const photosModule: (lang: TopicLocale, attrs?: string) => string;
53
+ /** The topic page: a title and the three modules. */
54
+ export declare const topicPage: (lang: TopicLocale, modules?: readonly string[]) => string;
55
+ //# sourceMappingURL=modules.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.d.ts","sourceRoot":"","sources":["../../../../src/__tests__/composed/fixtures/modules.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAG5D,eAAO,MAAM,EAAE,GAAI,OAAO,MAAM;;;CAAqC,CAAC;AAMtE,eAAO,MAAM,gBAAgB,EAAE,QAAQ,EAAoB,CAAC;AAE5D,qEAAqE;AACrE,eAAO,MAAM,cAAc,EAAE,YAO5B,CAAC;AAEF,4DAA4D;AAC5D,eAAO,MAAM,UAAU,EAAE,YAOxB,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,WAAW,EAAE,YAiBzB,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,aAAa,EAAE,YAS3B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,aAuB3B,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;CAwBvB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,MAAM,OAAO,WAAW,CAAC;AAEnD,8BAA8B;AAC9B,eAAO,MAAM,SAAS,GAAI,MAAM,WAAW,EAAE,cAAU,KAAG,MAGzD,CAAC;AAEF,+BAA+B;AAC/B,eAAO,MAAM,UAAU,GAAI,MAAM,WAAW,EAAE,cAAU,KAAG,MAG1D,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,YAAY,GAAI,MAAM,WAAW,EAAE,cAAU,KAAG,MAI5D,CAAC;AAEF,qDAAqD;AACrD,eAAO,MAAM,SAAS,GAAI,MAAM,WAAW,EAAE,UAAS,SAAS,MAAM,EAA4D,KAAG,MAC1C,CAAC"}
@@ -0,0 +1,123 @@
1
+ import { PAGE8_RESOURCES, PAGE8_TYPES } from './page8';
2
+ export const mm = (value) => ({ value, unit: 'mm' });
3
+ const pt = (value) => ({ value, unit: 'pt' });
4
+ const hex = (h) => ({ hex: h, model: 'hex' });
5
+ const PICTURES = PAGE8_RESOURCES.filter((r) => r.id.startsWith('foto-')).map((r) => r.id);
6
+ export const MODULE_RESOURCES = PAGE8_RESOURCES;
7
+ /** The page shell: the title, then the modules one under another. */
8
+ export const TOPIC_TEMPLATE = {
9
+ id: 'tema',
10
+ header: false,
11
+ frames: [
12
+ { name: 'titulo', takes: 'h1', placement: { anchor: { to: 'container', edge: 'top-left' } } },
13
+ ],
14
+ groups: [{ name: 'cuerpo', modules: true, gap: mm(8), placement: { anchor: { to: '#titulo', edge: 'below' }, offset: { y: mm(6) }, size: { width: 'fill', height: 'fill' } } }],
15
+ };
16
+ /** A box with a tab over its text and a photo beside it. */
17
+ export const BOX_MODULE = {
18
+ id: 'caja',
19
+ role: 'module',
20
+ frames: [
21
+ { name: 'texto', style: 'recuadro', width: { percent: 64 }, placement: { anchor: { to: 'container', edge: 'top-left' }, offset: { y: mm(6.4) } } },
22
+ { name: 'foto', style: 'marco', width: mm(36), placement: { anchor: { to: '#texto', edge: 'right-of' }, offset: { x: mm(5) } } },
23
+ ],
24
+ };
25
+ /** A tree of three: a root over two branches, on a tinted ground. */
26
+ export const TREE_MODULE = {
27
+ id: 'arbol',
28
+ role: 'module',
29
+ frames: [
30
+ { name: 'raiz', style: 'nodo', width: mm(56), placement: { anchor: { to: 'container', edge: 'top' }, offset: { y: mm(4) } } },
31
+ { name: 'izq', style: 'nodo', width: mm(56), placement: { anchor: { to: '#raiz', edge: 'below' }, offset: { x: mm(-44), y: mm(10) } } },
32
+ { name: 'der', style: 'nodo', width: mm(56), placement: { anchor: { to: '#raiz', edge: 'below' }, offset: { x: mm(44), y: mm(10) } } },
33
+ ],
34
+ decoration: {
35
+ elements: [
36
+ { kind: 'box', id: 'suelo', placement: { anchor: { to: 'container', edge: 'top-left' }, size: { width: { to: 'container', edge: 'right' }, height: { to: 'container', edge: 'bottom' } } }, style: { backgroundColor: hex('#eef6ea'), borderRadius: mm(3) } },
37
+ { kind: 'rule', id: 'tronco', direction: 'vertical', color: hex('#3c6e47'), thickness: pt(1.5), placement: { anchor: { to: '#raiz', edge: 'below' }, offset: { x: mm(28) }, size: { height: mm(5) } } },
38
+ { kind: 'rule', id: 'rama', direction: 'horizontal', color: hex('#3c6e47'), thickness: pt(1.5), placement: { anchor: { to: '#raiz', edge: 'below' }, offset: { x: mm(-16), y: mm(5) }, size: { width: mm(88) } } },
39
+ { kind: 'rule', id: 'hacia-izq', direction: 'vertical', color: hex('#3c6e47'), thickness: pt(1.5), placement: { anchor: { to: '#izq', edge: 'above' }, offset: { x: mm(28) }, size: { height: mm(5) } } },
40
+ { kind: 'rule', id: 'hacia-der', direction: 'vertical', color: hex('#3c6e47'), thickness: pt(1.5), placement: { anchor: { to: '#der', edge: 'above' }, offset: { x: mm(28) }, size: { height: mm(5) } } },
41
+ ],
42
+ },
43
+ };
44
+ /** A 2 × 2 photo grid under a heading of its own. */
45
+ export const PHOTOS_MODULE = {
46
+ id: 'fotos',
47
+ role: 'module',
48
+ frames: [
49
+ { name: 'cabecera', takes: 'h3', placement: { anchor: { to: 'container', edge: 'top-left' } } },
50
+ { name: 'foto', style: 'marco', placement: { anchor: { to: '#cabecera', edge: 'below' }, offset: { y: mm(3) } } },
51
+ { name: 'pie', style: 'pastilla', width: 'auto', layer: 2, overlap: 'allow', placement: { anchor: { to: '#foto', edge: 'bottom' }, offset: { y: mm(4) } } },
52
+ ],
53
+ groups: [{ name: 'rejilla', kind: 'grid', columns: 2, columnGap: mm(6), rowGap: mm(8), repeat: { frames: ['foto', 'pie'] }, placement: { anchor: { to: '#cabecera', edge: 'below' }, offset: { y: mm(3) }, size: { width: mm(120), height: 'fill' } } }],
54
+ };
55
+ export const MODULE_CONFIG = {
56
+ page: { sizePreset: 'custom', width: mm(210), height: mm(280), margins: { top: mm(18), bottom: mm(18), left: mm(16), right: mm(16), mirror: true } },
57
+ bodyText: { fontSize: pt(11), lineHeight: pt(15) },
58
+ headings: {
59
+ balancing: { enabled: false },
60
+ levels: [
61
+ { level: 1, fontSize: pt(20), lineHeight: pt(24), breakBefore: { enabled: false } },
62
+ { level: 3, fontSize: pt(13), lineHeight: pt(16) },
63
+ ],
64
+ },
65
+ resourceTypes: PAGE8_TYPES,
66
+ calloutStyles: [
67
+ {
68
+ id: 'recuadro', backgroundEnabled: true, background: hex('#d8ecf9'), border: { enabled: false }, borderRadius: mm(1.5),
69
+ padding: { top: mm(3), right: mm(4), bottom: mm(3.5), left: mm(4) },
70
+ label: { position: 'top-left', background: hex('#0885bf'), color: hex('#ffffff'), fontSize: pt(10), height: mm(6.4), paddingX: mm(2.5), offset: mm(6.4), inset: mm(0), rule: { enabled: false, color: hex('#0885bf') } },
71
+ body: { fontSize: pt(10.5), lineHeight: pt(15), firstLineIndent: mm(0) },
72
+ },
73
+ { id: 'marco', backgroundEnabled: true, background: hex('#ffffff'), border: { enabled: true, color: hex('#2a6f97'), width: pt(1.5) }, borderRadius: mm(2), padding: { top: mm(2), right: mm(2), bottom: mm(2), left: mm(2) } },
74
+ { id: 'pastilla', backgroundEnabled: true, background: hex('#f4a259'), border: { enabled: false }, borderRadius: mm(4), padding: { top: mm(1), right: mm(3), bottom: mm(1), left: mm(3) }, body: { fontSize: pt(9), lineHeight: pt(11), firstLineIndent: mm(0) } },
75
+ { id: 'nodo', backgroundEnabled: true, background: hex('#ffffff'), border: { enabled: true, color: hex('#3c6e47'), width: pt(1) }, borderRadius: mm(3), padding: { top: mm(2), right: mm(3), bottom: mm(2), left: mm(3) }, body: { fontSize: pt(10), lineHeight: pt(13), firstLineIndent: mm(0), textAlign: 'center' } },
76
+ ],
77
+ pageTemplates: [TOPIC_TEMPLATE, BOX_MODULE, TREE_MODULE, PHOTOS_MODULE],
78
+ };
79
+ /** The words of the topic page in each language. */
80
+ export const TOPIC_WORDS = {
81
+ es: {
82
+ title: 'El río',
83
+ tab: '¿Sabías que…?',
84
+ box: [
85
+ 'Un río nace en las montañas, donde la lluvia y la nieve se juntan en arroyos que bajan por las laderas.',
86
+ 'Por el camino recibe el agua de otros ríos más pequeños, que llamamos afluentes, y su cauce se hace cada vez más ancho y más lento hasta que llega al mar o a un lago.',
87
+ 'En sus orillas viven muchas plantas y animales que dependen de su agua limpia, y por eso conviene cuidarlo y no tirar nada a su corriente.',
88
+ ],
89
+ tree: ['El río', 'El agua que lleva', 'La vida en sus orillas'],
90
+ photos: 'Animales del río',
91
+ captions: ['La garza', 'La nutria', 'El sapo', 'La libélula'],
92
+ },
93
+ en: {
94
+ title: 'The river',
95
+ tab: 'Did you know?',
96
+ box: [
97
+ 'A river begins in the mountains, where rain and snow gather into streams.',
98
+ 'On its way it takes in smaller rivers and grows wider until it reaches the sea.',
99
+ ],
100
+ tree: ['The river', 'The water it carries', 'Life on its banks'],
101
+ photos: 'Animals of the river',
102
+ captions: ['The heron', 'The otter', 'The toad', 'The dragonfly'],
103
+ },
104
+ };
105
+ /** The box module's block. */
106
+ export const boxModule = (lang, attrs = '') => {
107
+ const w = TOPIC_WORDS[lang];
108
+ return `:::module{template="caja"${attrs}}\n:::frame{slot="texto" label="${w.tab}"}\n${w.box.join('\n\n')}\n:::\n::resource{id="${PICTURES[0]}" slot="foto"}\n:::\n`;
109
+ };
110
+ /** The tree module's block. */
111
+ export const treeModule = (lang, attrs = '') => {
112
+ const [root, left, right] = TOPIC_WORDS[lang].tree;
113
+ return `:::module{template="arbol"${attrs}}\n:::frame{slot="raiz"}\n${root}\n:::\n:::frame{slot="izq"}\n${left}\n:::\n:::frame{slot="der"}\n${right}\n:::\n:::\n`;
114
+ };
115
+ /** The photo grid module's block: its heading, then one card per photo. */
116
+ export const photosModule = (lang, attrs = '') => {
117
+ const w = TOPIC_WORDS[lang];
118
+ const cards = w.captions.map((c, k) => `:::frame{slot="foto"}\n::resource{id="${PICTURES[k % PICTURES.length]}"}\n\n:::frame{slot="pie"}\n${c}\n:::\n:::\n`).join('\n');
119
+ return `:::module{template="fotos"${attrs}}\n### ${w.photos}\n\n${cards}:::\n`;
120
+ };
121
+ /** The topic page: a title and the three modules. */
122
+ export const topicPage = (lang, modules = [boxModule(lang), treeModule(lang), photosModule(lang)]) => `::::page{template="tema"}\n# ${TOPIC_WORDS[lang].title}\n\n${modules.join('\n')}::::\n`;
123
+ //# sourceMappingURL=modules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modules.js","sourceRoot":"","sources":["../../../../src/__tests__/composed/fixtures/modules.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAEvD,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAa,EAAE,CAAC,CAAC;AACtE,MAAM,EAAE,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAa,EAAE,CAAC,CAAC;AAC/D,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,KAAc,EAAE,CAAC,CAAC;AAE/D,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAE1F,MAAM,CAAC,MAAM,gBAAgB,GAAe,eAAe,CAAC;AAE5D,qEAAqE;AACrE,MAAM,CAAC,MAAM,cAAc,GAAiB;IAC1C,EAAE,EAAE,MAAM;IACV,MAAM,EAAE,KAAK;IACb,MAAM,EAAE;QACN,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;KAC9F;IACD,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;CAChL,CAAC;AAEF,4DAA4D;AAC5D,MAAM,CAAC,MAAM,UAAU,GAAiB;IACtC,EAAE,EAAE,MAAM;IACV,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE;QACN,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE;QAClJ,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;KACjI;CACF,CAAC;AAEF,qEAAqE;AACrE,MAAM,CAAC,MAAM,WAAW,GAAiB;IACvC,EAAE,EAAE,OAAO;IACX,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE;QACN,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;QAC7H,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE;QACvI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE;KACvI;IACD,UAAU,EAAE;QACV,QAAQ,EAAE;YACR,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,eAAe,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;YAC7P,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;YACvM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE;YAClN,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;YACzM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;SAC1M;KACO;CACX,CAAC;AAEF,qDAAqD;AACrD,MAAM,CAAC,MAAM,aAAa,GAAiB;IACzC,EAAE,EAAE,OAAO;IACX,IAAI,EAAE,QAAQ;IACd,MAAM,EAAE;QACN,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE;QAC/F,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;QACjH,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE;KAC5J;IACD,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;CACzP,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,IAAI,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,EAAW;IAC7J,QAAQ,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAW;IAC3D,QAAQ,EAAE;QACR,SAAS,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;QAC7B,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YACnF,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE;SACnD;KACO;IACV,aAAa,EAAE,WAAW;IAC1B,aAAa,EAAE;QACb;YACE,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,GAAG,CAAC;YACtH,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;YACnE,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE;YACxN,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE;SAChE;QACV,EAAE,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAW;QACvO,EAAE,EAAE,EAAE,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAW;QAC3Q,EAAE,EAAE,EAAE,MAAM,EAAE,iBAAiB,EAAE,IAAI,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAW;KAClU;IACD,aAAa,EAAE,CAAC,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,CAAC;CACxE,CAAC;AAEF,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,EAAE,EAAE;QACF,KAAK,EAAE,QAAQ;QACf,GAAG,EAAE,eAAe;QACpB,GAAG,EAAE;YACH,yGAAyG;YACzG,wKAAwK;YACxK,4IAA4I;SAC7I;QACD,IAAI,EAAE,CAAC,QAAQ,EAAE,mBAAmB,EAAE,wBAAwB,CAAC;QAC/D,MAAM,EAAE,kBAAkB;QAC1B,QAAQ,EAAE,CAAC,UAAU,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,CAAC;KAC9D;IACD,EAAE,EAAE;QACF,KAAK,EAAE,WAAW;QAClB,GAAG,EAAE,eAAe;QACpB,GAAG,EAAE;YACH,2EAA2E;YAC3E,iFAAiF;SAClF;QACD,IAAI,EAAE,CAAC,WAAW,EAAE,sBAAsB,EAAE,mBAAmB,CAAC;QAChE,MAAM,EAAE,sBAAsB;QAC9B,QAAQ,EAAE,CAAC,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,CAAC;KAClE;CACF,CAAC;AAIF,8BAA8B;AAC9B,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAiB,EAAE,KAAK,GAAG,EAAE,EAAU,EAAE;IACjE,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,4BAA4B,KAAK,mCAAmC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,yBAAyB,QAAQ,CAAC,CAAC,CAAC,uBAAuB,CAAC;AACvK,CAAC,CAAC;AAEF,+BAA+B;AAC/B,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAiB,EAAE,KAAK,GAAG,EAAE,EAAU,EAAE;IAClE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;IACnD,OAAO,6BAA6B,KAAK,6BAA6B,IAAI,gCAAgC,IAAI,gCAAgC,KAAK,cAAc,CAAC;AACpK,CAAC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAiB,EAAE,KAAK,GAAG,EAAE,EAAU,EAAE;IACpE,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,yCAAyC,QAAQ,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,+BAA+B,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxK,OAAO,6BAA6B,KAAK,UAAU,CAAC,CAAC,MAAM,OAAO,KAAK,OAAO,CAAC;AACjF,CAAC,CAAC;AAEF,qDAAqD;AACrD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAiB,EAAE,UAA6B,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC,EAAU,EAAE,CAC3I,gCAAgC,WAAW,CAAC,IAAI,CAAC,CAAC,KAAK,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=grid.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/composed/grid.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,357 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildDocument } from '../../pipeline/build';
3
+ import { createMeasurementCache } from '../../measure';
4
+ import { formatWarning } from '../../pipeline/contentWarnings';
5
+ import { validatePageTemplates } from '../../composed/validate';
6
+ import { resolvePageTemplate } from '../../composed/templates';
7
+ import { expandRepeats, pageRepeats } from '../../composed/repeat';
8
+ import { composedPages } from '../../composed/document';
9
+ import { elementsForSource, findElement } from '../../composed/sourceMap';
10
+ import { clearComposedPageMemo, composedPageMemoStats, setComposedPageMemo } from '../../composed/pageMemo';
11
+ import { parseMarkdown } from '../../parse';
12
+ import { flowRectToPage } from '../../vdt';
13
+ import { CAPTIONS, GRID_CONFIG, GRID_RESOURCES, mm, PANEL_TEMPLATE, panelPage, PHOTO_TEMPLATE, photoItem, photoPage } from './fixtures/grid';
14
+ // #1061 (DESIGN §12.6): a grid group that repeats a frame set lays one
15
+ // instance of the set per content item, `<frame>[n]`, cell after cell.
16
+ class StubCtx {
17
+ font = '';
18
+ measureText(s) {
19
+ return { width: s.length * 7 };
20
+ }
21
+ }
22
+ globalThis.OffscreenCanvas = class {
23
+ getContext() {
24
+ return new StubCtx();
25
+ }
26
+ };
27
+ const MM = 300 / 25.4;
28
+ const build = (markdown, config = {}) => buildDocument({ markdown, resources: GRID_RESOURCES }, { ...GRID_CONFIG, ...config }, createMeasurementCache());
29
+ const composedPagesOf = (doc) => doc.pages.filter((p) => p.composed);
30
+ const frame = (page, name) => page.composed.frames.find((f) => f.name === name);
31
+ const warningsOf = (doc, kind) => (doc.contentWarnings ?? []).filter((w) => w.kind === kind);
32
+ const withTemplate = (t, more = []) => ({ pageTemplates: [t, ...more] });
33
+ const withGrid = (t, patch) => ({ ...t, groups: [{ ...t.groups[0], ...patch }] });
34
+ describe('a grid that repeats a frame set (#1061)', () => {
35
+ it('lays a 3 × 3 grid of photo cards, each caption pill on its photo\'s foot', () => {
36
+ const doc = build(photoPage('Animals of the river', CAPTIONS.en));
37
+ const [page] = composedPagesOf(doc);
38
+ expect(page).toBeDefined();
39
+ const names = page.composed.frames.map((f) => f.name);
40
+ expect(names).toEqual(['titulo', ...Array.from({ length: 9 }, (_, k) => [`foto[${k + 1}]`, `pie[${k + 1}]`]).flat()]);
41
+ const fotos = Array.from({ length: 9 }, (_, k) => frame(page, `foto[${k + 1}]`));
42
+ // Ids, items and the template's entry.
43
+ expect(fotos[1].id).toBe('cp0:foto[2]');
44
+ expect(fotos[1].repeat).toEqual({ frame: 'foto', item: 2 });
45
+ expect(fotos[1].configPath).toBe('/pageTemplates/0/frames/1');
46
+ expect(frame(page, 'pie[2]').configPath).toBe('/pageTemplates/0/frames/2');
47
+ // Three columns of one width, rows from the start side.
48
+ const area = page.contentArea;
49
+ const colW = (area.width - 2 * 6 * MM) / 3;
50
+ for (let k = 0; k < 9; k++) {
51
+ const f = fotos[k];
52
+ expect(f.rect.width).toBeCloseTo(colW, 3);
53
+ expect(f.rect.x).toBeCloseTo(area.x + (k % 3) * (colW + 6 * MM), 3);
54
+ if (k % 3 > 0)
55
+ expect(f.rect.y).toBeCloseTo(fotos[k - (k % 3)].rect.y, 6);
56
+ }
57
+ // A row is as tall as its tallest cell (stretch): the photos of a row
58
+ // are as tall as each other.
59
+ expect(fotos[0].rect.height).toBeCloseTo(fotos[1].rect.height, 6);
60
+ // Each pill hangs centred from its own photo's foot, 4 mm below it, and
61
+ // the next row starts past the pills (rowGap 10 mm).
62
+ for (let k = 0; k < 9; k++) {
63
+ const f = fotos[k];
64
+ const pie = frame(page, `pie[${k + 1}]`);
65
+ expect(pie.rect.x + pie.rect.width / 2).toBeCloseTo(f.rect.x + f.rect.width / 2, 3);
66
+ expect(pie.rect.y + pie.rect.height).toBeCloseTo(f.rect.y + f.rect.height + 4 * MM, 3);
67
+ expect(pie.blockIds.length).toBeGreaterThan(0);
68
+ }
69
+ const pie1 = frame(page, 'pie[1]');
70
+ expect(fotos[3].rect.y).toBeCloseTo(pie1.rect.y + pie1.rect.height + 10 * MM, 3);
71
+ // Each instance holds its own item: the n-th caption.
72
+ const text = (f) => f.blockIds.map((id) => doc.blocks.find((b) => b.id === id)).flatMap((b) => b?.lines.map((l) => l.text) ?? []).join(' ').trim();
73
+ expect(text(frame(page, 'pie[5]'))).toBe(CAPTIONS.en[4]);
74
+ expect(fotos[4].blockIds.some((id) => doc.blocks.find((b) => b.id === id)?.type === 'resource')).toBe(true);
75
+ expect(warningsOf(doc, 'frameOverflow')).toEqual([]);
76
+ expect(warningsOf(doc, 'slotEmpty')).toEqual([]);
77
+ expect(warningsOf(doc, 'slotUnknown')).toEqual([]);
78
+ });
79
+ it('adds a row for a tenth item', () => {
80
+ const doc = build(photoPage('Animals of the river', [...CAPTIONS.en, 'The salmon']));
81
+ const [page] = composedPagesOf(doc);
82
+ const f10 = frame(page, 'foto[10]');
83
+ const f7 = frame(page, 'foto[7]');
84
+ expect(f10.rect.x).toBeCloseTo(frame(page, 'foto[1]').rect.x, 6);
85
+ expect(f10.rect.y).toBeGreaterThan(f7.rect.y + f7.rect.height);
86
+ });
87
+ it('makes as many cards as each language has: 3 × 2 panels over photos, top-aligned', () => {
88
+ const es = ['Vive en la orilla y caza peces al acecho.', 'Anida en los taludes del río.', 'Nada de noche.', 'Canta en primavera junto al agua.', 'Pone sus huevos en el agua quieta.', 'Busca comida entre las piedras del fondo.'];
89
+ const en = ['It lives on the bank and waits for fish.', 'It nests in the river\'s banks.', 'It swims at night.', 'It sings by the water in spring.', 'It lays its eggs in still water.'];
90
+ const docEs = build(panelPage('El río', es), { locale: 'es' });
91
+ const docEn = build(panelPage('The river', en), { locale: 'en' });
92
+ const pageEs = composedPagesOf(docEs)[0];
93
+ const pageEn = composedPagesOf(docEn)[0];
94
+ expect(pageEs.composed.frames.filter((f) => f.repeat?.frame === 'panel')).toHaveLength(6);
95
+ expect(pageEn.composed.frames.filter((f) => f.repeat?.frame === 'panel')).toHaveLength(5);
96
+ // Same ids in both languages for the items they share.
97
+ expect(frame(pageEs, 'imagen[3]').id).toBe(frame(pageEn, 'imagen[3]').id);
98
+ for (const page of [pageEs, pageEn]) {
99
+ const panels = page.composed.frames.filter((f) => f.repeat?.frame === 'panel');
100
+ for (const p of panels) {
101
+ const img = frame(page, `imagen[${p.repeat.item}]`);
102
+ // The photo under its own panel, 2 mm below it.
103
+ expect(img.rect.y).toBeCloseTo(p.rect.y + p.rect.height + 2 * MM, 3);
104
+ expect(img.rect.x).toBeCloseTo(p.rect.x, 3);
105
+ // As wide as its cell: a `'fill'` width runs to the cell's edge.
106
+ expect(img.rect.width).toBeCloseTo(p.rect.width, 3);
107
+ expect(img.blockIds.some((id) => (page.floats ?? []).find((b) => b.id === id)?.type === 'resource')).toBe(true);
108
+ }
109
+ // `rowAlign: 'start'`: the panels of a row start at one height.
110
+ expect(panels[1].rect.y).toBeCloseTo(panels[0].rect.y, 6);
111
+ }
112
+ expect([...warningsOf(docEs, 'frameOverflow'), ...warningsOf(docEn, 'frameOverflow')]).toEqual([]);
113
+ });
114
+ it('sends the items past `max` to the flow, with repeatOverflow', () => {
115
+ const t = withGrid(PHOTO_TEMPLATE, { repeat: { frames: ['foto', 'pie'], max: 4 } });
116
+ const md = photoPage('Animals of the river', CAPTIONS.en.slice(0, 6));
117
+ const doc = build(md, withTemplate(t));
118
+ const page = composedPagesOf(doc)[0];
119
+ expect(page.composed.frames.filter((f) => f.repeat?.frame === 'foto').map((f) => f.repeat.item)).toEqual([1, 2, 3, 4]);
120
+ const over = warningsOf(doc, 'repeatOverflow');
121
+ expect(over.map((w) => w.item)).toEqual([5, 6]);
122
+ const w = over[0];
123
+ expect(w).toMatchObject({ template: 'fotos', group: 'fotos', frame: 'foto', max: 4, fenceIndex: 0 });
124
+ // It points at the item's `slot="foto"`.
125
+ const at = md.indexOf('slot="foto"', md.indexOf(CAPTIONS.en[3]));
126
+ expect(md.slice(w.sourceStart, w.sourceEnd)).toBe('foto');
127
+ expect(w.sourceStart).toBe(at + 'slot="'.length);
128
+ expect(formatWarning(w)).toContain('holds 4 items');
129
+ // Never lost: with no flow frame, the rest is set after the page.
130
+ const after = doc.pages.filter((p) => !p.composed).flatMap((p) => p.columns.flatMap((c) => c.blocks));
131
+ expect(after.some((b) => b.lines.some((l) => l.text.includes(CAPTIONS.en[4])))).toBe(true);
132
+ });
133
+ it('goes on by whole rows on a next page', () => {
134
+ const t = withGrid({ ...PHOTO_TEMPLATE, frames: PHOTO_TEMPLATE.frames.map((f) => (f.name === 'foto' ? { ...f, overflow: { continueIn: 'next-page' } } : f)) }, {
135
+ placement: { anchor: { to: '#titulo', edge: 'below' }, offset: { y: mm(6) }, size: { height: mm(120) } },
136
+ });
137
+ const doc = build(photoPage('Animals of the river', CAPTIONS.en), withTemplate(t));
138
+ const pages = composedPagesOf(doc);
139
+ expect(pages).toHaveLength(2);
140
+ const first = pages[0].composed.frames.filter((f) => f.repeat?.frame === 'foto').map((f) => f.repeat.item);
141
+ const second = pages[1].composed.frames.filter((f) => f.repeat?.frame === 'foto' && !f.collapsed).map((f) => f.repeat.item);
142
+ // Two rows fit 120 mm; the third goes on whole.
143
+ expect(first).toEqual([1, 2, 3, 4, 5, 6]);
144
+ expect(second).toEqual([7, 8, 9]);
145
+ expect(pages[1].composed.continuationOf).toBe(pages[0].index);
146
+ expect(frame(pages[1], 'foto[7]').id).toBe('cp0:foto[7]~1');
147
+ expect(frame(pages[1], 'pie[7]').id).toBe('cp0:pie[7]~1');
148
+ // The receiving page lays the grid alone: the title it anchors under
149
+ // takes no room there.
150
+ expect(frame(pages[1], 'titulo').collapsed).toBe(true);
151
+ expect(frame(pages[1], 'foto[7]').rect.y).toBeCloseTo(frame(pages[0], 'foto[1]').rect.y - frame(pages[0], 'titulo').rect.height, 3);
152
+ // Each item is whole on one page: its caption too.
153
+ const text = (p, f) => f.blockIds.map((id) => (p.floats ?? []).find((b) => b.id === id)).flatMap((b) => b?.lines.map((l) => l.text) ?? []).join(' ').trim();
154
+ expect(text(pages[1], frame(pages[1], 'pie[8]'))).toBe(CAPTIONS.en[7]);
155
+ expect(pages[0].composed.log.filter((e) => e.kind === 'continued').map((e) => e.frame)).toEqual(['foto[7]', 'pie[7]', 'foto[8]', 'pie[8]', 'foto[9]', 'pie[9]']);
156
+ expect(warningsOf(doc, 'frameOverflow')).toEqual([]);
157
+ });
158
+ it('takes the empty frames of an item that goes on with it', () => {
159
+ const t = withGrid({ ...PHOTO_TEMPLATE, frames: PHOTO_TEMPLATE.frames.map((f) => (f.name === 'foto' ? { ...f, overflow: { continueIn: 'next-page' } } : f)) }, {
160
+ placement: { anchor: { to: '#titulo', edge: 'below' }, offset: { y: mm(6) }, size: { height: mm(120) } },
161
+ });
162
+ const items = CAPTIONS.en.map((c, k) => (k === 7 ? ':::frame{slot="foto"}\n::resource{id="foto-gasto"}\n:::\n' : photoItem(k, c)));
163
+ const doc = build(`::::page{template="fotos"}\n# Animals of the river\n\n${items.join('\n')}::::\n`, withTemplate(t));
164
+ const pages = composedPagesOf(doc);
165
+ expect(pages).toHaveLength(2);
166
+ // Item 8 has no caption: its pill goes on with its photo, empty, and
167
+ // keeps its place under it.
168
+ const pie8 = frame(pages[1], 'pie[8]');
169
+ const foto8 = frame(pages[1], 'foto[8]');
170
+ expect(pie8.collapsed).toBeUndefined();
171
+ expect(pie8.rect.y + pie8.rect.height).toBeCloseTo(foto8.rect.y + foto8.rect.height + 4 * MM, 3);
172
+ expect(warningsOf(doc, 'slotEmpty')).toEqual([]);
173
+ });
174
+ it('clips the rows that do not fit when the grid cannot go on, and warns once', () => {
175
+ const t = withGrid(PHOTO_TEMPLATE, { placement: { anchor: { to: '#titulo', edge: 'below' }, offset: { y: mm(6) }, size: { height: mm(120) } } });
176
+ const doc = build(photoPage('Animals of the river', CAPTIONS.en), withTemplate(t));
177
+ expect(composedPagesOf(doc)).toHaveLength(1);
178
+ const page = composedPagesOf(doc)[0];
179
+ // Nothing runs past the grid's foot.
180
+ const titulo = frame(page, 'titulo');
181
+ const foot = titulo.rect.y + titulo.rect.height + 126 * MM;
182
+ for (const f of page.composed.frames)
183
+ if (f.repeat)
184
+ expect(f.rect.y + f.rect.height).toBeLessThanOrEqual(foot + 0.01);
185
+ // The rows that fit are whole; the third is cut.
186
+ expect(frame(page, 'foto[6]').overflowPx).toBe(0);
187
+ expect(frame(page, 'foto[7]').overflowPx).toBeGreaterThan(0);
188
+ // One warning, on the last instance cut.
189
+ const over = warningsOf(doc, 'frameOverflow');
190
+ expect(over.map((w) => w.frame)).toEqual(['pie[9]']);
191
+ });
192
+ it('anchors decoration to an instance: #foto[2]', () => {
193
+ const t = {
194
+ ...PHOTO_TEMPLATE,
195
+ decoration: { elements: [{ kind: 'rule', id: 'raya', direction: 'horizontal', color: { hex: '#2a6f97', model: 'hex' }, thickness: mm(0.8), placement: { anchor: { to: '#foto[2]', edge: 'above' }, offset: { y: mm(-1) }, size: { width: mm(20) } } }] },
196
+ };
197
+ const config = { ...GRID_CONFIG, ...withTemplate(t) };
198
+ expect(validatePageTemplates(config).filter((w) => w.kind === 'frameAnchorUnknown')).toEqual([]);
199
+ const doc = build(photoPage('Animals of the river', CAPTIONS.en), withTemplate(t));
200
+ const page = composedPagesOf(doc)[0];
201
+ const rule = page.composed.decoration.blocks.find((b) => b.elementId === 'raya');
202
+ expect(rule).toBeDefined();
203
+ const f2 = flowRectToPage(page, frame(page, 'foto[2]').rect);
204
+ expect(rule.bbox.x).toBeCloseTo(f2.x, 3);
205
+ expect(rule.bbox.y + rule.bbox.height).toBeLessThanOrEqual(f2.y + 0.01);
206
+ expect(rule.bbox.y + rule.bbox.height).toBeGreaterThan(f2.y - 2 * MM);
207
+ });
208
+ it('leaves out decoration anchored to an instance the page does not have', () => {
209
+ const t = {
210
+ ...PHOTO_TEMPLATE,
211
+ decoration: { elements: [{ kind: 'rule', id: 'raya', direction: 'horizontal', color: { hex: '#2a6f97', model: 'hex' }, thickness: mm(0.8), placement: { anchor: { to: '#foto[5]', edge: 'above' }, size: { width: mm(20) } } }] },
212
+ };
213
+ const doc = build(photoPage('Animals of the river', CAPTIONS.en.slice(0, 3)), withTemplate(t));
214
+ const page = composedPagesOf(doc)[0];
215
+ expect(page.composed.decoration?.blocks.find((b) => b.elementId === 'raya')).toBeUndefined();
216
+ });
217
+ it('keeps a page with a grid in the page memo, the same as laid afresh', () => {
218
+ const md = photoPage('Animals of the river', CAPTIONS.en.slice(0, 5));
219
+ setComposedPageMemo(true);
220
+ clearComposedPageMemo();
221
+ try {
222
+ const fresh = build(md);
223
+ const before = composedPageMemoStats();
224
+ const again = build(md);
225
+ expect(composedPageMemoStats().hits).toBeGreaterThan(before.hits);
226
+ const ids = (d) => composedPagesOf(d)[0].composed.frames.map((f) => `${f.id} ${f.rect.x.toFixed(3)} ${f.rect.y.toFixed(3)} ${f.blockIds.join(',')}`);
227
+ expect(ids(again)).toEqual(ids(fresh));
228
+ // The same as laid afresh, the memo off.
229
+ setComposedPageMemo(false);
230
+ expect(ids(build(md))).toEqual(ids(again));
231
+ }
232
+ finally {
233
+ clearComposedPageMemo();
234
+ setComposedPageMemo(true);
235
+ }
236
+ });
237
+ it('fills the cells from the start side of a right-to-left page', () => {
238
+ const doc = build(photoPage('حيوانات النهر', CAPTIONS.en.slice(0, 3)), { direction: 'rtl', locale: 'ar' });
239
+ const page = composedPagesOf(doc)[0];
240
+ const x = (n) => flowRectToPage(page, frame(page, n).rect).x;
241
+ expect(x('foto[1]')).toBeGreaterThan(x('foto[2]'));
242
+ expect(x('foto[2]')).toBeGreaterThan(x('foto[3]'));
243
+ });
244
+ it('maps each instance to its own Markdown and back', () => {
245
+ const md = photoPage('Animals of the river', CAPTIONS.en.slice(0, 4));
246
+ const doc = build(md);
247
+ const page = composedPagesOf(doc)[0];
248
+ const el = findElement(doc, 'cp0:pie[3]')?.element;
249
+ expect(el?.level).toBe('frame');
250
+ expect(el?.source).toEqual({ kind: 'config', path: '/pageTemplates/0/frames/2' });
251
+ const at = md.indexOf(CAPTIONS.en[2]);
252
+ const hits = elementsForSource(doc, at, at + CAPTIONS.en[2].length).map((h) => h.element.id);
253
+ expect(hits.some((id) => id.startsWith('cp0:pie[3]'))).toBe(true);
254
+ expect(hits.some((id) => id.startsWith('cp0:pie[2]'))).toBe(false);
255
+ // Its group is the grid.
256
+ const chain = findElement(doc, frame(page, 'pie[3]').blockIds[1]);
257
+ expect(chain).toBeDefined();
258
+ expect(frame(page, 'pie[3]').sourceStart).toBeLessThanOrEqual(at);
259
+ expect(frame(page, 'pie[3]').sourceEnd).toBeGreaterThanOrEqual(at + CAPTIONS.en[2].length);
260
+ });
261
+ it('lays the frames a grid lists as its cells when it repeats none', () => {
262
+ const t = {
263
+ id: 'cuatro',
264
+ header: false,
265
+ frames: ['a', 'b', 'c', 'd'].map((name) => ({ name, style: 'panel' })),
266
+ groups: [{ name: 'g', kind: 'grid', columns: 2, columnGap: mm(4), rowGap: mm(4), frames: ['a', 'b', 'c', 'd'] }],
267
+ };
268
+ const md = '::::page{template="cuatro"}\n' + ['a', 'b', 'c', 'd'].map((n) => `:::frame{slot="${n}"}\nBox ${n}.\n:::\n`).join('\n') + '::::\n';
269
+ const doc = build(md, withTemplate(t));
270
+ const page = composedPagesOf(doc)[0];
271
+ const [a, b, c, d] = ['a', 'b', 'c', 'd'].map((n) => frame(page, n));
272
+ expect(b.rect.y).toBeCloseTo(a.rect.y, 6);
273
+ expect(b.rect.x).toBeCloseTo(a.rect.x + a.rect.width + 4 * MM, 3);
274
+ expect(c.rect.x).toBeCloseTo(a.rect.x, 6);
275
+ expect(c.rect.y).toBeCloseTo(a.rect.y + a.rect.height + 4 * MM, 3);
276
+ expect(d.rect.y).toBeCloseTo(c.rect.y, 6);
277
+ expect(page.composed.frames.every((f) => f.repeat === undefined && !f.id.includes('['))).toBe(true);
278
+ });
279
+ it('threads an item\'s text through the frames of its own set', () => {
280
+ const t = {
281
+ id: 'fichas',
282
+ header: false,
283
+ frames: [
284
+ { name: 'ficha', style: 'panel', height: mm(14), next: 'mas' },
285
+ { name: 'mas', style: 'panel', optional: true, height: mm(30), placement: { anchor: { to: '#ficha', edge: 'below' }, offset: { y: mm(1) } } },
286
+ ],
287
+ groups: [{ name: 'g', kind: 'grid', columns: 2, columnGap: mm(4), rowGap: mm(4), repeat: { frames: ['ficha', 'mas'] } }],
288
+ };
289
+ const long = 'It lives on the bank and waits for fish to come by. '.repeat(4).trim();
290
+ const md = '::::page{template="fichas"}\n' + [long, 'Short.'].map((x) => `:::frame{slot="ficha"}\n${x}\n:::\n`).join('\n') + '::::\n';
291
+ const doc = build(md, withTemplate(t));
292
+ const page = composedPagesOf(doc)[0];
293
+ // Item 1 goes on in its own `mas`, item 2 fits its `ficha`.
294
+ expect(frame(page, 'mas[1]').continuedFrom).toBe('cp0:ficha[1]');
295
+ expect(frame(page, 'mas[1]').blockIds.length).toBeGreaterThan(0);
296
+ expect(warningsOf(doc, 'frameOverflow')).toEqual([]);
297
+ // Each item's text stays in its own story.
298
+ const text = (f) => f.blockIds.map((id) => doc.blocks.find((x) => x.id === id)).flatMap((x) => x?.lines.map((l) => l.text) ?? []).join(' ').trim();
299
+ expect(text(frame(page, 'mas[2]'))).toBe('');
300
+ expect(text(frame(page, 'mas[1]'))).not.toContain('Short');
301
+ expect(text(frame(page, 'ficha[2]'))).toContain('Short');
302
+ });
303
+ it('lays a template without grids as before', () => {
304
+ const t = { ...PHOTO_TEMPLATE, groups: [] };
305
+ const doc = build(`::::page{template="fotos"}\n# A\n\n${photoItem(0, 'One')}::::\n`, withTemplate(t));
306
+ const page = composedPagesOf(doc)[0];
307
+ expect(page.composed.frames.map((f) => f.id)).toEqual(['cp0:titulo', 'cp0:foto', 'cp0:pie']);
308
+ expect(page.composed.frames.every((f) => f.repeat === undefined)).toBe(true);
309
+ });
310
+ });
311
+ describe('grid configuration (#1061)', () => {
312
+ const base = (groups, frames = PHOTO_TEMPLATE.frames) => ({ ...GRID_CONFIG, pageTemplates: [{ ...PHOTO_TEMPLATE, frames, groups }] });
313
+ it('resolves a grid with its defaults', () => {
314
+ const t = resolvePageTemplate(base([{ name: 'g', kind: 'grid', gap: mm(3), repeat: { frames: ['foto', 'pie'] } }]), 'fotos');
315
+ expect(t.groups[0]).toMatchObject({ kind: 'grid', columns: 1, columnGap: mm(3), rowGap: mm(3), rowAlign: 'stretch', frames: ['foto', 'pie'], repeat: { frames: ['foto', 'pie'] } });
316
+ // Other groups resolve as they did.
317
+ const s = resolvePageTemplate(base([{ name: 's', kind: 'stack', frames: ['foto'] }]), 'fotos');
318
+ expect(Object.keys(s.groups[0]).sort()).toEqual(['align', 'configPath', 'fieldPaths', 'frames', 'gap', 'kind', 'name']);
319
+ });
320
+ it('warns about unknown repeated frames, a repeated frame in another group, and no columns', () => {
321
+ const config = base([
322
+ { name: 'otra', kind: 'stack', frames: ['titulo', 'foto'] },
323
+ { name: 'g', kind: 'grid', columns: 0, rowAlign: 'middle', repeat: { frames: ['foto', 'nada'], max: 0 } },
324
+ ]);
325
+ const ws = validatePageTemplates(config);
326
+ expect(ws).toContainEqual(expect.objectContaining({ kind: 'groupFrameUnknown', path: '/pageTemplates/0/groups/1/repeat/frames/1', value: 'nada' }));
327
+ expect(ws).toContainEqual(expect.objectContaining({ kind: 'groupFrameTwice', path: '/pageTemplates/0/groups/0/frames/1', value: 'foto' }));
328
+ expect(ws).toContainEqual(expect.objectContaining({ kind: 'unknownConfigValue', path: '/pageTemplates/0/groups/1/columns', value: '0' }));
329
+ expect(ws).toContainEqual(expect.objectContaining({ kind: 'unknownConfigValue', path: '/pageTemplates/0/groups/1/rowAlign', value: 'middle' }));
330
+ expect(ws).toContainEqual(expect.objectContaining({ kind: 'unknownConfigValue', path: '/pageTemplates/0/groups/1/repeat/max', value: '0' }));
331
+ // The repeat keeps its frame; the other group loses it.
332
+ const t = resolvePageTemplate(config, 'fotos');
333
+ expect(t.groups.find((g) => g.name === 'g').repeat).toEqual({ frames: ['foto'] });
334
+ expect(t.groups.find((g) => g.name === 'otra').frames).toEqual(['titulo']);
335
+ expect(t.groups.find((g) => g.name === 'g').columns).toBe(1);
336
+ });
337
+ it('expands the set per item, anchors among the set rewritten to the instance', () => {
338
+ const t = resolvePageTemplate(GRID_CONFIG, 'fotos');
339
+ const md = photoPage('T', ['a', 'b']);
340
+ const blocks = parseMarkdown(md);
341
+ const page = composedPages(blocks)[0];
342
+ const reps = pageRepeats(page, t);
343
+ expect(reps.items.map((i) => i.item)).toEqual([1, 2]);
344
+ expect([...reps.items[0].frames.keys()].sort()).toEqual(['foto', 'pie']);
345
+ const x = expandRepeats(t, new Map([['fotos', [1, 2]]]));
346
+ expect(x.frames.map((f) => f.name)).toEqual(['titulo', 'foto[1]', 'pie[1]', 'foto[2]', 'pie[2]']);
347
+ expect(x.frames.find((f) => f.name === 'pie[2]').placement.anchor.to).toBe('#foto[2]');
348
+ // The main frame keeps the template's drawing (to a frame outside the set).
349
+ expect(x.frames.find((f) => f.name === 'foto[2]').placement.anchor.to).toBe('#titulo');
350
+ expect(x.groups[0].items).toEqual([{ item: 1, frames: ['foto[1]', 'pie[1]'] }, { item: 2, frames: ['foto[2]', 'pie[2]'] }]);
351
+ // No grid: the same template.
352
+ const plain = resolvePageTemplate({ ...GRID_CONFIG, pageTemplates: [PANEL_TEMPLATE] }, 'paneles');
353
+ const none = { ...plain, groups: [] };
354
+ expect(expandRepeats(none, new Map())).toBe(none);
355
+ });
356
+ });
357
+ //# sourceMappingURL=grid.test.js.map