> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aftersell.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Блок товаров корзины

> Блок Cart items: список позиций, строка Product и контейнер для вложенных блоков.

> Блок **Cart items** — это список позиций в корзине, отображающий каждый добавленный покупателем товар с его изображением, названием, вариантом, ценой, степпером количества и кнопкой удаления. Это обязательный блок, и это контейнер, содержащий вложенные блоки корзины (строку **Product**, [**Subscription upgrade**](/ru/aftersell/cart/subscription-upgrade-block) и [**Custom code**](/ru/aftersell/cart/custom-code-blocks)), предоставляя структуру, к которой прикрепляются построчные вложенные блоки.

<Frame>
  <img src="https://mintcdn.com/aftersell/1Y3gBpUfxv16VGSW/images/aftersell/cart-items-block-line-product-title-variant.png?fit=max&auto=format&n=1Y3gBpUfxv16VGSW&q=85&s=3c9f088b55cfd8450dcb8670dfe0728a" alt="Блок Cart items, показывающий позиции с изображением товара, названием, вариантом, ценой, степпером количества и кнопкой удаления" width="1420" height="486" data-path="images/aftersell/cart-items-block-line-product-title-variant.png" />
</Frame>

<div id="the-product-row">
  ## Строка Product
</div>

Внутри Cart items находится вложенный блок **Product**: собственно строка позиции. Он заблокирован и добавляется автоматически, поэтому каждый блок Cart items всегда содержит ровно одну строку Product, которую нельзя удалить; другие вложенные блоки вы располагаете вокруг неё. Её настройки управляют отображением цены каждой строки:

| Настройка                                  | Что она контролирует                                                                                                                                                                                                                                                                                                                    | По умолчанию                                    |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- |
| **Strike-through price**                   | Какая цена показывается зачёркнутой: **Compare-at or pre-discount, whichever is higher**, **Compare-at price**, **Pre-discount price** или **No strike-through**.                                                                                                                                                                       | Compare-at or pre-discount, whichever is higher |
| **Strike-through price for subscriptions** | Тот же выбор для строк подписки, с двумя отличиями: дополнительная опция **Subscription compare-at price**, а **Compare-at price** переименована в **Product compare-at, then subscription compare-at**.                                                                                                                                | Compare-at or pre-discount, whichever is higher |
| **Savings label**                          | Показывать ли экономию как **Amount** (сумму), **Percentage** (процент) или **Hidden** (скрыть).                                                                                                                                                                                                                                        | Amount                                          |
| **Bundle price**                           | Как рассчитывается отображаемая цена для строк бандла. **Automatic** показывает итог всех товаров в бандле (или цену основного товара, когда остальные бесплатны). **Main item price only** показывает только цену основного (якорного) товара. Это лишь отображаемая надпись — итог корзины Shopify всегда является источником истины. | Automatic                                       |
| **Savings text**                           | Надпись экономии. Поддерживает токен `{{value}}`.                                                                                                                                                                                                                                                                                       | `Save {{value}}`                                |

Сама строка отображает изображение товара (со ссылкой на страницу товара, когда доступна), название, вариант, цену и зачёркнутую цену compare-at при наличии, степпер количества и кнопку удаления. Строки бандлов показывают раскрывающийся список своих компонентов.

<div id="text-styling">
  ### Оформление текста
</div>

Строка Product включает раздел **Text** в своих настройках Design. Используйте его для управления типографикой отдельных текстовых элементов каждой позиции. Выберите текстовый элемент из селектора, чтобы настроить его параметры:

| Настройка          | Что она контролирует                                                                                                                                               |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **Text color**     | Цвет выбранного текстового элемента.                                                                                                                               |
| **Font**           | **Theme font** (наследует шрифт вашей темы) или **Custom font** (введите название шрифта, который уже загружает ваша тема). Доступно только для **Product title**. |
| **Size**           | Размер шрифта в пикселях.                                                                                                                                          |
| **Weight**         | Насыщенность шрифта: Light, Regular, Medium, Semibold или Bold.                                                                                                    |
| **Line height**    | Межстрочный интервал как множитель размера шрифта (например, `1.4`).                                                                                               |
| **Letter spacing** | Межбуквенный интервал в пикселях. Отрицательные значения сжимают текст.                                                                                            |

