All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

While the version is in the 0.x range, any release MAY contain breaking changes; the minor version is bumped for each one. See CONTRIBUTING.md for the full policy.

Unreleased

[0.1.0-beta.5] - 2026-06-14

Added

  • Drag-and-drop insertion-line indicator inside AthanorDropZone. On dragover the zone gets a dashed primary outline + tinted background, and a horizontal primary line (with dot endcaps) is positioned at the cursor's computed insertion point between sibling drop-items. Empty zones show only the outline/tint. Hook self-injects the required styles into document.head so consumers need no additional CSS.

0.1.0-beta.3 - 2026-06-05

Added

  • Built-in :asset field type — a host-agnostic picker for uploaded assets (image / pdf / video / anything). Ships a paste-a-URL default and emits a fixed "athanor_asset_request" event the host fulfils; Athanor never performs or names an upload. Field opts: accept: (opaque hint, forwarded), multiple: (gallery / multi-file), min: / max: (forwarded, host-enforced). Value is an asset descriptor map %{"url" => ..., "name" => ..., "content_type" => ...} (single) or a list of them (multiple: true); opaque extra keys are preserved. Single-value paste-URL participates in the existing update_props form; gallery items get add / remove chrome and an athanor_asset_remove handler.
  • Athanor.Editor.AssetRequest struct describing a pending request (node_id, key, accept, multiple, min, max, current).
  • Athanor.Editor.handle_asset_request/2 — optional host callback, invoked when an :asset field is activated. Default is a no-op (the field degrades to paste-a-URL).
  • Athanor.Editor.render_outlet/1 — optional, general consumer render outlet fed into the shell's :modals layer. Host mounts arbitrary fixed/offscreen chrome (asset picker, drawer, toast) here. Overridable alongside render_header/1 and render_top_bar_actions/1.
  • Editor pending-request lifecycle: Athanor.Editor.State.asset_request tracks the open picker; cleared on the matching write-back (only when the pending key's value changes), on "athanor_asset_cancel" (event or :athanor_asset_cancel message), and on select / close-config / remove navigation.

0.1.0-beta.2 - 2026-06-03

Added

  • Drag-and-drop in the page-builder editor. Drag from the components palette onto the canvas, reorder canvas items, drag children in and out of Columns zones. Server side: new Athanor.Tree.move_to/4 helper and athanor:dnd_drop event handled by Athanor.Editor.Live. Client side: AthanorHooks exported from assets/js/athanor.js with two hooks (AthanorDragSource, AthanorDropZone) — wire into your LiveSocket hooks:. Native HTML5 DnD, no JS deps.
  • package.json + assets/js/ shipped in the Hex tarball so consumers can import "athanor" directly through esbuild module resolution.

0.1.0-beta.1 - 2026-06-02

First public beta. API may shift before 0.1.0 based on early feedback. Pin tightly ({:athanor, "== 0.1.0-beta.1"}) if integrating during the beta window.

Added

  • Athanor.Tree — pure-data manipulation of the editor content tree (insert, remove, move, find, with String.t()-keyed node ids and child-zone slots).
  • Athanor.Component — behaviour + use Athanor.Component macro for declaring page-builder components. Optional callbacks: metadata/0, default_props/0, required_props/0, validate/1, fields/0, resolve_fields/2, resolve_data/2, render/3, editor_form/0, child_zones/1. Inspired by Puck.js's dynamic fields + data hooks.
  • Athanor.Registry — runtime lookup of component modules by type string, sourced from config :athanor, :components.
  • Athanor.Ctx — render/edit context struct carrying account_id, brand_id, edit_mode?, callbacks, and a freeform :extra map.
  • Athanor.Renderer — dispatches each node in the tree to its component's render/3 and wraps the result in edit chrome when ctx.edit_mode?.
  • Athanor.Fields — auto-renders a component's field schema (text, textarea, number, select, color, checkbox, custom) into HTML form inputs. Custom fields delegate to consumer-provided LiveComponents.
  • Athanor.Field — behaviour-style contract for custom field LiveComponents (value/on_change/ctx/label/opts assigns).
  • Athanor.AutoEditorForm — LiveComponent wrapping Athanor.Fields with the form/state plumbing (phx-change, custom field callbacks).
  • Athanor.Editor — function components (canvas, components_panel, config_panel, zone_picker_modal, shell) for composing custom editor layouts, plus a @behaviour for the consumer LiveView.
  • Athanor.Editor.Live — turn-key use macro injecting mount/3, render/1, handle_event/3, handle_info/2. Consumer implements load/3 and save/2; optional overrides for render_header/1 and render_top_bar_actions/1.
  • Athanor.Editor.State — typed struct for editor state (content, metadata, ctx, selected_component_id, preview_viewport, show_components_panel, column_picker, open_sections).
  • Built-in primitive components: Athanor.Components.Button, Athanor.Components.Columns, Athanor.Components.Divider, Athanor.Components.Heading, Athanor.Components.Text.
  • Athanor.Components.Formatting + Athanor.Components.Formatting.EditorForm — shared formatting tab (alignment / colors / padding / margin / borders) reused across every component's config panel. Color swatches ship with a Clear button (pure client-side, no JS hooks).
  • Page settings as a regular Athanor.Component: consumers pass any Athanor.Component module as the :page_settings_component opt and the library auto-renders its fields/0 at the top of the sidebar.