Expresso.SvgCopy (expresso v0.1.0)

Copy Markdown View Source

Makes each copy of an SVG in a document independent of the other copies

The document holds each slide three or more times: in the present view, on each page of the handout view and in the menu. A copy of an SVG then needs its own ids and its own style rules, for two causes:

  • A browser resolves a reference such as url(#fill) to the first element of the document with that id. That element can be in a view that the browser does not show, and a gradient, a clip or a mask in a hidden view does not paint.
  • A <style> element in an inline SVG applies to the whole document. Two files with the same class names then change the colors of each other.

number/2 puts the number of the copy after each id of the SVG, and it puts the same number into each url(#id), each href="#id" and each #id selector of a <style>. It makes a map from each old id to its new id, and it changes the text in one pass, so an id such as g1-2 does not change two times. Then it limits each rule of each <style> to the copy: the root svg element gets data-svg-copy with the number, and the subject of each selector gets :where([data-svg-copy="N"], [data-svg-copy="N"] *). The :where adds no specificity, so the rules of the file keep their order against the rules of the theme.

A rule in @media, @supports, @container or @layer gets the same change. Other at-rules, such as @keyframes and @font-face, stay as they are.

Expresso.Element.Diagram, Expresso.Element.Icon, Expresso.Element.TextArea and Expresso.Element.Item use this module, and Expresso.Copies.next/0 gives the number.

Summary

Functions

Number the copy of an SVG with the next number of Expresso.Copies

Number each SVG of an HTML text with its own number

Put a number into each id, each reference and each style rule of an SVG

Functions

copy(svg)

@spec copy(String.t()) :: String.t()

Number the copy of an SVG with the next number of Expresso.Copies

An SVG with no id and no <style> stays as it is, and it takes no number.

iex> Expresso.SvgCopy.copy(~s(<svg viewBox="0 0 1 1"><path d="M0 0h1"/></svg>))
~s(<svg viewBox="0 0 1 1"><path d="M0 0h1"/></svg>)

copy_each(html)

@spec copy_each(String.t()) :: String.t()

Number each SVG of an HTML text with its own number

A text area and an item can hold more than one inline icon, and two icons with the same file must have different ids.

number(svg, number)

@spec number(String.t(), pos_integer()) :: String.t()

Put a number into each id, each reference and each style rule of an SVG

iex> Expresso.SvgCopy.number(~s|<svg><linearGradient id="g1"/><linearGradient id="g1-2"/><rect fill="url(#g1-2)"/></svg>|, 2)
~s|<svg><linearGradient id="g1-2"/><linearGradient id="g1-2-2"/><rect fill="url(#g1-2-2)"/></svg>|

iex> Expresso.SvgCopy.number(~s(<svg id="s"><style>#s .a, b::before{fill:red}</style></svg>), 3)
~s|<svg data-svg-copy="3" id="s-3"><style>#s-3 .a:where([data-svg-copy="3"], [data-svg-copy="3"] *), b:where([data-svg-copy="3"], [data-svg-copy="3"] *)::before{fill:red}</style></svg>|