# `Expresso.SvgCopy`
[🔗](https://github.com/rellen/expresso/blob/main/lib/expresso/svg_copy.ex#L1)

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.

# `copy`

```elixir
@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`

```elixir
@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`

```elixir
@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>|

---

*Consult [api-reference.md](api-reference.md) for complete listing*
