@kensio/colophon 2.3.0 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (361) hide show
  1. package/README.md +107 -798
  2. package/dist/background/gradient.d.ts +12 -0
  3. package/dist/background/gradient.d.ts.map +1 -0
  4. package/dist/background/gradient.js +21 -0
  5. package/dist/background/gradient.js.map +1 -0
  6. package/dist/background/image.d.ts +14 -0
  7. package/dist/background/image.d.ts.map +1 -0
  8. package/dist/background/image.js +36 -0
  9. package/dist/background/image.js.map +1 -0
  10. package/dist/background/index.d.ts +13 -0
  11. package/dist/background/index.d.ts.map +1 -0
  12. package/dist/background/index.js +27 -0
  13. package/dist/background/index.js.map +1 -0
  14. package/dist/background/mesh.d.ts +12 -0
  15. package/dist/background/mesh.d.ts.map +1 -0
  16. package/dist/background/mesh.js +43 -0
  17. package/dist/background/mesh.js.map +1 -0
  18. package/dist/background.d.ts +7 -2
  19. package/dist/background.d.ts.map +1 -1
  20. package/dist/background.js +44 -1
  21. package/dist/background.js.map +1 -1
  22. package/dist/cli/args.d.ts +1 -1
  23. package/dist/cli/args.d.ts.map +1 -1
  24. package/dist/cli/args.js +1 -1
  25. package/dist/cli/config.d.ts +1 -1
  26. package/dist/cli/config.js +1 -1
  27. package/dist/config/defaults.d.ts +8 -7
  28. package/dist/config/defaults.d.ts.map +1 -1
  29. package/dist/config/defaults.js +8 -8
  30. package/dist/config/defaults.js.map +1 -1
  31. package/dist/config/index.d.ts +1 -1
  32. package/dist/config/index.d.ts.map +1 -1
  33. package/dist/config/index.js +14 -5
  34. package/dist/config/index.js.map +1 -1
  35. package/dist/config/resolve.d.ts +7 -0
  36. package/dist/config/resolve.d.ts.map +1 -1
  37. package/dist/config/resolve.js +16 -0
  38. package/dist/config/resolve.js.map +1 -1
  39. package/dist/config/size.d.ts +7 -1
  40. package/dist/config/size.d.ts.map +1 -1
  41. package/dist/config/size.js +22 -9
  42. package/dist/config/size.js.map +1 -1
  43. package/dist/content/props.d.ts +2 -2
  44. package/dist/content/props.js +2 -2
  45. package/dist/content/slug.d.ts +5 -5
  46. package/dist/content/slug.js +6 -6
  47. package/dist/content/slug.js.map +1 -1
  48. package/dist/content/walk.d.ts +1 -1
  49. package/dist/content/walk.js +1 -1
  50. package/dist/fonts/index.d.ts +3 -2
  51. package/dist/fonts/index.d.ts.map +1 -1
  52. package/dist/fonts/index.js +3 -2
  53. package/dist/fonts/index.js.map +1 -1
  54. package/dist/fonts/resolve.js +1 -1
  55. package/dist/generate/extra.js +4 -4
  56. package/dist/generate/extra.js.map +1 -1
  57. package/dist/generate/options.d.ts +1 -1
  58. package/dist/generate/outputs.d.ts +4 -4
  59. package/dist/generate/outputs.js +4 -4
  60. package/dist/highlight/language.d.ts +2 -3
  61. package/dist/highlight/language.d.ts.map +1 -1
  62. package/dist/highlight/language.js +3 -4
  63. package/dist/highlight/language.js.map +1 -1
  64. package/dist/highlight/normalise.d.ts +2 -2
  65. package/dist/highlight/normalise.js +2 -2
  66. package/dist/image/index.d.ts +18 -0
  67. package/dist/image/index.d.ts.map +1 -0
  68. package/dist/image/index.js +42 -0
  69. package/dist/image/index.js.map +1 -0
  70. package/dist/image/jpeg.d.ts +10 -0
  71. package/dist/image/jpeg.d.ts.map +1 -0
  72. package/dist/image/jpeg.js +57 -0
  73. package/dist/image/jpeg.js.map +1 -0
  74. package/dist/image/load.d.ts +4 -0
  75. package/dist/image/load.d.ts.map +1 -0
  76. package/dist/image/load.js +60 -0
  77. package/dist/image/load.js.map +1 -0
  78. package/dist/image/media.d.ts +10 -0
  79. package/dist/image/media.d.ts.map +1 -0
  80. package/dist/image/media.js +37 -0
  81. package/dist/image/media.js.map +1 -0
  82. package/dist/image/resolve.d.ts +13 -0
  83. package/dist/image/resolve.d.ts.map +1 -0
  84. package/dist/image/resolve.js +38 -0
  85. package/dist/image/resolve.js.map +1 -0
  86. package/dist/image/size.d.ts +22 -0
  87. package/dist/image/size.d.ts.map +1 -0
  88. package/dist/image/size.js +60 -0
  89. package/dist/image/size.js.map +1 -0
  90. package/dist/image/svg.d.ts +12 -0
  91. package/dist/image/svg.d.ts.map +1 -0
  92. package/dist/image/svg.js +61 -0
  93. package/dist/image/svg.js.map +1 -0
  94. package/dist/image/uri.d.ts +9 -0
  95. package/dist/image/uri.d.ts.map +1 -0
  96. package/dist/image/uri.js +22 -0
  97. package/dist/image/uri.js.map +1 -0
  98. package/dist/index.d.ts +8 -3
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +7 -2
  101. package/dist/index.js.map +1 -1
  102. package/dist/layout/block.d.ts +37 -0
  103. package/dist/layout/block.d.ts.map +1 -0
  104. package/dist/layout/block.js +26 -0
  105. package/dist/layout/block.js.map +1 -0
  106. package/dist/layout/box.d.ts +20 -0
  107. package/dist/layout/box.d.ts.map +1 -0
  108. package/dist/layout/box.js +61 -0
  109. package/dist/layout/box.js.map +1 -0
  110. package/dist/layout/distribute.d.ts +15 -0
  111. package/dist/layout/distribute.d.ts.map +1 -0
  112. package/dist/layout/distribute.js +30 -0
  113. package/dist/layout/distribute.js.map +1 -0
  114. package/dist/layout/image.d.ts +42 -0
  115. package/dist/layout/image.d.ts.map +1 -0
  116. package/dist/layout/image.js +34 -0
  117. package/dist/layout/image.js.map +1 -0
  118. package/dist/layout/index.d.ts +40 -0
  119. package/dist/layout/index.d.ts.map +1 -0
  120. package/dist/layout/index.js +30 -0
  121. package/dist/layout/index.js.map +1 -0
  122. package/dist/layout/lines.d.ts +45 -0
  123. package/dist/layout/lines.d.ts.map +1 -0
  124. package/dist/layout/lines.js +71 -0
  125. package/dist/layout/lines.js.map +1 -0
  126. package/dist/layout/measure.d.ts +11 -0
  127. package/dist/layout/measure.d.ts.map +1 -0
  128. package/dist/layout/measure.js +11 -0
  129. package/dist/layout/measure.js.map +1 -0
  130. package/dist/layout/panel.d.ts +20 -0
  131. package/dist/layout/panel.d.ts.map +1 -0
  132. package/dist/layout/panel.js +22 -0
  133. package/dist/layout/panel.js.map +1 -0
  134. package/dist/layout/row.d.ts +15 -0
  135. package/dist/layout/row.d.ts.map +1 -0
  136. package/dist/layout/row.js +20 -0
  137. package/dist/layout/row.js.map +1 -0
  138. package/dist/layout/scrim.d.ts +23 -0
  139. package/dist/layout/scrim.d.ts.map +1 -0
  140. package/dist/layout/scrim.js +38 -0
  141. package/dist/layout/scrim.js.map +1 -0
  142. package/dist/layout/stack.d.ts +14 -0
  143. package/dist/layout/stack.d.ts.map +1 -0
  144. package/dist/layout/stack.js +19 -0
  145. package/dist/layout/stack.js.map +1 -0
  146. package/dist/layout/types.d.ts +49 -0
  147. package/dist/layout/types.d.ts.map +1 -0
  148. package/dist/layout/types.js +2 -0
  149. package/dist/layout/types.js.map +1 -0
  150. package/dist/manifest/build.d.ts +1 -1
  151. package/dist/manifest/build.js +1 -1
  152. package/dist/manifest/index.d.ts +1 -1
  153. package/dist/manifest/index.js +1 -1
  154. package/dist/manifest/order.d.ts +1 -1
  155. package/dist/manifest/order.js +1 -1
  156. package/dist/manifest/page.d.ts +2 -2
  157. package/dist/manifest/page.js +3 -3
  158. package/dist/measure/estimate.d.ts +10 -0
  159. package/dist/measure/estimate.d.ts.map +1 -0
  160. package/dist/measure/estimate.js +58 -0
  161. package/dist/measure/estimate.js.map +1 -0
  162. package/dist/measure/faces.d.ts +15 -0
  163. package/dist/measure/faces.d.ts.map +1 -0
  164. package/dist/measure/faces.js +70 -0
  165. package/dist/measure/faces.js.map +1 -0
  166. package/dist/measure/index.d.ts +16 -0
  167. package/dist/measure/index.d.ts.map +1 -0
  168. package/dist/measure/index.js +0 -0
  169. package/dist/measure/index.js.map +1 -0
  170. package/dist/measure/runs.d.ts +17 -0
  171. package/dist/measure/runs.d.ts.map +1 -0
  172. package/dist/measure/runs.js +39 -0
  173. package/dist/measure/runs.js.map +1 -0
  174. package/dist/measure/select.d.ts +13 -0
  175. package/dist/measure/select.d.ts.map +1 -0
  176. package/dist/measure/select.js +47 -0
  177. package/dist/measure/select.js.map +1 -0
  178. package/dist/meta/tags.d.ts +6 -6
  179. package/dist/meta/tags.js +6 -6
  180. package/dist/meta/url.d.ts +4 -4
  181. package/dist/meta/url.js +4 -4
  182. package/dist/placement/check.d.ts +1 -1
  183. package/dist/placement/check.js +1 -1
  184. package/dist/placement/index.js +1 -1
  185. package/dist/placement/relative.d.ts +3 -3
  186. package/dist/placement/relative.js +3 -3
  187. package/dist/pool.d.ts +2 -2
  188. package/dist/pool.js +3 -3
  189. package/dist/pool.js.map +1 -1
  190. package/dist/props.d.ts +7 -0
  191. package/dist/props.d.ts.map +1 -0
  192. package/dist/props.js +17 -0
  193. package/dist/props.js.map +1 -0
  194. package/dist/render/svg.d.ts +4 -2
  195. package/dist/render/svg.d.ts.map +1 -1
  196. package/dist/render/svg.js +28 -6
  197. package/dist/render/svg.js.map +1 -1
  198. package/dist/stamp/config-digest.d.ts.map +1 -1
  199. package/dist/stamp/config-digest.js +21 -1
  200. package/dist/stamp/config-digest.js.map +1 -1
  201. package/dist/stamp/index.js +2 -2
  202. package/dist/stamp/index.js.map +1 -1
  203. package/dist/stamp/read.d.ts +1 -1
  204. package/dist/stamp/read.js +4 -4
  205. package/dist/templates/attribution.d.ts +17 -0
  206. package/dist/templates/attribution.d.ts.map +1 -0
  207. package/dist/templates/attribution.js +39 -0
  208. package/dist/templates/attribution.js.map +1 -0
  209. package/dist/templates/banner/badge-props.d.ts +16 -0
  210. package/dist/templates/banner/badge-props.d.ts.map +1 -0
  211. package/dist/templates/banner/badge-props.js +58 -0
  212. package/dist/templates/banner/badge-props.js.map +1 -0
  213. package/dist/templates/banner/badge.d.ts.map +1 -1
  214. package/dist/templates/banner/badge.js +3 -6
  215. package/dist/templates/banner/badge.js.map +1 -1
  216. package/dist/templates/banner/index.d.ts +3 -0
  217. package/dist/templates/banner/index.d.ts.map +1 -1
  218. package/dist/templates/banner/index.js +41 -37
  219. package/dist/templates/banner/index.js.map +1 -1
  220. package/dist/templates/banner/lines.d.ts +7 -12
  221. package/dist/templates/banner/lines.d.ts.map +1 -1
  222. package/dist/templates/banner/lines.js +23 -34
  223. package/dist/templates/banner/lines.js.map +1 -1
  224. package/dist/templates/banner/version.d.ts +9 -0
  225. package/dist/templates/banner/version.d.ts.map +1 -0
  226. package/dist/templates/banner/version.js +21 -0
  227. package/dist/templates/banner/version.js.map +1 -0
  228. package/dist/templates/card/index.d.ts +4 -1
  229. package/dist/templates/card/index.d.ts.map +1 -1
  230. package/dist/templates/card/index.js +37 -25
  231. package/dist/templates/card/index.js.map +1 -1
  232. package/dist/templates/card/lines.d.ts +17 -13
  233. package/dist/templates/card/lines.d.ts.map +1 -1
  234. package/dist/templates/card/lines.js +24 -20
  235. package/dist/templates/card/lines.js.map +1 -1
  236. package/dist/templates/code/chrome.d.ts +7 -3
  237. package/dist/templates/code/chrome.d.ts.map +1 -1
  238. package/dist/templates/code/chrome.js +12 -11
  239. package/dist/templates/code/chrome.js.map +1 -1
  240. package/dist/templates/code/clip.d.ts +1 -1
  241. package/dist/templates/code/clip.js +1 -1
  242. package/dist/templates/code/fit.d.ts +2 -2
  243. package/dist/templates/code/fit.d.ts.map +1 -1
  244. package/dist/templates/code/fit.js +4 -4
  245. package/dist/templates/code/fit.js.map +1 -1
  246. package/dist/templates/code/index.d.ts.map +1 -1
  247. package/dist/templates/code/index.js +7 -6
  248. package/dist/templates/code/index.js.map +1 -1
  249. package/dist/templates/code/layout.d.ts +1 -1
  250. package/dist/templates/code/layout.d.ts.map +1 -1
  251. package/dist/templates/code/layout.js +6 -6
  252. package/dist/templates/code/layout.js.map +1 -1
  253. package/dist/templates/code/panel.d.ts +13 -0
  254. package/dist/templates/code/panel.d.ts.map +1 -1
  255. package/dist/templates/code/panel.js +34 -2
  256. package/dist/templates/code/panel.js.map +1 -1
  257. package/dist/templates/code/plate.d.ts +3 -1
  258. package/dist/templates/code/plate.d.ts.map +1 -1
  259. package/dist/templates/code/plate.js +11 -9
  260. package/dist/templates/code/plate.js.map +1 -1
  261. package/dist/templates/code/spans.js +1 -1
  262. package/dist/templates/code/spans.js.map +1 -1
  263. package/dist/templates/code/width.d.ts +10 -0
  264. package/dist/templates/code/width.d.ts.map +1 -0
  265. package/dist/templates/code/width.js +26 -0
  266. package/dist/templates/code/width.js.map +1 -0
  267. package/dist/templates/footer.d.ts +8 -0
  268. package/dist/templates/footer.d.ts.map +1 -1
  269. package/dist/templates/footer.js +11 -1
  270. package/dist/templates/footer.js.map +1 -1
  271. package/dist/templates/index.d.ts +1 -1
  272. package/dist/templates/index.d.ts.map +1 -1
  273. package/dist/templates/index.js +1 -1
  274. package/dist/templates/index.js.map +1 -1
  275. package/dist/templates/logo.d.ts +15 -0
  276. package/dist/templates/logo.d.ts.map +1 -0
  277. package/dist/templates/logo.js +30 -0
  278. package/dist/templates/logo.js.map +1 -0
  279. package/dist/templates/measure.d.ts +11 -0
  280. package/dist/templates/measure.d.ts.map +1 -0
  281. package/dist/templates/measure.js +11 -0
  282. package/dist/templates/measure.js.map +1 -0
  283. package/dist/templates/props.d.ts +2 -2
  284. package/dist/templates/props.js +2 -2
  285. package/dist/templates/text.d.ts +37 -0
  286. package/dist/templates/text.d.ts.map +1 -0
  287. package/dist/templates/text.js +26 -0
  288. package/dist/templates/text.js.map +1 -0
  289. package/dist/text/break.d.ts +11 -0
  290. package/dist/text/break.d.ts.map +1 -0
  291. package/dist/text/break.js +30 -0
  292. package/dist/text/break.js.map +1 -0
  293. package/dist/text/fit.d.ts +30 -0
  294. package/dist/text/fit.d.ts.map +1 -0
  295. package/dist/text/fit.js +29 -0
  296. package/dist/text/fit.js.map +1 -0
  297. package/dist/text/index.d.ts +5 -3
  298. package/dist/text/index.d.ts.map +1 -1
  299. package/dist/text/index.js +3 -2
  300. package/dist/text/index.js.map +1 -1
  301. package/dist/text/wrap.d.ts +17 -7
  302. package/dist/text/wrap.d.ts.map +1 -1
  303. package/dist/text/wrap.js +25 -17
  304. package/dist/text/wrap.js.map +1 -1
  305. package/dist/texture/grain.d.ts +17 -0
  306. package/dist/texture/grain.d.ts.map +1 -0
  307. package/dist/texture/grain.js +29 -0
  308. package/dist/texture/grain.js.map +1 -0
  309. package/dist/texture/index.d.ts +11 -0
  310. package/dist/texture/index.d.ts.map +1 -0
  311. package/dist/texture/index.js +20 -0
  312. package/dist/texture/index.js.map +1 -0
  313. package/dist/texture/pattern.d.ts +17 -0
  314. package/dist/texture/pattern.d.ts.map +1 -0
  315. package/dist/texture/pattern.js +45 -0
  316. package/dist/texture/pattern.js.map +1 -0
  317. package/dist/texture/resolve.d.ts +16 -0
  318. package/dist/texture/resolve.d.ts.map +1 -0
  319. package/dist/texture/resolve.js +20 -0
  320. package/dist/texture/resolve.js.map +1 -0
  321. package/dist/theme/index.d.ts +27 -0
  322. package/dist/theme/index.d.ts.map +1 -0
  323. package/dist/theme/index.js +41 -0
  324. package/dist/theme/index.js.map +1 -0
  325. package/dist/theme/presets.d.ts +38 -0
  326. package/dist/theme/presets.d.ts.map +1 -0
  327. package/dist/theme/presets.js +150 -0
  328. package/dist/theme/presets.js.map +1 -0
  329. package/dist/types.d.ts +281 -46
  330. package/dist/types.d.ts.map +1 -1
  331. package/dist/validate/background.d.ts +12 -0
  332. package/dist/validate/background.d.ts.map +1 -0
  333. package/dist/validate/background.js +53 -0
  334. package/dist/validate/background.js.map +1 -0
  335. package/dist/validate/collect.d.ts +9 -0
  336. package/dist/validate/collect.d.ts.map +1 -0
  337. package/dist/validate/collect.js +34 -0
  338. package/dist/validate/collect.js.map +1 -0
  339. package/dist/validate/index.d.ts +1 -1
  340. package/dist/validate/index.d.ts.map +1 -1
  341. package/dist/validate/index.js +3 -20
  342. package/dist/validate/index.js.map +1 -1
  343. package/dist/validate/keys.d.ts +35 -2
  344. package/dist/validate/keys.d.ts.map +1 -1
  345. package/dist/validate/keys.js +92 -3
  346. package/dist/validate/keys.js.map +1 -1
  347. package/dist/validate/overrides.d.ts.map +1 -1
  348. package/dist/validate/overrides.js +5 -1
  349. package/dist/validate/overrides.js.map +1 -1
  350. package/dist/validate/suggest.d.ts.map +1 -1
  351. package/dist/validate/suggest.js +21 -3
  352. package/dist/validate/suggest.js.map +1 -1
  353. package/dist/validate/texture.d.ts +11 -0
  354. package/dist/validate/texture.d.ts.map +1 -0
  355. package/dist/validate/texture.js +34 -0
  356. package/dist/validate/texture.js.map +1 -0
  357. package/dist/validate/values.d.ts +10 -10
  358. package/dist/validate/values.d.ts.map +1 -1
  359. package/dist/validate/values.js +21 -31
  360. package/dist/validate/values.js.map +1 -1
  361. package/package.json +7 -1
