# `Flicker.Facet.Preset`
[🔗](https://github.com/team-alembic/flicker/blob/v0.1.0/lib/flicker/facet/preset.ex#L1)

A semantic date preset — `last-30-days`, `this-quarter`, `all-time`
([Spec 018](https://github.com/team-alembic/flicker/blob/main/docs/specs/spec-018-rich-facet-types.md)).

A preset is the *question* a user is asking ("the last 30 days"), not the
answer ("Jun 29 to Jul 28"). That distinction is load-bearing: presets
serialise back to their `:token`, so a query saved today still means "the
last 30 days" when reopened next week, rather than freezing to this week's
dates ([ADR-011](https://github.com/team-alembic/flicker/blob/main/docs/adrs/adr-011-facet-editors-are-modal-subcontexts.md)).

## Fields

  * `:id` — the canonical atom (`:last_30_days`), carried on
    `Flicker.Facet.Range`'s `:preset`.
  * `:token` — the typed/serialised form (`"last-30-days"`).
  * `:label` — the fallback display string. With `localize` present,
    `Flicker.Facet.Format` prefers CLDR's own wording
    ([ADR-013](https://github.com/team-alembic/flicker/blob/main/docs/adrs/adr-013-canonical-tokens-localised-display.md)).
  * `:resolve` — `fun(reference_date, first_day_of_week) :: {from, to}`, or
    `nil` for a built-in, which `resolve/3` computes from `:id` instead.

## Why built-ins carry no function

A `%Flicker.Facet{}` holding presets that each closed over an anonymous
function could not be a module attribute — `@facets [...]` fails, because
anonymous functions can't be escaped into one. Since a hand-built facet
registry as a module attribute is a perfectly reasonable thing to write, the
built-in table stores plain data and `resolve/3` dispatches on `:id`. A host
defining its own preset may still pass a `:resolve` function; that preset
just can't live in a module attribute.

## Resolution is contextual, and takes its context as arguments

`:resolve` never calls `Date.utc_today/0` and never reads a locale: both
the reference date and the week's first day arrive as arguments. That keeps
every preset a pure function — the whole table is testable at a fixed date
— and it is what lets `this-week` mean different days in `en-US` (Sunday
start) and `en-AU` (Monday start) without the preset knowing anything about
locales.

`first_day_of_week` is `1` for Monday through `7` for Sunday, matching
`Date.day_of_week/1`. Without `localize`, callers pass `1` (Monday), which
is the ISO 8601 default.

# `day_of_week`

```elixir
@type day_of_week() :: 1..7
```

A day-of-week number, `1` (Monday) through `7` (Sunday).

# `t`

```elixir
@type t() :: %Flicker.Facet.Preset{
  id: atom(),
  label: String.t(),
  resolve: (Date.t(), day_of_week() -&gt; {Date.t() | nil, Date.t() | nil}) | nil,
  token: String.t()
}
```

A semantic date preset.

# `builtin`

```elixir
@spec builtin() :: [t()]
```

The built-in preset table, in display order.

## Examples

    iex> Flicker.Facet.Preset.builtin() |> Enum.map(& &1.token) |> Enum.take(3)
    ["today", "yesterday", "last-7-days"]

# `find_by_id`

```elixir
@spec find_by_id(atom(), [t()]) :: t() | nil
```

Finds a preset by its canonical id.

## Examples

    iex> Flicker.Facet.Preset.find_by_id(:all_time).token
    "all-time"

    iex> Flicker.Facet.Preset.find_by_id(:nope)
    nil

# `find_by_token`

```elixir
@spec find_by_token(String.t(), [t()]) :: t() | nil
```

Finds a preset by its typed token, case-sensitively.

## Examples

    iex> Flicker.Facet.Preset.find_by_token("last-30-days").id
    :last_30_days

    iex> Flicker.Facet.Preset.find_by_token("Last-30-Days")
    nil

    iex> Flicker.Facet.Preset.find_by_token("nope")
    nil

# `resolve`

```elixir
@spec resolve(t(), Date.t(), day_of_week()) :: Flicker.Facet.Range.t()
```

Resolves `preset` against a reference date and the locale's first day of
week, returning a `Flicker.Facet.Range` tagged with the preset's id.

## Examples

    iex> preset = Flicker.Facet.Preset.find_by_id(:last_7_days)
    ...> Flicker.Facet.Preset.resolve(preset, ~D[2026-07-28], 1)
    %Flicker.Facet.Range{from: ~D[2026-07-22], to: ~D[2026-07-28], preset: :last_7_days}

    iex> preset = Flicker.Facet.Preset.find_by_id(:this_week)
    ...> Flicker.Facet.Preset.resolve(preset, ~D[2026-07-29], 1).from
    ~D[2026-07-27]

    iex> preset = Flicker.Facet.Preset.find_by_id(:this_week)
    ...> Flicker.Facet.Preset.resolve(preset, ~D[2026-07-29], 7).from
    ~D[2026-07-26]

    iex> preset = Flicker.Facet.Preset.find_by_id(:all_time)
    ...> Flicker.Facet.Preset.resolve(preset, ~D[2026-07-28], 1)
    %Flicker.Facet.Range{from: nil, to: nil, preset: :all_time}

---

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