Skip to main content

lib/fresco_strip.ex

defmodule FrescoStrip do
  @moduledoc """
  Vertical-image-strip scroll companion to [Fresco](https://hex.pm/packages/fresco).

  Use `FrescoStrip.viewer/1` for content read by **scrolling continuously**
  through a stack of full-width images — manhwa, long-form web comics,
  IG-style feeds, documentation snapshots. For deep-zoom imagery or
  paged layouts, reach for `Fresco.viewer` / `Fresco.canvas` from the
  `fresco` package instead.

  ## Annotations out of the box

  [Etcher](https://hex.pm/packages/etcher) (>= 0.4.12) draws shapes
  on each page of a strip with the same UX surface as canvas mode —
  per-page SVG overlays, hit-testing scoped to the right page,
  hover tooltips, undo / redo, color picker, multi-select. Drop in
  `<Etcher.layer fresco_id="reader" />` alongside the strip and the
  annotation toolbar appears. Etcher detects the strip handle at
  runtime via `"scrollTo" in handle` — no per-package configuration.
  Shapes get an extra `image_idx` field identifying which page they
  live on; the `etcher:annotations-changed` payload round-trips
  through the strip's `:extensions` map (see "Attaching annotation
  tools" in `FrescoStrip.viewer`).

  ## Why a separate package?

  Strip mode used to ship inside `fresco` as `Fresco.scroll_strip`. It
  was extracted to keep `fresco` lightweight for the common
  viewer / canvas consumer (lightboxes, paged readers, document
  viewers, lookbooks) who never needed the strip's memory-windowing /
  per-image-overlay machinery. Two packages, two release cadences,
  two distinct API surfaces — share only the `window.Fresco`
  handle-registry contract so peer libraries (Etcher annotations,
  ML overlays, comment threads) can find any handle regardless of
  which package mounted it.

  ## Compatibility

  - Drop-in replacement for `Fresco.scroll_strip` from `fresco <= 0.5.9`
    (rename: `<Fresco.scroll_strip>` → `<FrescoStrip.viewer>`; component
    attributes + event surface + handle methods are unchanged).
  - Etcher 0.4.12+ supports `FrescoStrip.viewer` automatically — it
    detects the handle shape at runtime and routes through its
    existing strip-renderer.
  - Co-installable with `fresco` of any 0.5.x / 0.6.x version. Both
    packages contribute to the same `window.Fresco.viewerRegistry`
    global; whichever loads first creates the registry, the second
    piggy-backs.

  ## Quick start

      # mix.exs
      defp deps do
        [
          {:fresco, "~> 0.6.0"},
          {:fresco_strip, "~> 0.1.0"}
        ]
      end

      # assets/js/app.js
      import "../../deps/fresco/priv/static/fresco.js"
      import "../../deps/fresco_strip/priv/static/fresco_strip.js"

      # template
      <FrescoStrip.viewer
        id="reader"
        sources={[
          %{url: "/img/page-01.jpg", width: 720, height: 9200},
          %{url: "/img/page-02.jpg", width: 720, height: 8800}
        ]}
        class="w-full h-lvh"
      />

  See `FrescoStrip.viewer/1` for the full attribute list, handle API,
  and the extension contract for peer libraries.
  """

  # Convenience delegate so consumers can write `<FrescoStrip.viewer ...>`
  # without aliasing `FrescoStrip.Viewer` themselves. Mirrors the
  # `defdelegate viewer(assigns), to: Fresco.Viewer` pattern from the
  # `fresco` package.
  defdelegate viewer(assigns), to: FrescoStrip.Viewer
end