@@ -0,0 +1,14 @@
1
+ import type { Align, Extent, Rect } from "./types.js";
2
+ /** A stacked item's rectangle, and which item it belongs to. */
3
+ export interface StackedRect extends Rect {
4
+ readonly index: number;
5
+ }
6
+ /**
7
+ * Stack items down an area and give each one its rectangle.
8
+ *
9
+ * Each keeps the full width of the area, because the vertical placement is the
10
+ * only decision being made here. An item that wants less width draws itself
11
+ * narrower, or puts a `row` inside the rectangle it was given.
12
+ */
13
+ export declare function stack(items: readonly Extent[], area: Rect, align?: Align): readonly StackedRect[];
14
+ //# sourceMappingURL=stack.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.d.ts","sourceRoot":"","sources":["../../src/layout/stack.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEtD,gEAAgE;AAChE,MAAM,WAAW,WAAY,SAAQ,IAAI;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,CACnB,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,IAAI,EAAE,IAAI,EACV,KAAK,GAAE,KAAgB,GACtB,SAAS,WAAW,EAAE,CAcxB"}
@@ -0,0 +1,19 @@
1
+ import { distribute } from "./distribute.js";
2
+ /**
3
+ * Stack items down an area and give each one its rectangle.
4
+ *
5
+ * Each keeps the full width of the area, because the vertical placement is the
6
+ * only decision being made here. An item that wants less width draws itself
7
+ * narrower, or puts a `row` inside the rectangle it was given.
8
+ */
9
+ export function stack(items, area, align = "centre") {
10
+ const placed = distribute(items, { start: area.y, end: area.y + area.height }, align);
11
+ return placed.map((placement, index) => ({
12
+ x: area.x,
13
+ y: placement.start,
14
+ width: area.width,
15
+ height: items[index]?.size ?? 0,
16
+ index: placement.index,
17
+ }));
18
+ }
19
+ //# sourceMappingURL=stack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stack.js","sourceRoot":"","sources":["../../src/layout/stack.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAQ7C;;;;;;GAMG;AACH,MAAM,UAAU,KAAK,CACnB,KAAwB,EACxB,IAAU,EACV,KAAK,GAAU,QAAQ;IAEvB,MAAM,MAAM,GAAG,UAAU,CACvB,KAAK,EACL,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,EAC5C,KAAK,CACN,CAAC;IAEF,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACvC,CAAC,EAAE,IAAI,CAAC,CAAC;QACT,CAAC,EAAE,SAAS,CAAC,KAAK;QAClB,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,IAAI,IAAI,CAAC;QAC/B,KAAK,EAAE,SAAS,CAAC,KAAK;KACvB,CAAC,CAAC,CAAC;AACN,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * A rectangle in image coordinates, which is what every primitive here takes
3
+ * and returns. Templates are handed the image's `dimensions` and work down
4
+ * from there, so a rectangle is the one shape they all have in common.
5
+ */
6
+ export interface Rect {
7
+ readonly x: number;
8
+ readonly y: number;
9
+ readonly width: number;
10
+ readonly height: number;
11
+ }
12
+ /**
13
+ * A stretch of one axis: top and bottom for a stack, left and right for a row.
14
+ * `start` is the smaller coordinate, so it is the top or the left edge.
15
+ */
16
+ export interface Span {
17
+ readonly start: number;
18
+ readonly end: number;
19
+ }
20
+ /**
21
+ * Where a group of items sits within the space it was given. `centre` is the
22
+ * default everywhere, because a share image is looked at rather than read down,
23
+ * and the middle is where the eye goes.
24
+ */
25
+ export type Align = "start" | "centre" | "end";
26
+ /**
27
+ * How much of an axis one item takes, and how much clear space goes before it.
28
+ * A gap on the first item is space at the head of the group.
29
+ */
30
+ export interface Extent {
31
+ readonly size: number;
32
+ readonly gapBefore?: number;
33
+ }
34
+ /** Where an item ended up: its start coordinate along the axis. */
35
+ export interface Placed {
36
+ readonly start: number;
37
+ readonly index: number;
38
+ }
39
+ /** Fill, corners and stroke for a rectangle. Every field is optional. */
40
+ export interface BoxStyle {
41
+ readonly fill?: string;
42
+ readonly fillOpacity?: number;
43
+ /** Corner radius. Omit for square corners. */
44
+ readonly radius?: number;
45
+ readonly stroke?: string;
46
+ readonly strokeOpacity?: number;
47
+ readonly strokeWidth?: number;
48
+ }
49
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/layout/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,mEAAmE;AACnE,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,yEAAyE;AACzE,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/layout/types.ts"],"names":[],"mappings":""}
@@ -4,7 +4,7 @@ import type { Manifest } from "../types.js";
4
4
  * Build the manifest for a planned build.
