Skip to content
KaufmannCommerce UI
Foundations · v0.1⌘ K

Kaufmann Commerce UI / Promise family

Offer Detail

One Offer given room, and the resolver-shaped contract that lets editorial content reference commerce without ever copying it.

A bundle

The same OfferCardView the grid renders, given room. Its Item references are shown as references — the Offer is the promise, the Items are the operational units beneath it.

Live specimen

Archive bundle

The First Four Letters

€38.00€48.00

The complete first year of Forest Letters, gathered as one edition.

Returning soon

What this Offer resolves to

  • item-forest-letter-01Quantity 1
  • item-forest-letter-02Quantity 1
  • item-forest-letter-03Quantity 1
  • item-forest-letter-04Quantity 1

The Offer is the promise; the Items beneath it are the operational units. This page shows the reference only — it reads no stock and reserves nothing.

A single Item Offer

Most Offers resolve to one Item. The section still appears, because hiding it for the simple case would teach the wrong model.

Live specimen

A small ritual

Winter Window Set

€18.00

Transparent paper shapes for bringing low winter light indoors.

Ready to ship

What this Offer resolves to

  • item-window-paperQuantity 8
  • item-window-guideQuantity 1

The Offer is the promise; the Items beneath it are the operational units. This page shows the reference only — it reads no stock and reserves nothing.

Offer is not Item

The detail page renders OfferCardView — the same projection the grid uses, with nothing added. items stays a list of references: an id and a quantity. The page reads no stock, holds no reservation, and makes no claim that the Items exist in any warehouse.

A bundle is the clearest case: The First Four Letters is one customer-facing promise that resolves to four operational Items. Collapsing those into one row would be convenient and wrong.

Content that references commerce

Prose interleaved with Offer references. The payload stores ids; the price and availability you see were resolved a moment ago.

Live specimen

Content holds the reference, never the price. When this paragraph was written nobody knew what the Offer below would cost today — and it did not need to.

The resolver contract

The second commerce truth is that content references commerce and never copies it. A copied price is a lie with a delay on it: correct when written, wrong from the first change onward, and nothing in the content knows it. So an editorial block stores an Offer id and the writer's own framing — nothing volatile.

resolveContent(blocks, offers) is a pure read-only projection, the same shape as projectCartPricing. When a Kaufmann backend exists it becomes resolver-backed and the payloads do not change — which is the entire reason for storing references.

Unresolved references stay visibleA retired Offer keeps its place in the stream with an honest line. Dropping the block silently would leave the surrounding paragraphs pointing at something the reader cannot see — the third specimen above shows this deliberately.
Astro
// The payload a writer stores — no price, no availability, no title.
const entry: ContentBlock[] = [
  { type: "prose", text: "A letter begins on a walk…" },
  { type: "offer-reference", offerId: "forest-letter-autumn", note: "…" },
];

// Read-only projection. Unresolved ids are reported, never swallowed.
const { blocks, unresolved } = resolveContent(entry, offers);
Astro
---
import { OfferDetail, ContentStream } from "@kaufmann/ui";
---

<OfferDetail offer={offer} />

<!-- Editorial payload holds ids; resolution happens here, at render time. -->
<ContentStream blocks={entry} offers={offers} />