defmodule Orange.Component.Modal do @moduledoc """ An modal/dialog component which renders an overlay in the middle of the viewport. ## Attributes - `:open` - Whether the modal is open or not. This attribute is required. - `:offset_x` - The offset from the left and right edge of the screen. This attribute is required. - `:offset_y` - The offset from the top and bottom edge of the screen. This attribute is required. > #### Info {: .info} > > When the offset_x/y is too big for the terminal size, the modal will not be rendered. - `:children` - The content of the modal. This attribute is optional. ## Examples defmodule Example do @behaviour Orange.Component import Orange.Macro @impl true def init(_attrs), do: %{state: %{search_value: ""}} @impl true def render(state, _attrs, update) do modal_content = rect do "foo" "bar" end rect do line do "Displaying modal..." end { Orange.Component.Modal, offset_x: 8, offset_y: 4, children: modal_content, open: true } end end end ![rendered result](assets/modal-example.png) """ @behaviour Orange.Component import Orange.Macro @impl true def init(_attrs), do: %{state: nil} @impl true def render(_state, attrs, _update) do {width, height} = terminal_impl().terminal_size() offset_x = attrs[:offset_x] offset_y = attrs[:offset_y] # Plus 2 for the border if attrs[:open] && width > offset_x * 2 + 2 && height > offset_y * 2 + 2 do rect position: {:fixed, offset_y, offset_x, offset_y, offset_x}, style: [border: true] do attrs[:children] end end end defp terminal_impl(), do: Application.get_env(:orange, :terminal, Orange.Terminal) end