Packages
corex
0.1.0-alpha.24
0.1.2
0.1.1
0.1.0
0.1.0-rc.1
0.1.0-rc.0
0.1.0-beta.5
0.1.0-beta.4
0.1.0-beta.3
0.1.0-beta.2
0.1.0-beta.1
0.1.0-alpha.33
0.1.0-alpha.32
0.1.0-alpha.31
0.1.0-alpha.30
0.1.0-alpha.29
0.1.0-alpha.28
0.1.0-alpha.27
0.1.0-alpha.26
0.1.0-alpha.25
0.1.0-alpha.24
0.1.0-alpha.23
0.1.0-alpha.22
0.1.0-alpha.21
0.1.0-alpha.20
0.1.0-alpha.19
0.1.0-alpha.18
0.1.0-alpha.17
0.1.0-alpha.16
0.1.0-alpha.15
0.1.0-alpha.14
0.1.0-alpha.13
0.1.0-alpha.12
0.1.0-alpha.11
0.1.0-alpha.10
0.1.0-alpha.9
0.1.0-alpha.8
0.1.0-alpha.7
0.1.0-alpha.6
0.1.0-alpha.5
0.1.0-alpha.4
0.1.0-alpha.3
0.1.0-alpha.2
0.1.0-alpha.1
Accessible and unstyled UI components library written in Elixir and TypeScript that integrates Zag.js state machines into the Phoenix Framework.
Current section
Files
Jump to
Current section
Files
lib/tree.ex
defmodule Corex.Tree do
@moduledoc """
Tree item structure for hierarchical/nested items.
"""
defmodule Item do
@moduledoc """
Tree item structure.
Use it to create hierarchical/nested structures for:
- [Menu](Corex.Menu.html)
## Fields
* `:id` - (optional) Unique identifier, auto-generated if not provided
* `:label` - (required) Display text
* `:children` - (optional) Nested items
* `:disabled` - (optional) Whether the item is disabled
* `:group` - (optional) Group identifier for grouping items
* `:meta` - (optional) Additional metadata for the item
* `:redirect` - (optional) When top-level redirect is true, set to false on an item to disable redirect for that item
* `:new_tab` - (optional) When redirect is used, set to true to open this item's URL in a new tab
"""
@derive Jason.Encoder
@enforce_keys [:label]
defstruct [
:id,
:label,
children: [],
disabled: false,
group: nil,
meta: %{},
redirect: nil,
new_tab: false
]
@type t :: %__MODULE__{
id: String.t(),
label: String.t(),
children: list(t()),
disabled: boolean(),
group: String.t() | nil,
meta: map(),
redirect: boolean() | nil,
new_tab: boolean()
}
@doc """
Creates a single Tree.Item with an auto-generated ID if not provided.
Recursively processes children if present.
Raises `ArgumentError` if attrs is not a keyword list or map.
"""
def new(attrs) when is_list(attrs) or is_map(attrs) do
attrs =
attrs
|> Enum.into([])
|> Keyword.put_new(:id, Corex.Tree.generate_id())
# Process children recursively
attrs =
if attrs[:children] do
children =
Enum.map(attrs[:children], fn
%__MODULE__{} = child ->
child
child_attrs when is_list(child_attrs) or is_map(child_attrs) ->
new(child_attrs)
invalid ->
raise ArgumentError, """
Invalid child item: #{inspect(invalid)}
Children must be keyword lists, maps, or Tree.Item structs.
"""
end)
Keyword.put(attrs, :children, children)
else
attrs
end
struct!(__MODULE__, attrs)
rescue
e in [KeyError, ArgumentError] ->
reraise ArgumentError,
"""
Failed to create Tree.Item: #{Exception.message(e)}
Required fields: [:label]
Optional fields: [:id, :children, :disabled, :group, :meta, :redirect, :new_tab]
Example:
Corex.Tree.Item.new(label: "File", children: [
[label: "New"],
[label: "Open"]
])
""",
__STACKTRACE__
end
def new(attrs) do
raise ArgumentError, """
Expected a keyword list or map, got: #{inspect(attrs)}
Example:
Corex.Tree.Item.new(label: "My Label")
Corex.Tree.Item.new(%{label: "My Label", children: []})
"""
end
end
@doc """
Creates a list of Tree.Item structs from a list of attribute maps.
Recursively processes children if present.
Raises `ArgumentError` if items is not a list or contains invalid items.
"""
def new([]), do: []
def new([first | _rest] = items) when is_list(first) or is_map(first) do
Enum.map(items, &Item.new/1)
end
def new(items) when is_list(items) do
raise ArgumentError, """
Expected a list of keyword lists or maps, got invalid item format.
Example:
Corex.Tree.new([
[label: "File", children: [[label: "New"]]],
[label: "Edit"]
])
"""
end
def new(items) do
raise ArgumentError, """
Expected a list, got: #{inspect(items)}
Example:
Corex.Tree.new([
[label: "File"],
[label: "Edit"]
])
"""
end
@doc false
def generate_id do
"tree-#{System.unique_integer([:positive, :monotonic])}"
end
end