@tonguetoquill/collection 0.2.6 → 0.2.7

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.2.6",
3
+ "version": "0.2.7",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/nibsbin/tonguetoquill-collection.git"
@@ -7,29 +7,60 @@
7
7
  #let FORM_MIN_TEXT_SIZE = 6pt
8
8
  #let FORM_MIN_CHARS_PER_LINE = 7
9
9
 
10
- /// Render a text-like field with word-wrapping and shrink-to-fit.
10
+ /// Should this field shrink text to a single line rather than word-wrap?
11
+ /// True for short/narrow fields with brief content (grades, ranks, dates).
12
+ #let should-shrink-to-fit(display, width, height) = {
13
+ let aspect = width / height
14
+ let char-count = display.len()
15
+ char-count <= 10 or height < 20pt or aspect > 4.0
16
+ }
17
+
18
+ /// Render a text-like field with shrink-to-fit and word-wrap fallback.
11
19
  #let render-text-field(display, width, height, x-inset, y-inset) = {
12
20
  set par(leading: 0.25em)
13
21
  context {
22
+ let avail-w = width - 2 * x-inset
23
+ let avail-h = height - 2 * y-inset
24
+ let shrink = should-shrink-to-fit(display, width, height)
25
+
14
26
  let final-size = FORM_MIN_TEXT_SIZE
15
27
  let current = FORM_MAX_TEXT_SIZE
16
28
  let step = 0.5pt
17
29
 
18
- // Find the largest font size that fits both horizontally and vertically
19
- // and optionally leaves enough room for a minimum number of characters
20
30
  while current >= FORM_MIN_TEXT_SIZE {
21
- let m = measure(block(width: width - 2 * x-inset, text(size: current, display)))
31
+ let m = if shrink {
32
+ // Measure as a single line (no width constraint → no wrapping)
33
+ measure(text(size: current, display))
34
+ } else {
35
+ // Measure with wrapping within the available width
36
+ measure(block(width: avail-w, text(size: current, display)))
37
+ }
22
38
  let char-m = measure(text(size: current, "0" * FORM_MIN_CHARS_PER_LINE))
23
39
 
24
- if m.height <= height - 2 * y-inset and char-m.width <= width - 2 * x-inset {
40
+ if m.width <= avail-w and m.height <= avail-h and char-m.width <= avail-w {
25
41
  final-size = current
26
42
  break
27
43
  }
28
44
  current = current - step
29
45
  }
30
- // Alignment: center vertically if it's a short box (likely single line),
31
- // otherwise top-align for multi-line paragraphs.
32
- let vert-align = if height < 24pt { horizon } else { top }
46
+
47
+ // Fallback: if shrink-to-fit hit min size and still overflows,
48
+ // re-try with word-wrap enabled as a last resort.
49
+ if shrink and current < FORM_MIN_TEXT_SIZE {
50
+ current = FORM_MAX_TEXT_SIZE
51
+ while current >= FORM_MIN_TEXT_SIZE {
52
+ let m = measure(block(width: avail-w, text(size: current, display)))
53
+ let char-m = measure(text(size: current, "0" * FORM_MIN_CHARS_PER_LINE))
54
+ if m.height <= avail-h and char-m.width <= avail-w {
55
+ final-size = current
56
+ break
57
+ }
58
+ current = current - step
59
+ }
60
+ }
61
+
62
+ // Default to vertically centered. Only top-align for tall "text areas".
63
+ let vert-align = if height >= 40pt { top } else { horizon }
33
64
 
34
65
  box(
35
66
  width: width,