5
5
  *
6
6
  * It is built from the jobs rather than from what was written, so a rebuild
7
- * that skips every image still describes the whole site the manifest says
7
+ * that skips every image still describes the whole site. The manifest says
8
8
  * what exists, not what happened this time.
9
9
  *
10
10
  * Pages are sorted by slug, and each page's images by size name, so a manifest
@@ -27,7 +27,7 @@ function drafts(jobs) {
27
27
  * Build the manifest for a planned build.
28
28
  *
29
29
  * It is built from the jobs rather than from what was written, so a rebuild
30
- * that skips every image still describes the whole site the manifest says
30
+ * that skips every image still describes the whole site. The manifest says
31
31
  * what exists, not what happened this time.
32
32
  *
33
33
  * Pages are sorted by slug, and each page's images by size name, so a manifest
@@ -13,7 +13,7 @@ export interface PlannedManifest {
13
13
  *
14
14
  * Built while planning rather than from the results, so that a site with two
15
15
  * pages sharing a slug hears about it before rendering the tree rather than
16
- * after the same reason the output paths are checked up front.
16
+ * after. That is the same reason the output paths are checked up front.
17
17
  */
18
18
  export declare function planManifest(manifestPath: string | undefined, jobs: readonly RenderJob[]): PlannedManifest | undefined;
19
19
  /**
@@ -7,7 +7,7 @@ export { buildManifest } from "./build.js";
7
7
  *
8
8
  * Built while planning rather than from the results, so that a site with two
9
9
  * pages sharing a slug hears about it before rendering the tree rather than
10
- * after the same reason the output paths are checked up front.
10
+ * after. That is the same reason the output paths are checked up front.
11
11
  */
12
12
  export function planManifest(manifestPath, jobs) {
13
13
  return manifestPath === undefined
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * The manifest is written into a site's repository and committed, so the order
6
6
  * has to be the same on a laptop and on CI. `localeCompare` reads the default
7
- * locale, and locales disagree about case and accented letters a slug of
7
+ * locale, and locales disagree about case and accented letters, so a slug of
8
8
  * `Über` or `MyPost` could sort one way in development and another in the
9
9
  * build, leaving a diff that says nothing happened.
10
10
  */
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * The manifest is written into a site's repository and committed, so the order
6
6
  * has to be the same on a laptop and on CI. `localeCompare` reads the default
7
- * locale, and locales disagree about case and accented letters a slug of
7
+ * locale, and locales disagree about case and accented letters, so a slug of
8
8
  * `Über` or `MyPost` could sort one way in development and another in the
9
9
  * build, leaving a diff that says nothing happened.
10
10
  */
@@ -5,8 +5,8 @@ import type { ManifestPage } from "../types.js";
5
5
  * of them so far.
6
6
  *
7
7
  * A page is created from its first job rather than from an empty list, so
8
- * there is never a page without images to explain away `widest` has to name
9
- * one of them.
8
+ * there is never a page without images to explain away, since `widest` has to
9
+ * name one of them.
10
10
  */
11
11
  export interface PageDraft {
12
12
  readonly jobs: RenderJob[];
@@ -21,9 +21,9 @@ export function addToPage(page, job) {
21
21
  * Reject two pages sharing a slug.
22
22
  *
23
23
  * The manifest is keyed by slug, so a site looking a page up would find
24
- * whichever was written last an image quietly belonging to the wrong post,
25
- * which is worse than no manifest at all. Their images may well be distinct on
26
- * disk, so nothing else in the build has any reason to complain.
24
+ * whichever was written last. That is an image quietly belonging to the wrong
25
+ * post, which is worse than no manifest at all. Their images may well be
26
+ * distinct on disk, so nothing else in the build has any reason to complain.
27
27
  */
28
28
  function assertOnePage(slug, page) {
29
29
  const paths = [...new Set(page.jobs.map((job) => job.contentPath))];
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Width of `text` when there is no font to measure it in, either because none
3
+ * were configured or because the stack names one the build did not load.
4
+ *
5
+ * It is a guess, and a build that wants text laid out to the pixel supplies
6
+ * the font as a file. What it is not is a guess a template has to make: the
7
+ * one ratio lives here, where the reason for it can be written down once.
8
+ */
9
+ export declare function estimateWidth(text: string, fontSize: number, weight: number, ratio?: number): number;
10
+ //# sourceMappingURL=estimate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.d.ts","sourceRoot":"","sources":["../../src/measure/estimate.ts"],"names":[],"mappings":"AA8CA;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,EACd,KAAK,SAAe,GACnB,MAAM,CAQR"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Advance width to assume for proportional text, as a fraction of the font
3
+ * size. It is the average over the sort of text a share image carries, mostly
4
+ * lower-case Latin with spaces, for the sans-serif faces a site is likely to
5
+ * use. Nothing here is exact, which is the point of measuring instead.
6
+ */
7
+ const defaultRatio = 0.52;
8
+ /**
9
+ * Characters that occupy a full em rather than a fraction of one: the CJK
10
+ * ranges, Hangul, kana, the fullwidth forms and emoji.
11
+ *
12
+ * Estimating these at the Latin ratio is what makes a Japanese title overflow
13
+ * by nearly half its width, and no per-template fudge factor can be right for
14
+ * both scripts at once. Widths of the scripts in between, such as Devanagari,
15
+ * are still guesses; those want a font file, which is what measuring is for.
16
+ */
17
+ const wideRanges = [
18
+ [0x11_00, 0x11_5f], // Hangul Jamo
19
+ [0x2e_80, 0x30_3e], // CJK radicals and punctuation
20
+ [0x30_41, 0x33_ff], // Kana through the CJK compatibility forms
21
+ [0x34_00, 0x4d_bf], // CJK extension A
22
+ [0x4e_00, 0x9f_ff], // CJK unified ideographs
23
+ [0xa0_00, 0xa4_cf], // Yi
24
+ [0xac_00, 0xd7_a3], // Hangul syllables
25
+ [0xf9_00, 0xfa_ff], // CJK compatibility ideographs
26
+ [0xfe_30, 0xfe_4f], // CJK compatibility forms
27
+ [0xff_00, 0xff_60], // Fullwidth forms, but not the halfwidth kana after them
28
+ [0xff_e0, 0xff_e6], // Fullwidth currency and bar symbols
29
+ [0x1_f3_00, 0x1_fa_ff], // Emoji
30
+ [0x2_00_00, 0x3_ff_fd], // CJK extensions B onwards
31
+ ];
32
+ function isWide(character) {
33
+ const point = character.codePointAt(0) ?? 0;
34
+ return wideRanges.some(([from, to]) => point >= from && point <= to);
35
+ }
36
+ /**
37
+ * How much wider a face gets as its weight rises. A bold cut of a family runs
38
+ * around a tenth wider than its regular; heavier than bold, little more.
39
+ */
40
+ function weightFactor(weight) {
41
+ return 1 + Math.min(Math.max(weight - 400, 0) / 400, 1) * 0.1;
42
+ }
43
+ /**
44
+ * Width of `text` when there is no font to measure it in, either because none
45
+ * were configured or because the stack names one the build did not load.
46
+ *
47
+ * It is a guess, and a build that wants text laid out to the pixel supplies
48
+ * the font as a file. What it is not is a guess a template has to make: the
49
+ * one ratio lives here, where the reason for it can be written down once.
50
+ */
51
+ export function estimateWidth(text, fontSize, weight, ratio = defaultRatio) {
52
+ let ems = 0;
53
+ for (const character of text) {
54
+ ems += isWide(character) ? 1 : ratio;
55
+ }
56
+ return ems * fontSize * weightFactor(weight);
57
+ }
58
+ //# sourceMappingURL=estimate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.js","sourceRoot":"","sources":["../../src/measure/estimate.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B;;;;;;;;GAQG;AACH,MAAM,UAAU,GAA2C;IACzD,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc;IAClC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,+BAA+B;IACnD,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,2CAA2C;IAC/D,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,kBAAkB;IACtC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,yBAAyB;IAC7C,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,KAAK;IACzB,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,mBAAmB;IACvC,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,+BAA+B;IACnD,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,0BAA0B;IAC9C,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,yDAAyD;IAC7E,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,qCAAqC;IACzD,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,QAAQ;IAChC,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,2BAA2B;CACpD,CAAC;AAEF,SAAS,MAAM,CAAC,SAAiB;IAC/B,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC5C,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,SAAS,YAAY,CAAC,MAAc;IAClC,OAAO,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,GAAG,GAAG,CAAC;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,QAAgB,EAChB,MAAc,EACd,KAAK,GAAG,YAAY;IAEpB,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,GAAG,IAAI,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACvC,CAAC;IAED,OAAO,GAAG,GAAG,QAAQ,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Font } from "fontkit";
2
+ import type { FontSource, WarningHandler } from "../types.js";
3
+ /**
4
+ * One face loaded for measurement: the font itself, plus the family and weight
5
+ * it declares. Both are read from the file rather than from config, for the
6
+ * reason {@link FontSource} gives: the file is what the rasteriser matches on.
7
+ */
8
+ export interface Face {
9
+ readonly family: string;
10
+ readonly weight: number;
11
+ readonly font: Font;
12
+ }
13
+ /** Every face the configured fonts hold, in the order they were configured. */
14
+ export declare function loadFaces(fonts: readonly FontSource[], onWarning: WarningHandler): Promise<readonly Face[]>;
15
+ //# sourceMappingURL=faces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faces.d.ts","sourceRoot":"","sources":["../../src/measure/faces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAGpC,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE9D;;;;GAIG;AACH,MAAM,WAAW,IAAI;IACnB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;CACrB;AAuFD,+EAA+E;AAC/E,wBAAsB,SAAS,CAC7B,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,SAAS,EAAE,cAAc,GACxB,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC,CAM1B"}
@@ -0,0 +1,70 @@
1
+ import { create, open } from "fontkit";
2
+ /**
3
+ * Parsed faces, keyed by the font file's path. A build renders many images
4
+ * from one config, so without this every image would parse every font again.
5
+ */
6
+ const byPath = new Map();
7
+ /**
8
+ * The same for fonts supplied as bytes, keyed by the array itself. A config
9
+ * holds one of these and hands it to every render, so identity is enough here
10
+ * and hashing the bytes would cost more than the parse it saves.
11
+ */
12
+ const byData = new WeakMap();
13
+ /**
14
+ * What a face declares about itself. The types say both of these are always
15
+ * there, and a font file is data: one missing its name or its `OS/2` table
16
+ * would otherwise take the build down inside `selectFace`, rather than being
17
+ * measured as well as it can be. A face with no family name matches no stack,
18
+ * so it is only ever reached as the fallback that the first configured font is.
19
+ */
20
+ function toFace(font) {
21
+ const declared = font;
22
+ return {
23
+ family: declared.familyName ?? "",
24
+ weight: declared["OS/2"]?.usWeightClass ?? 400,
25
+ font,
26
+ };
27
+ }
28
+ /** A collection file holds several faces; a plain font file holds one. */
29
+ function facesOf(loaded) {
30
+ return "fonts" in loaded
31
+ ? loaded.fonts.map((font) => toFace(font))
32
+ : [toFace(loaded)];
33
+ }
34
+ /**
35
+ * Parse one configured font for measurement, or report that it could not be.
36
+ *
37
+ * A file the rasteriser accepts and this cannot is rare, but it is not fatal:
38
+ * the image still renders, and its text is laid out from estimates instead. It
39
+ * is worth saying so, because wrapping that is quietly approximate is exactly
40
+ * what supplying a font file was meant to stop. The warning goes through the
41
+ * cache below, so a build says it once per file rather than once per image.
42
+ */
43
+ async function load(font, onWarning) {
44
+ try {
45
+ return facesOf("data" in font ? create(Buffer.from(font.data)) : await open(font.path));
46
+ }
47
+ catch (error) {
48
+ const name = "data" in font ? (font.family ?? "font data") : font.path;
49
+ const reason = error instanceof Error ? error.message : String(error);
50
+ onWarning(`could not read ${name} for text measurement, so text drawn in it is` +
51
+ ` wrapped from estimates instead: ${reason}`);
52
+ return [];
53
+ }
54
+ }
55
+ function cached(font, onWarning) {
56
+ if ("data" in font) {
57
+ const pending = byData.get(font.data) ?? load(font, onWarning);
58
+ byData.set(font.data, pending);
59
+ return pending;
60
+ }
61
+ const pending = byPath.get(font.path) ?? load(font, onWarning);
62
+ byPath.set(font.path, pending);
63
+ return pending;
64
+ }
65
+ /** Every face the configured fonts hold, in the order they were configured. */
66
+ export async function loadFaces(fonts, onWarning) {
67
+ const loaded = await Promise.all(fonts.map(async (font) => cached(font, onWarning)));
68
+ return loaded.flat();
69
+ }
70
+ //# sourceMappingURL=faces.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"faces.js","sourceRoot":"","sources":["../../src/measure/faces.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAevC;;;GAGG;AACH,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,MAAM,GAAG,IAAI,OAAO,EAAwC,CAAC;AAEnE;;;;;;GAMG;AACH,SAAS,MAAM,CAAC,IAAU;IACxB,MAAM,QAAQ,GAAG,IAKhB,CAAC;IAEF,OAAO;QACL,MAAM,EAAE,QAAQ,CAAC,UAAU,IAAI,EAAE;QACjC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,IAAI,GAAG;QAC9C,IAAI;KACL,CAAC;AACJ,CAAC;AAED,0EAA0E;AAC1E,SAAS,OAAO,CAAC,MAAyC;IACxD,OAAO,OAAO,IAAI,MAAM;QACtB,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACvB,CAAC;AAED;;;;;;;;GAQG;AACH,KAAK,UAAU,IAAI,CACjB,IAAgB,EAChB,SAAyB;IAEzB,IAAI,CAAC;QACH,OAAO,OAAO,CACZ,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CACxE,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;QACvE,MAAM,MAAM,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACtE,SAAS,CACP,kBAAkB,IAAI,+CAA+C;YACnE,oCAAoC,MAAM,EAAE,CAC/C,CAAC;QACF,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,MAAM,CACb,IAAgB,EAChB,SAAyB;IAEzB,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QACnB,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QAC/D,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC/D,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,+EAA+E;AAC/E,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,KAA4B,EAC5B,SAAyB;IAEzB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,CAC9B,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CACnD,CAAC;IAEF,OAAO,MAAM,CAAC,IAAI,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { MeasureText, ResolvedConfig } from "../types.js";
2
+ export type { Face } from "./faces.js";
3
+ /**
4
+ * A {@link MeasureText} for the fonts a build is rendering with.
5
+ *
6
+ * Widths are held per em and multiplied by the font size on the way out, which
7
+ * is what makes fitting text affordable: choosing a size means wrapping the
8
+ * same words several times over, and only the last multiplication differs.
9
+ * Text is unhinted at these sizes, so the scaling is exact rather than close.
10
+ *
11
+ * The cache lives for as long as the measurer, which is one image. Titles
12
+ * repeat across the sizes of an image and rarely between images, so a longer
13
+ * life would hold a build's worth of strings to save very little.
14
+ */
15
+ export declare function createMeasurer(config: ResolvedConfig): Promise<MeasureText>;
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/measure/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAa,MAAM,aAAa,CAAC;AAO1E,YAAY,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AA8CvC;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,WAAW,CAAC,CAgBtB"}
Binary file
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/measure/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAIzC;;;;;;;;GAQG;AACH,SAAS,OAAO,CACd,KAAsB,EACtB,KAAgB,EAChB,cAAuB;IAEvB,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,IAAI,GAAG,CAAC;IAEvC,OAAO,CACL,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,EAAE,MAAM,CAAC;QAC3C,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CACxC,CAAC;AACJ,CAAC;AAED,gEAAgE;AAChE,SAAS,SAAS,CAChB,IAAY,EACZ,KAAgB,EAChB,KAAsB,EACtB,cAAuB;IAEvB,MAAM,MAAM,GAAG,KAAK,CAAC,UAAU,IAAI,GAAG,CAAC;IACvC,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;IAEtD,IAAI,GAAG,GAAG,CAAC,CAAC;IAEZ,KAAK,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;QACrD,GAAG;YACD,GAAG,CAAC,IAAI,KAAK,SAAS;gBACpB,CAAC,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,aAAa,CAAC;gBACzD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAsB;IAEtB,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;IAC9D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;IAExC,OAAO,CAAC,IAAY,EAAE,KAAgB,EAAU,EAAE;QAChD,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC,UAAU,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,aAAa,IAAI,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QAClH,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAE7B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC;QAChC,CAAC;QAED,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9D,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACpB,OAAO,GAAG,GAAG,KAAK,CAAC,QAAQ,CAAC;IAC9B,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { Face } from "./faces.js";
2
+ /**
3
+ * A stretch of text and the face that will draw it, or no face where nothing
4
+ * loaded covers it and the width has to be estimated.
5
+ */
6
+ export interface TextRun {
7
+ readonly text: string;
8
+ readonly face: Face | undefined;
9
+ }
10
+ /** Advance width of `text` in `face`, as a multiple of the font size. */
11
+ export declare function emWidth(text: string, face: Face): number;
12
+ /**
13
+ * Split `text` into the longest runs that one face can draw. Text a build has
14
+ * supplied fonts for comes back as a single run, which is the common case.
15
+ */
16
+ export declare function coverageRuns(text: string, primary: Face | undefined, faces: readonly Face[]): readonly TextRun[];
17
+ //# sourceMappingURL=runs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.d.ts","sourceRoot":"","sources":["../../src/measure/runs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,SAAS,CAAC;CACjC;AAED,yEAAyE;AACzE,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAExD;AA0BD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,IAAI,GAAG,SAAS,EACzB,KAAK,EAAE,SAAS,IAAI,EAAE,GACrB,SAAS,OAAO,EAAE,CAepB"}
@@ -0,0 +1,39 @@
1
+ /** Advance width of `text` in `face`, as a multiple of the font size. */
2
+ export function emWidth(text, face) {
3
+ return face.font.layout(text).advanceWidth / face.font.unitsPerEm;
4
+ }
5
+ /**
6
+ * The face that will draw one character: the one the style resolved to, or the
7
+ * first other loaded face holding a glyph for it. This is what the rasteriser
8
+ * does with a missing glyph, and measuring a Japanese title against a Latin
9
+ * face that has none of it would be worse than not measuring at all.
10
+ */
11
+ function coveringFace(character, primary, faces) {
12
+ const point = character.codePointAt(0);
13
+ if (point === undefined) {
14
+ return primary;
15
+ }
16
+ if (primary?.font.hasGlyphForCodePoint(point) === true) {
17
+ return primary;
18
+ }
19
+ return faces.find((face) => face.font.hasGlyphForCodePoint(point));
20
+ }
21
+ /**
22
+ * Split `text` into the longest runs that one face can draw. Text a build has
23
+ * supplied fonts for comes back as a single run, which is the common case.
24
+ */
25
+ export function coverageRuns(text, primary, faces) {
26
+ const runs = [];
27
+ for (const character of text) {
28
+ const face = coveringFace(character, primary, faces);
29
+ const last = runs.at(-1);
30
+ if (last === undefined || last.face !== face) {
31
+ runs.push({ text: character, face });
32
+ }
33
+ else {
34
+ runs[runs.length - 1] = { text: last.text + character, face };
35
+ }
36
+ }
37
+ return runs;
38
+ }
39
+ //# sourceMappingURL=runs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/measure/runs.ts"],"names":[],"mappings":"AAWA,yEAAyE;AACzE,MAAM,UAAU,OAAO,CAAC,IAAY,EAAE,IAAU;IAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;AACpE,CAAC;AAED;;;;;GAKG;AACH,SAAS,YAAY,CACnB,SAAiB,EACjB,OAAyB,EACzB,KAAsB;IAEtB,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IAEvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,IAAI,OAAO,EAAE,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC;QACvD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAC;AACrE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,OAAyB,EACzB,KAAsB;IAEtB,MAAM,IAAI,GAAc,EAAE,CAAC;IAE3B,KAAK,MAAM,SAAS,IAAI,IAAI,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,YAAY,CAAC,SAAS,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAEzB,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YAC7C,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,SAAS,EAAE,IAAI,EAAE,CAAC;QAChE,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { Face } from "./faces.js";
2
+ /**
3
+ * The families named by a CSS-style stack, in order and unquoted, so that
4
+ * `'"JetBrains Mono", Menlo, monospace'` becomes three names to try.
5
+ */
6
+ export declare function familyNames(stack: string): readonly string[];
7
+ /**
8
+ * The face a style resolves to, or `undefined` when the stack names nothing
9
+ * that was loaded. Families are tried in the order the stack lists them, which
10
+ * is what a stack means.
11
+ */
12
+ export declare function selectFace(faces: readonly Face[], stack: string, weight: number): Face | undefined;
13
+ //# sourceMappingURL=select.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.d.ts","sourceRoot":"","sources":["../../src/measure/select.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEvC;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAU5D;AA4BD;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GACb,IAAI,GAAG,SAAS,CAUlB"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The families named by a CSS-style stack, in order and unquoted, so that
3
+ * `'"JetBrains Mono", Menlo, monospace'` becomes three names to try.
4
+ */
5
+ export function familyNames(stack) {
6
+ return stack
7
+ .split(",")
8
+ .map((name) => name
9
+ .trim()
10
+ .replaceAll(/^["']|["']$/g, "")
11
+ .trim())
12
+ .filter((name) => name !== "");
13
+ }
14
+ /** Faces belonging to one family, matched as the rasteriser matches them. */
15
+ function inFamily(faces, family) {
16
+ const wanted = family.toLowerCase();
17
+ return faces.filter((face) => face.family.toLowerCase() === wanted);
18
+ }
19
+ /**
20
+ * The face nearest the requested weight. A family supplying only a regular cut
21
+ * is drawn in that cut by the rasteriser rather than being emboldened, so
22
+ * measuring the nearest weight is measuring what will actually appear.
23
+ */
24
+ function nearestWeight(faces, weight) {
25
+ let best = faces[0];
26
+ for (const face of faces) {
27
+ if (Math.abs(face.weight - weight) < Math.abs(best.weight - weight)) {
28
+ best = face;
29
+ }
30
+ }
31
+ return best;
32
+ }
33
+ /**
34
+ * The face a style resolves to, or `undefined` when the stack names nothing
35
+ * that was loaded. Families are tried in the order the stack lists them, which
36
+ * is what a stack means.
37
+ */
38
+ export function selectFace(faces, stack, weight) {
39
+ for (const family of familyNames(stack)) {
40
+ const [first, ...rest] = inFamily(faces, family);
41
+ if (first !== undefined) {
42
+ return nearestWeight([first, ...rest], weight);
43
+ }
44
+ }
45
+ return undefined;
46
+ }
47
+ //# sourceMappingURL=select.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/measure/select.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,KAAK;SACT,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CACZ,IAAI;SACD,IAAI,EAAE;SACN,UAAU,CAAC,cAAc,EAAE,EAAE,CAAC;SAC9B,IAAI,EAAE,CACV;SACA,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,6EAA6E;AAC7E,SAAS,QAAQ,CAAC,KAAsB,EAAE,MAAc;IACtD,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;IACpC,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,CAAC,CAAC;AACtE,CAAC;AAED;;;;GAIG;AACH,SAAS,aAAa,CACpB,KAAiC,EACjC,MAAc;IAEd,IAAI,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAEpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;YACpE,IAAI,GAAG,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,KAAsB,EACtB,KAAa,EACb,MAAc;IAEd,KAAK,MAAM,MAAM,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAEjD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,aAAa,CAAC,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -3,14 +3,14 @@ import type { Manifest, MetaTag, MetaTagOptions } from "../types.js";
3
3
  * The social meta tags for one page of a {@link Manifest}.
4
4
  *
5
5
  * Generating the image is half the job: a site still has to write the tags,
6
- * and every site ends up with slightly different results a missing width, a
7
- * relative URL a crawler cannot resolve, a large card promising an image that
8
- * is square.
6
+ * and every site ends up with slightly different results: a missing width, a
7
+ * relative URL a crawler cannot resolve, or a large card promising an image
8
+ * that is square.
9
9
  *
10
10
  * A page the manifest does not have gets no tags rather than an error. Not
11
- * every page has a share image a props mapper returning `undefined` is how a
12
- * site says so and a template asking about one should not have to know in
13
- * advance.
11
+ * every page has a share image, and a props mapper returning `undefined` is
12
+ * how a site says so, so a template asking about one should not have to know
13
+ * in advance.
14
14
  *
15
15
  * Alt text is emitted for both platforms when the page has any. Twitter reads
16
16
  * its own `twitter:image:alt` rather than falling back to the Open Graph one,
package/dist/meta/tags.js CHANGED
@@ -30,14 +30,14 @@ function imageUrl(slug, image, options) {
30
30
  * The social meta tags for one page of a {@link Manifest}.
31
31
  *
32
32
  * Generating the image is half the job: a site still has to write the tags,
33
- * and every site ends up with slightly different results a missing width, a
34
- * relative URL a crawler cannot resolve, a large card promising an image that
35
- * is square.
33
+ * and every site ends up with slightly different results: a missing width, a
34
+ * relative URL a crawler cannot resolve, or a large card promising an image
35
+ * that is square.
36
36
  *
37
37
  * A page the manifest does not have gets no tags rather than an error. Not
38
- * every page has a share image a props mapper returning `undefined` is how a
39
- * site says so and a template asking about one should not have to know in
40
- * advance.
38
+ * every page has a share image, and a props mapper returning `undefined` is
39
+ * how a site says so, so a template asking about one should not have to know
40
+ * in advance.
41
41
  *
42
42
  * Alt text is emitted for both platforms when the page has any. Twitter reads
43
43
  * its own `twitter:image:alt` rather than falling back to the Open Graph one,
@@ -6,10 +6,10 @@
6
6
  * the placement's `urlBase` said, which is usually site-relative, so this is
7
7
  * where the two halves meet.
8
8
  *
9
- * A URL that names its own scheme is returned untouched a placement pointing
10
- * at a CDN has said everything there is to say. A scheme-relative one (`//cdn`)
11
- * has not: it is relative to the page's scheme, which is exactly what a crawler
12
- * reading the tag elsewhere does not have, so it borrows the base's.
9
+ * A URL that names its own scheme is returned untouched, since a placement
10
+ * pointing at a CDN has said everything there is to say. A scheme-relative one
11
+ * (`//cdn`) has not: it is relative to the page's scheme, which is exactly what
12
+ * a crawler reading the tag elsewhere does not have, so it borrows the base's.
13
13
  */
14
14
  export declare function absoluteUrl(url: string, baseUrl: string | undefined): string;
15
15
  //# sourceMappingURL=url.d.ts.map
package/dist/meta/url.js CHANGED
@@ -15,10 +15,10 @@ function schemeOf(url) {
15
15
  * the placement's `urlBase` said, which is usually site-relative, so this is
16
16
  * where the two halves meet.
17
17
  *
18
- * A URL that names its own scheme is returned untouched a placement pointing
19
- * at a CDN has said everything there is to say. A scheme-relative one (`//cdn`)
20
- * has not: it is relative to the page's scheme, which is exactly what a crawler
21
- * reading the tag elsewhere does not have, so it borrows the base's.
18
+ * A URL that names its own scheme is returned untouched, since a placement
19
+ * pointing at a CDN has said everything there is to say. A scheme-relative one
20
+ * (`//cdn`) has not: it is relative to the page's scheme, which is exactly what
21
+ * a crawler reading the tag elsewhere does not have, so it borrows the base's.
22
22
  */
23
23
  export function absoluteUrl(url, baseUrl) {
24
24
  if (baseUrl === undefined || schemed.test(url)) {
@@ -6,7 +6,7 @@ import type { Placement } from "../types.js";
6
6
  * JavaScript with nothing checking it, and none of these omissions fails
7
7
  * anywhere near the config: a missing `dir` surfaces as a complaint about an
8
8
  * argument to `path`, and the rest as something not being a function. Key
9
- * validation is no help either it is the option that is not there.
9
+ * validation is no help either, since it is the option that is not there.
10
10
  *
11
11
  * This sits here rather than in `validate/`, which checks keys and the names
12
12
  * of closed sets, for the reason `fonts/resolve.ts` does: what a value has to