@tonguetoquill/collection 0.17.0 → 0.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonguetoquill/collection",
3
- "version": "0.17.0",
3
+ "version": "0.17.2",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/nibsbin/tonguetoquill-collection.git"
@@ -312,8 +312,16 @@
312
312
  if i == total_count {
313
313
  let available_width = page.width - spacing.margin * 2
314
314
 
315
- // Use configured paragraph metrics for line height estimation
316
- let line_height = measure(line(length: spacing.line + spacing.line-height)).width
315
+ // Use the shared measured line stride used by blank-line spacing.
316
+ let line_height = {
317
+ let cached = LINE_STRIDE.get()
318
+ if cached != none {
319
+ cached
320
+ } else {
321
+ let one-line = measure(par(spacing: 0pt)[x]).height
322
+ measure(par(spacing: 0pt)[x#linebreak()x]).height - one-line
323
+ }
324
+ }
317
325
  // Calculate last item's height
318
326
  let par_height = measure(final_par, width: available_width).height
319
327
 
@@ -9,8 +9,10 @@
9
9
  // AFH 33-337 specifies precise spacing requirements throughout Chapter 14
10
10
 
11
11
  #let spacing = (
12
- vertical: 19.05pt, // Base gap between elements
13
- line: .5em, // Internal line spacing for readability
12
+ // Legacy exported field retained for compatibility with downstream imports.
13
+ // Internal blank-line spacing now uses measured line stride from utils.typ.
14
+ vertical: 19.05pt,
15
+ line: .5em, // Internal line spacing for readability (`par.leading`; gap between line boxes)
14
16
  line-height: .7em, // Base height of text lines for pagination estimates
15
17
  tab: 0.5in, // Tab stop for multi-column recipient alignment
16
18
  margin: 1in, // AFH 33-337 §4: "Use 1-inch margins on the left, right and bottom"
@@ -107,11 +107,15 @@
107
107
  // Since we have a 1-inch top margin, we need (1.75in - margin) vertical space
108
108
  v(1.75in - spacing.margin)
109
109
 
110
- render-date-section(actual_date, memo-style: memo_style)
111
- render-for-section(memo_for, memo_for_cols)
112
- render-from-section(memo_from)
113
- render-subject-section(subject)
114
- render-references-section(references)
110
+ // Measure and cache body line stride once for downstream spacing logic.
111
+ context {
112
+ let one-line = measure(par(spacing: 0pt)[x]).height
113
+ let line-stride = measure(par(spacing: 0pt)[x#linebreak()x]).height - one-line
114
+ let em-size = measure(box(width: 1em)[]).width
115
+ let legacy-scaled = spacing.vertical * (em-size / 12pt)
116
+ LINE_STRIDE.update(line-stride)
117
+ BLANK_LINE_STEP.update(calc.max(line-stride, legacy-scaled))
118
+ }
115
119
 
116
120
  metadata((
117
121
  subject: subject,
@@ -123,5 +127,11 @@
123
127
  memo_style: memo_style,
124
128
  ))
125
129
 
130
+ render-date-section(actual_date, memo-style: memo_style)
131
+ render-for-section(memo_for, memo_for_cols)
132
+ render-from-section(memo_from)
133
+ render-subject-section(subject)
134
+ render-references-section(references)
135
+
126
136
  it
127
137
  }
@@ -52,14 +52,17 @@
52
52
  #fit-box(width: 2in, height: 1in)[#letterhead-seal]
53
53
  ]
54
54
  } else {
55
+ // Isolate seal column from document `font_size`: stack `em` spacing and subtitle
56
+ // must not scale with body text (see frontmatter `set text(size: font_size)`).
55
57
  block(width: 2in)[
58
+ #set text(9pt, font: font, fill: LETTERHEAD_COLOR, weight: "bold")
56
59
  #align(left)[
57
- #stack(spacing: 0.15em)[
58
- #fit-box(width: 2in, height: 1in)[#letterhead-seal]
59
- #text(9pt, font: font, fill: LETTERHEAD_COLOR, weight: "bold")[
60
- #upper(ensure-string(letterhead-seal-subtitle))
61
- ]
62
- ]
60
+ // Spacing applies between positional stack children only, not one `[…]` body.
61
+ #stack(
62
+ spacing: 0.5em,
63
+ fit-box(width: 2in, height: 1in)[#letterhead-seal],
64
+ upper(ensure-string(letterhead-seal-subtitle)),
65
+ )
63
66
  ]
64
67
  ]
65
68
  }
@@ -14,10 +14,15 @@
14
14
 
15
15
  #import "config.typ": CLASSIFICATION_COLORS, counters, paragraph-config, spacing
16
16
 
17
+ // Shared measured line-stride cache used by blank-line spacing and body
18
+ // line-count heuristics. Value is a `length` set once in `frontmatter`.
19
+ #let LINE_STRIDE = state("LINE_STRIDE")
20
+ // Shared blank-line step cache used by structural spacing.
21
+ #let BLANK_LINE_STEP = state("BLANK_LINE_STEP")
22
+
17
23
  /// Creates vertical spacing equivalent to multiple blank lines.
18
24
  ///
19
- /// Calculates proper vertical space using the centralized `spacing.vertical`
20
- /// configuration to maintain consistent gap spacing throughout the document.
25
+ /// Each step matches one row of the body paragraph line grid.
21
26
  ///
22
27
  /// - count (int): Number of blank lines to create
23
28
  /// - weak (bool): Whether spacing can be compressed at page breaks
@@ -26,8 +31,20 @@
26
31
  if count == 0 {
27
32
  v(0em, weak: weak)
28
33
  } else {
29
- // vertical uses the centralized vertical spacing from config
30
- v(spacing.vertical * count, weak: weak)
34
+ context {
35
+ let measured-stride = {
36
+ let one-line = measure(par(spacing: 0pt)[x]).height
37
+ measure(par(spacing: 0pt)[x#linebreak()x]).height - one-line
38
+ }
39
+ // Scale legacy visual step with current font size:
40
+ // 19.05pt was tuned for 12pt body text.
41
+ let em-size = measure(box(width: 1em)[]).width
42
+ let legacy-scaled = spacing.vertical * (em-size / 12pt)
43
+ let fallback-step = calc.max(measured-stride, legacy-scaled)
44
+ let cached-step = BLANK_LINE_STEP.get()
45
+ let step = if cached-step != none { cached-step } else { fallback-step }
46
+ v(step * count, weak: weak)
47
+ }
31
48
  }
32
49
  }
33
50
 
@@ -34,7 +34,7 @@
34
34
  memo_style: data.at("memo_style", default: "usaf"),
35
35
 
36
36
  // Font size
37
- ..if "font_size" in data { (font_size: float(data.font_size) * 1pt) },
37
+ font_size: data.at("font_size", default: 12) * 1pt,
38
38
 
39
39
  // List recipients in vertical list
40
40
  memo_for_cols: 1,