Текстовые элементы, которые можно оформить, сгруппированы по категориям:

**Product**

* **Product title** — название товара в каждой строке. Также поддерживает собственный шрифт.
* **Variant** — надпись варианта (например, *Size: Medium*).
* **Subscription plan** — надпись плана только для чтения, отображаемая в строках подписки.

**Pricing**

* **Price** — текущая цена строки.
* **Compare-at price** — зачёркнутая исходная цена.
* **Savings** — надпись экономии (например, *Save \$5.00*). Только размер и межстрочный интервал — жирность и цвет задаются в редакторе Rich Text выше.

**Bundle**

* **Bundle toggle** — раскрывающийся заголовок, разворачивающий список компонентов бандла.
* **Bundle item title** — название каждого компонента внутри бандла.
* **Bundle item variant** — надпись варианта для каждого компонента бандла.

Если оставить поле пустым, элемент сохраняет значение по умолчанию.

<Tip>
  Клик по текстовому элементу прямо в предпросмотре корзины подсвечивает его и автоматически открывает его настройки в панели.
</Tip>

<div id="discount-tags-design">
  ### Дизайн тегов скидок
</div>

Строка Product включает раздел **Discount tags** в своих настройках Design. Используйте его для оформления плашек тегов скидок, появляющихся на каждой позиции:

| Настройка            | Что она контролирует                   | По умолчанию |
| -------------------- | -------------------------------------- | ------------ |
| **Background color** | Цвет заливки плашки тега скидки.       | `#F1F1F1`    |
| **Text color**       | Цвет текста внутри плашки тега скидки. | `#585858`    |
| **Border radius**    | Скругление углов плашки тега скидки.   | `6px`        |

Эти настройки применяются только к тегам скидок позиций в блоке Cart items. Теги кодов скидок в [блоке Summary](/ru/aftersell/cart/summary-block) оформляются отдельно.

<div id="sub-blocks-and-how-they-position">
  ## Вложенные блоки и их позиционирование
</div>

Cart items — единственный блок, содержащий вложенные блоки. **Вложенные блоки отображаются один раз на строку, внутри каждой строки товара**, позиционируясь относительно закреплённой строки Product:

* Вложенные блоки, расположенные **перед** строкой Product, появляются **над** содержимым товара в каждой строке.
* Вложенные блоки, расположенные **после** строки Product, появляются **под** содержимым товара в каждой строке.

Поэтому блок [Subscription upgrade](/ru/aftersell/cart/subscription-upgrade-block), помещённый после строки Product, отображается под каждой подходящей строкой, а не один раз внизу всего списка.

<div id="behavior">
  ## Поведение
</div>

* Когда в корзине нет товаров, выдвижная корзина переключается в пустое состояние, и этот блок не показывается.
* **Одновременно выполняется одно изменение корзины.** Пока выполняется обновление количества или удаление, элементы управления строки отключены для сохранения консистентности корзины, а затем снова включаются после завершения изменения.
* Снижение количества строки ниже 1 удаляет её. Количество, отклонённое магазином (например, сверх доступных запасов), синхронизируется обратно с последним допустимым значением.
* **Бандлы изменяются как единое целое.** Изменение количества у якорной строки бандла масштабирует весь бандл за одну операцию — если дочерний товар включён по 3 на якорь, увеличение якоря с 1 до 2 доводит этот дочерний товар до 6. Удаление якоря удаляет все элементы бандла сразу.
* **Количество у некоторых бандлов изменить нельзя.** Если какой-либо дочерний товар бандла включён с дробным коэффициентом (скажем, 1,5 на якорь), степпер количества этого бандла заблокирован: кнопки +/− и поле количества отключены, а введённые значения не принимаются. Бандл всё ещё можно удалить.
* **Строки подписки показывают свой план.** Когда у строки есть план продаж, а вложенный блок [Subscription upgrade](/ru/aftersell/cart/subscription-upgrade-block) выключен или не добавлен, строка Product показывает надпись плана только для чтения под вариантом — например, *Delivers every month (save 30%)*. Когда этот вложенный блок включён, он представляет план в собственном выборе, поэтому надпись только для чтения скрывается, а не дублируется.

