# `Delta.Op`
[🔗](https://github.com/slab/delta-elixir/blob/main/lib/delta/op.ex#L1)

# `attributes`

```elixir
@type attributes() :: %{required(String.t()) =&gt; attributes_val()}
```

Stand-in type while attributes is keyed with String.t() instead of Atom.t()

# `delete_op`

```elixir
@type delete_op() :: %{
  required(delete_key()) =&gt; pos_integer(),
  optional(attributes()) =&gt; attributes_val()
}
```

Stand-in type while operators are keyed with String.t() instead of Atom.t()

`%{delete: pos_integer()}`

# `insert_op`

```elixir
@type insert_op() :: %{
  required(insert_key()) =&gt; insert_val(),
  optional(attributes()) =&gt; attributes_val()
}
```

Stand-in type while operators are keyed with String.t() instead of Atom.t()

`%{insert: String.t() | EmbedHandler.embed(), ...}`

# `operation`

```elixir
@type operation() :: insert_key() | retain_key() | delete_key()
```

Stand-in type while operators are keyed with String.t() instead of Atom.t()

# `retain_op`

```elixir
@type retain_op() :: %{
  required(retain_key()) =&gt; retain_val(),
  optional(attributes()) =&gt; attributes_val()
}
```

Stand-in type while operators are keyed with String.t() instead of Atom.t()

`%{retain: pos_integer() | EmbedHandler.embed()}`

# `t`

```elixir
@type t() :: insert_op() | retain_op() | delete_op()
```

# `compose`

```elixir
@spec compose(a :: t(), b :: t()) :: {t() | false, t(), t()}
```

# `delete`

```elixir
@spec delete(value :: delete_val(), attr :: attributes_val()) :: delete_op()
```

A shorthand for `new("delete", value, attributes)`. See `new/3`.

## Examples
    iex> Op.delete(1, %{"bold" => true})
    %{"delete" => 1, "attributes" => %{"bold" => true}}

# `delete?`

```elixir
@spec delete?(op :: t(), type :: any()) :: boolean()
```

A shorthand for `type?(op, "delete", type)`. See `type?/3`.

## Examples
    iex> Op.delete(1) |> Op.delete?()
    true

# `get_embed_data!`

```elixir
@spec get_embed_data!(map(), map()) :: {any(), any(), any()}
```

Gets two embeds' data. An embed is always a [one-key map](https://quilljs.com/docs/delta/#embeds)

## Examples
    iex> Op.get_embed_data!(
    ...>   %{"image" => "https://quilljs.com/assets/images/icon.png"},
    ...>   %{"image" => "https://quilljs.com/assets/images/icon2.png"}
    ...> )
    {"image", "https://quilljs.com/assets/images/icon.png", "https://quilljs.com/assets/images/icon2.png"}

# `has_attributes?`

```elixir
@spec has_attributes?(any()) :: boolean()
```

Returns true if operation has attributes

## Examples
    iex> Op.has_attributes?(%{"insert" => "Hello", "attributes" => %{"bool" => true}})
    true

    iex> Op.has_attributes?(%{"insert" => "Hello"})
    false

# `insert`

```elixir
@spec insert(value :: insert_val(), attr :: attributes_val()) :: insert_op()
```

A shorthand for `new("insert", value, attributes)`. See `new/3`.

## Examples
    iex> Op.insert("Hello", %{"bold" => true})
    %{"insert" => "Hello", "attributes" => %{"bold" => true}}

# `insert?`

```elixir
@spec insert?(op :: t(), type :: any()) :: boolean()
```

A shorthand for `type?(op, "insert", type)`. See `type?/3`.

## Examples
    iex> Op.insert("Hello") |> Op.insert?()
    true

# `new`

```elixir
@spec new(action :: operation(), value :: operation_val(), attr :: attributes_val()) ::
  t()
```

Create a new operation.

Note that operations _are_ maps, and not structs.

## Examples
    iex> Op.new("insert", "Hello", %{"bold" => true})
    %{"insert" => "Hello", "attributes" => %{"bold" => true}}

# `retain`

```elixir
@spec retain(value :: retain_val(), attr :: attributes_val()) :: retain_op()
```

A shorthand for `new("retain", value, attributes)`. See `new/3`.

## Examples
    iex> Op.retain(1, %{"bold" => true})
    %{"retain" => 1, "attributes" => %{"bold" => true}}

# `retain?`

```elixir
@spec retain?(op :: t(), type :: any()) :: boolean()
```

A shorthand for `type?(op, "insert", type)`. See `type?/3`.

## Examples
    iex> Op.retain(1) |> Op.retain?()
    true

# `size`

```elixir
@spec size(t()) :: non_neg_integer()
```

Returns operation size.

## Examples
    iex> Op.insert("Hello") |> Op.size()
    5

    iex> Op.retain(3) |> Op.size()
    3

# `take`

```elixir
@spec take(op :: t(), length :: non_neg_integer(), opts :: Keyword.t()) ::
  {t(), t() | boolean()}
```

Takes `length` characters from an operation and returns it together with the
remaining part in a tuple.

## Options

  * `:align` - when `true`, allow moving index left if
    we're likely to split a grapheme otherwise.

## Examples
    iex> Op.insert("Hello") |> Op.take(3)
    {%{"insert" => "Hel"}, %{"insert" => "lo"}}

    iex> assert_raise RuntimeError, fn -> Op.insert("🏴󠁧󠁢󠁳󠁣󠁴󠁿") |> Op.take(1) end

    iex> Op.insert("🏴󠁧󠁢󠁳󠁣󠁴󠁿") |> Op.take(1, align: true)
    {%{"insert" => ""}, %{"insert" => "🏴󠁧󠁢󠁳󠁣󠁴󠁿"}}

# `text_size`

```elixir
@spec text_size(text :: binary()) :: non_neg_integer()
```

Returns text size.

## Examples
    iex> Op.text_size("Hello")
    5

    iex> Op.text_size("🏴󠁧󠁢󠁳󠁣󠁴󠁿")
    14

# `transform`

```elixir
@spec transform(a :: t(), b :: t(), priority :: boolean()) :: {t() | false, t(), t()}
```

# `transform`

```elixir
@spec transform(non_neg_integer(), non_neg_integer(), t(), boolean()) ::
  {non_neg_integer(), non_neg_integer()}
```

# `type?`

```elixir
@spec type?(op :: t(), action :: any(), value_type :: any()) :: boolean()
```

Returns true if operation is of type `type`. Optionally check against more specific `value_type`.

## Examples
    iex> Op.insert("Hello") |> Op.type?("insert")
    true

    iex> Op.insert("Hello") |> Op.type?("insert", :string)
    true

    iex> Op.insert("Hello") |> Op.type?("insert", :number)
    false

    iex> Op.retain(1) |> Op.type?("retain", :number)
    true

---

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