defmodule BlockBox.CompositionObjects do
@moduledoc """
Defines types and generator functions for all [composition objects](https://api.slack.com/reference/block-kit/composition-objects).
"""
alias BlockBox.Utils, as: Utils
@type text_type() :: :plain_text | :mrkdwn
@type text_object() :: %{
required(:text) => String.t(),
required(:type) => text_type(),
optional(:emoji) => boolean(),
optional(:verbatim) => boolean()
}
@type plain_text_object() :: %{
required(:text) => String.t(),
required(:type) => :plain_text,
optional(:emoji) => boolean()
}
@type confirm_object() :: %{
required(:title) => plain_text_object(),
required(:text) => text_object(),
required(:confirm) => plain_text_object(),
required(:deny) => plain_text_object()
}
@type option_object() :: %{
required(:text) => text_object(),
required(:value) => String.t(),
optional(:description) => plain_text_object(),
optional(:url) => String.t()
}
@type option_group_object() :: %{
required(:label) => plain_text_object(),
required(:options) => list(option_object())
}
@type filter_object() :: %{
optional(:include) => list(String.t()),
optional(:exclude_external_shared_channels) => boolean(),
optional(:exclude_bot_users) => boolean()
}
@doc """
Function that generates a [text object](https://api.slack.com/reference/block-kit/composition-objects#text)
## Options
Options are not included by default.
* `:emoji` - boolean, only usable when type is `:plain_text`
* `:verbatim` - boolean, only usable when type is `:mrkdwn`
"""
@spec text_object(String.t(), text_type(), keyword()) :: text_object()
def text_object(text, type \\ :plain_text, opts \\ []) do
%{
type: type,
text: text
}
|> Map.merge(Enum.into(opts, %{}))
end
@doc """
Function that generates a [confirmation dialog object](https://api.slack.com/reference/block-kit/composition-objects#confirm)
"""
@spec confirm_object(String.t(), String.t(), String.t(), String.t()) :: confirm_object()
def confirm_object(title, text, confirm \\ "Confirm", deny \\ "Deny") do
%{
title: text_object(title),
text: text_object(text),
confirm: text_object(confirm),
deny: text_object(deny)
}
end
@doc """
Function that generates an [option object](https://api.slack.com/reference/block-kit/composition-objects#option) for select menus
## Options
Options are not included by default.
* `:url` - boolean, only available in overflow menus
* `:description` - String, max 75 chars
"""
def option_object(text, value, opts \\ [])
@spec option_object(String.t() | plain_text_object(), String.t(), keyword()) :: option_object()
def option_object(text_str, value, opts) when is_binary(text_str) do
text_object(text_str)
|> option_object(value, opts)
end
def option_object(text_object, value, opts) do
opts = Utils.convert_text_opts(opts, [:description])
%{
text: text_object,
value: value
}
|> Map.merge(Enum.into(opts, %{}))
end
@doc """
Function that generates an [option group object](https://api.slack.com/reference/block-kit/composition-objects#option_group) for select menus
"""
@spec option_group_object(String.t() | plain_text_object(), String.t()) :: option_group_object()
def option_group_object(label, options) when is_binary(label) do
text_object(label)
|> option_group_object(options)
end
def option_group_object(label, options) do
%{
label: label,
options: options
}
end
@doc """
Function that generates a [filter object](https://api.slack.com/reference/block-kit/composition-objects#filter_conversations) for conversation lists.
All fields are optional but AT LEAST ONE MUST BE INCLUDED.
## Options
Options are not included by default.
* `:include` - non empty list of strings from the following options: "im", "mpim", "private", "public"
* `:exclude_external_shared_channels` - boolean, defaults to false
* `:exclude_bot_users` - boolean, defaults to false
"""
def filter_object(opts) do
Enum.into(opts, %{})
end
end