# `MingaEditor.FeatureState`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_editor/feature_state.ex#L1)

Source-owned per-workspace UI feature state.

Feature state is for presentation features that need tab-scoped state without adding permanent fields to `MingaEditor.Session.State`. Values are opaque to the registry. The owning feature decides the value shape and updates it through the helpers here and on `MingaEditor.Session.State`.

# `entries`

```elixir
@type entries() :: %{optional(source()) =&gt; %{optional(feature_id()) =&gt; value()}}
```

Feature state registry keyed first by source and then by feature id.

# `feature_id`

```elixir
@type feature_id() :: atom()
```

Feature identifier owned by a source.

# `source`

```elixir
@type source() :: Minga.Extension.ContributionCleanup.contribution_source()
```

Source that owns feature state.

# `t`

```elixir
@type t() :: %MingaEditor.FeatureState{entries: entries()}
```

# `value`

```elixir
@type value() :: term()
```

Opaque feature-owned value.

# `drop`

```elixir
@spec drop(t(), source(), feature_id()) :: t()
```

Drops one source-owned feature value.

# `drop_extension_sources`

```elixir
@spec drop_extension_sources(t()) :: t()
```

Drops every extension-owned feature value while preserving built-in and config state.

# `drop_source`

```elixir
@spec drop_source(t(), source()) :: t()
```

Drops every feature value owned by `source`.

# `empty?`

```elixir
@spec empty?(t()) :: boolean()
```

Returns true when no feature state is stored.

# `ensure_cleanup_registered`

```elixir
@spec ensure_cleanup_registered() :: :ok
```

Registers the source-cleanup callback used by extension unload/reload.

# `fetch`

```elixir
@spec fetch(t(), source(), feature_id()) :: {:ok, value()} | :error
```

Fetches a source-owned feature value.

# `get`

```elixir
@spec get(t(), source(), feature_id()) :: value() | nil
```

Returns the value for a source-owned feature, or nil when missing.

# `get`

```elixir
@spec get(t(), source(), feature_id(), default) :: value() | default when default: var
```

Returns the value for a source-owned feature, or a caller-provided default when missing.

# `member?`

```elixir
@spec member?(t(), source(), feature_id()) :: boolean()
```

Returns true when the source owns the feature id.

# `new`

```elixir
@spec new() :: t()
```

Creates an empty feature-state registry.

# `put`

```elixir
@spec put(t(), source(), feature_id(), value()) :: t()
```

Stores a source-owned feature value.

# `unregister_source`

```elixir
@spec unregister_source(source()) :: :ok | {:error, term()}
```

Cleanup callback bridge used by `Minga.Extension.ContributionCleanup`.

# `unregister_source`

```elixir
@spec unregister_source(source(), GenServer.server() | nil) :: :ok | {:error, term()}
```

Cleanup callback bridge against an explicit editor server. Useful for tests.

# `update`

```elixir
@spec update(t(), source(), feature_id(), value(), (value() -&gt; value())) :: t()
```

Updates a source-owned feature value. Missing values are initialized with `default`.

# `valid_feature_id?`

```elixir
@spec valid_feature_id?(term()) :: boolean()
```

Returns true for supported feature ids.

# `valid_source?`

```elixir
@spec valid_source?(term()) :: boolean()
```

Returns true for supported contribution source identifiers.

---

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