This is the proper way to do it (as of Typst 0.11 and 0.12)! The code inside the figure numbering function is given the original location of the figure as context, meaning any counter accesses in that function (including to the heading counter) will correctly return the value at where the figure was placed, even if the numbering is used in the outline. This won’t hold if you create a new context block inside the figure numbering function (then, the context will be relative to where the numbering is placed, not to the figure itself), so please don’t do that.
Regarding your solution, I’d note that the numbering function can be used to specify numbering formats (such as alphabetic) instead of having to implement that on your own: Numbering Function – Typst Documentation
Therefore, your figure set rule can be improved as follows (giving the same results):
#set figure(numbering: n => {
let appx = state("backmatter", false).get()
let hdr = counter(heading).get()
let format = if appx {
"A.1."
} else {
"1.1"
}
// Replace 'hdr.first()' by '..hdr' to display
// all heading levels
numbering(format, hdr.first(), n)
})
huh, yeah you’re right, reimplementing the numbering isn’t necessary, not sure anymore why I ended up doing that.
my point about the numbering not being correctly tracked is that i’d like to be able to just use counter(heading).display(), and for it to use the correct numbering of the heading. This does however not work as I would expect.
Your answer did however get me thinking, and I took some time to tinker. I finally figured out how to get this to work without having multiple “sources of truth” as to what numbering to use where. It also does away with having to use the “backmatter” state, and is therefore cleaner.
#set figure(numbering: n => {
let hdr = counter(heading).get().first()
let num = query(
selector(heading).before(here())
).last().numbering
numbering(num, hdr, n)
})
this seems to work correctly, in the figures, references, and outlines as well.