<div id="placement-and-limits">
  ## Размещение и ограничения
</div>

* **Область:** тело.
* **Максимум:** 1 на состояние корзины.
* **Состояние:** только заполненная корзина.
* **Заблокирован и добавлен по умолчанию.** Cart items нельзя удалить или скрыть, только переместить.

<div id="custom-template">
  ## Пользовательский шаблон
</div>

Поддерживает [пользовательский шаблон](/ru/aftersell/cart/custom-templates) на вкладке Code, который заменяет встроенную разметку этого блока вашим JSX. Вот пропсы, которые он получает.

У контейнера **Cart items** пользовательского шаблона нет. У строки **Product** внутри него — есть, и это самая насыщенная поверхность в корзине: ваш шаблон отображается один раз на строку.

<div id="line-content">
  ### Содержимое строки
</div>

| Проп               | Тип                         | Для чего он нужен                                                                                                                                                                                                                   |
| ------------------ | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title`            | `string`                    | Название товара, обычный текст.                                                                                                                                                                                                     |
| `variantTitle`     | `string \| null`            | Надпись варианта. `null` для товаров с одним вариантом и нативных бандлов.                                                                                                                                                          |
| `url`              | `string \| null`            | URL страницы товара. `null`, когда строка не должна вести наружу.                                                                                                                                                                   |
| `imageUrl`         | `string \| null`            | Изображение строки. `null`, когда у товара его нет.                                                                                                                                                                                 |
| `quantity`         | `number`                    | Текущее количество в строке.                                                                                                                                                                                                        |
| `price`            | `string`                    | Цена строки, **уже отформатированная**.                                                                                                                                                                                             |
| `compareAtPrice`   | `string \| null`            | Зачёркнутая «старая» цена, уже отформатированная. `null`, когда зачёркивать нечего.                                                                                                                                                 |
| `savingsHtml`      | `string \| null`            | Надпись экономии в виде очищенного HTML. `null`, когда скрыта или экономии нет.                                                                                                                                                     |
| `discountTags`     | `string[]`                  | Названия скидок этой строки, например `['Spring Sale']`. `[]`, когда их нет.                                                                                                                                                        |
| `sellingPlanLabel` | `string \| null`            | Название плана подписки только для чтения. `null`, когда это разовая строка или когда вложенный блок [Subscription upgrade](/ru/aftersell/cart/subscription-upgrade-block#custom-template) отображает интерфейс плана вместо этого. |
| `bundle`           | `object \| null`            | Вью-модель [бандла](/ru/aftersell/cart/sdk-cart-object#bundles) у якорной строки. Иначе `null`.                                                                                                                                     |
| `productId`        | `number`                    | ID товара Shopify.                                                                                                                                                                                                                  |
| `variantId`        | `number`                    | ID варианта Shopify.                                                                                                                                                                                                                |
| `line`             | `AftersellCartLine`         | Полная [строка корзины](/ru/aftersell/cart/sdk-cart-object#cart-lines) для всего, что не покрывают пропсы выше.                                                                                                                     |
| `formatMoney`      | `(cents: number) => string` | Форматирует сумму в младших единицах. Используйте для цен, прочитанных из `line`.                                                                                                                                                   |

<Warning>
  **`price` и `compareAtPrice` — отформатированные строки; всё в `line` — в центах.** Не выполняйте арифметику над `price`. Вычисляйте из `line.finalLinePrice` и подобных полей, затем пропускайте результат через `formatMoney`.
</Warning>

<div id="quantity-and-removal">
  ### Количество и удаление
</div>

| Проп                | Тип                                              | Для чего он нужен                                                                                                                                                                                                                               |
| ------------------- | ------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `increment`         | `() => void`                                     | Добавляет единицу к строке.                                                                                                                                                                                                                     |
| `decrement`         | `() => void`                                     | Убирает единицу из строки.                                                                                                                                                                                                                      |
| `remove`            | `() => void`                                     | Полностью удаляет строку.                                                                                                                                                                                                                       |
| `quantityInput`     | `string`                                         | Текущее значение для управляемого `<input>` количества. Строка, чтобы промежуточные состояния ввода сохранялись.                                                                                                                                |
| `onQuantityInput`   | `(event: Event) => void`                         | Обработчик `onInput` для этого поля.                                                                                                                                                                                                            |
| `commitQuantity`    | `() => void`                                     | Применяет введённое количество. Подключайте к `onBlur`.                                                                                                                                                                                         |
| `onQuantityKeyDown` | `(event: KeyboardEvent) => void`                 | Обработчик `onKeyDown`, чтобы Enter применял значение.                                                                                                                                                                                          |
| `busy`              | `boolean`                                        | `true`, пока выполняется любая мутация корзины. Отключайте свои элементы управления по этому значению.                                                                                                                                          |
| `pending`           | `'increment' \| 'decrement' \| 'remove' \| null` | Какое действие сейчас выполняется — для точечного спиннера.                                                                                                                                                                                     |
| `stepperLocked`     | `boolean`                                        | `true`, когда количество нельзя изменить, потому что строка — якорь бандла с дочерним товаром, включённым с дробным коэффициентом на якорь. Скройте или отключите степпер — встроенные обработчики уже отклоняют изменения, пока он установлен. |

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomTemplate(props) {
  return (
    <div className="cart-external-cart-items__row" style={{ display: 'flex', gap: '12px', opacity: props.busy ? 0.6 : 1 }}>
      {props.imageUrl && <img src={props.imageUrl} alt="" width={64} height={64} />}

      <div style={{ flex: 1 }}>
        {props.url ? <a href={props.url}>{props.title}</a> : <span>{props.title}</span>}
        {props.variantTitle && <div style={{ opacity: 0.6 }}>{props.variantTitle}</div>}
        {props.sellingPlanLabel && <div style={{ opacity: 0.6 }}>{props.sellingPlanLabel}</div>}

        {props.discountTags.map((tag) => (
          <span key={tag} style={{ fontSize: '11px', border: '1px solid', borderRadius: '4px', padding: '1px 5px' }}>
            {tag}
          </span>
        ))}

        {!props.stepperLocked && (
          <div style={{ display: 'flex', alignItems: 'center', gap: '6px', marginTop: '6px' }}>
            <button type="button" onClick={props.decrement} disabled={props.busy}>&minus;</button>
            <input
              value={props.quantityInput}
              onInput={props.onQuantityInput}
              onBlur={props.commitQuantity}
              onKeyDown={props.onQuantityKeyDown}
              size={2}
            />
            <button type="button" onClick={props.increment} disabled={props.busy}>+</button>
            <button type="button" onClick={props.remove} disabled={props.busy}>
              {props.pending === 'remove' ? 'Removing…' : 'Remove'}
            </button>
          </div>
        )}
      </div>

      <div style={{ textAlign: 'right' }}>
        <div>{props.price}</div>
        {props.compareAtPrice && <s style={{ opacity: 0.5 }}>{props.compareAtPrice}</s>}
        {props.savingsHtml && <div dangerouslySetInnerHTML={{ __html: props.savingsHtml }} />}
      </div>
    </div>
  );
}
```

<div id="rendering-a-bundle">
  ### Отображение бандла
</div>

У якорной строки бандла `bundle.children` содержит его состав. Дочерние товары никогда не появляются как отдельные строки, поэтому если вы их не отобразите, покупатель не увидит, что входит в бандл:

```jsx theme={"theme":{"light":"snazzy-light","dark":"github-dark"}}
function CustomTemplate(props) {
  return (
    <div>
      <div>{props.title} {props.price}</div>

      {props.bundle && (
        <ul style={{ margin: '4px 0 0 12px', fontSize: '12px', opacity: 0.7 }}>
          {props.bundle.children.map((child, i) => (
            <li key={child.key ?? i}>{child.quantity} × {child.title}</li>
          ))}
        </ul>
      )}
    </div>
  );
}
```

`key` дочернего товара равен `null` для компонента нативного бандла Shopify, поэтому используйте индекс как запасной вариант, как выше.

<div id="design">
  ## Дизайн
</div>

Оформляйте этот блок в разделе **Design** его панели настроек. Это переопределения на уровне блока, которые накладываются поверх глобального дизайна и наследуют его, если поля пусты.

Что такое настройки дизайна? Подробнее здесь: [Настройки дизайна](/ru/aftersell/cart/design-settings).
