What's going on in these #box?

Why are the output layouts of these boxes different?

** i not put any space between 1 and (xyz)

First Case

#box(width: 0pt, stroke: 1pt+yellow, "1(abc)")

image

Second Case

#box(width: 0pt, stroke: 1pt+yellow,  "1.(abc)")

Why does the output behave like an enum in the second case ?; What am I missing here?

The algorithm tries to make the text the same width as the box it’s in, to prevent it going outside (like we see in your pictures). The presence of a period in 1.(abc) signals that a word break is possible here, and as the box is 0pt wide every possible word break is made.

Did you really want a 0pt box, or did you want to achieve having the yellow stroke only on the left side? If so, try:

#box(width: auto, stroke: (left: 1pt+yellow),  "1.(abc)")
1 Like

i want zero width box so later i can use #move inside it (to achieve enum like structure which not misaligned when we have matrix, vector or big symbols | #1204)

like

#box(width:0pt, move(align(end,"1.(a)"), dx: -1em))

Because we currently don’t have a baseline alignment option (in both enum and grid/table).
so how can we prevent word break here(without using another box with pre-fixed width) ? or there more better approach to achieve this

Use U+2060 WORD JOINER (sym.wj).

#box(width: 0pt, stroke: 1pt + yellow, "1.(abc)")

#box(width: 0pt, stroke: 1pt + yellow, {
  "1."
  sym.wj
  "(abc)"
  // Or equivalently, "1.\u{2060}(abc)"
})

Edit: As pointed below by flokl, word joiner is more appropriate. I’ve edited my answer.

Old answer

Use U+FEFF ZERO WIDTH NO-BREAK SPACE.

#box(width: 0pt, stroke: 1pt + yellow, "1.(abc)")

#box(width: 0pt, stroke: 1pt + yellow, "1.\u{feff}(abc)")

Note that box also has baseline alignment problem when text.bottom-edge ≠ "baseline".

#set text(bottom-edge: "descender")
#grid(
  stroke: green + 0.5pt,
  [#box[g];a],
  [ga],
)

3 Likes

Another possible (and not too uncommon) technique is to wrap the inner content in a box with infinite width like so

#box(
  width: 0pt, 
  box(
    width: 1pt * float.inf,
    move(align(end,"1.(a)"), dx: -1em)
  )
)

This lifts the size constraint that is applied to everything inside the outer zero-width box.

In particular this works for any content and is therefore useful for packages when the content is provided by the user.

6 Likes

Note, U+FEFF should no longer be used to prevent linebreaks, instead U+2060 (in Typst sym.wj) should be preferred.

4 Likes

Indeed! I didn’t know that.

Quoting Unicode Standard Annex #14: Unicode Line Breaking Algorithm:

LB11 Do not break before or after Word joiner and related characters.

WJ: Word Joiner (Non-tailorable)

LB11, LB15b

These characters glue together left and right neighbor characters such that they are kept on the same line.

Code point Character name
2060 WORD JOINER (WJ)
FEFF ZERO WIDTH NO-BREAK SPACE (ZWNBSP)

The word joiner character is the preferred choice for an invisible character to keep other characters together that would otherwise be split across the line at a direct break. The character FEFF has the same effect, but because it is also used in an unrelated way as a byte order mark, the use of the WJ as the preferred interword glue simplifies the handling of FEFF.

By definition, WJ and ZWNBSP take precedence over the action of SP, but not ZW.

But in both cases it will disrupt the selectable text and search. What's going on in these #box? - #6 by Mc-Zen probably doesn’t have such issues.

Nooo :frowning:, I only knew about issues with ZWS (U+200B) is there an open issue for WJ? I can’t find one.

I don’t know if any of these should or can be absent in the document. Selectable and visual functionalities are probably coupled.