How to reference figures created through a custom figure function?

I have a custom function for figures (my-block) and I am trying to add spacing above the figure which only activates after a line of text. That is, the padding above is not added if a my-block follows another my-block or a heading.

This is achieved by using the below:

par(spacing: 1.5cm)[] // padding above only on if it follows a paragraph
block(above: 0cm, below: 1.5cm) // padding below always on

See below for a MWE:

// mypackage:

#show figure.where(kind: "block"): set align(left)

#let set_figure_spacing(it) = {
  show figure.where(kind: "block"): it => {
    par(spacing: 1.5cm)[]
    block(above: 0cm, below: 1.5cm, it
    )
  }

  it
}

#let my-block(body, ..args) = {
  figure(kind: "block", supplement: "Block", {
    block(fill: red.lighten(70%), ..args, [#body])
  }
  )
}

//import: "mypackage.typ" *

// // wishing to remove this line and have it fully implemented on the basis of the package import above.
#show: set_figure_spacing

== Heading
#my-block[This is a block.] <ref>

Content goes in here @ref

#my-block[This is a block.]
#my-block[This is a block.]

Works.

Output:

The issue is that I have to use a show rule to get around putting the padding directly in my-block, as if I try and do this I am presented with the error: “cannot reference sequence”, e.g.

#let my-block(body, ..args) = {
  par(spacing: 1.5cm)[]
  figure(kind: "block", supplement: "Block", {
    block(fill: red.lighten(70%), ..args, [#body])
  }
  )
}

For more complex reasons, I can’t have anything in my main doc other than the package import, and currently not able to execute show in the package so it then flows through to where the package is called.

Looking for one of the two solutions:

  1. The ability to call show in the package and it be automatically applied when we import the package into a new doc
  2. The ability to include par(spacing: 1.5cm)[] at the top and block(above:0cm, below: 1.5cm) at the bottom within my-block

As both will allow the package import with no other code to achieve desired functionality.

Is either possible?

When I try this, it doesn’t seem to work, do you have an example where it works?

Trying:

= Heading
#par(spacing: 1.5cm)[]
#figure[A]

Still produces a gap between the heading and the figure in this case.


I will help and clarify why this happens: Without the extra par, then my-block returns a figure and the label <ref> attaches to the figure. When par is added, the combined result of my-block is another content value that contains the value, and that content no longer supports being referenced. So the error is caused by not returning a figure, and it’s triggered by the @ref.

For this to work well we would have to style my-block figures globally (not inside the my-block function).

For example like this, which adds the same par but in a way that doesn’t get in the way of the label <ref> attaching to the function:

#show figure.where(kind: "block"): it => par(spacing: 1.5cm)[] + it
1 Like

I believe my MWE compiles? Apologies I don’t quite follow what doesn’t work?

Yes thank you re show option to style globally.

I guess the. We are reduced to one question if there is no alternative to using #show

Can we execute show indirectly by just calling the file / package or must it be executed directly in the document?

That’s right, I guess I tried something different (the code in my post) and pointed out that doesn’t work for the purpose - I’m sorry for the confusion. I didn’t catch the detail of how you were wrapping the figure in the block. Now I get it. :slightly_smiling_face:

It must be called explicitly. This is also how templates work, the documentation usually has the exact line the user needs to copy and apply to the top of their document.

If you want a custom kind of figure or element, maybe the elembic package could help. But ‘unfortunately’ even there, while it can do a lot, if you want the custom figure to support references, a show call in the final is necessary even there.

1 Like