Each cart row is now a swipeout with a green +1 on the left and a confirmed Remove on the right:
<li class="swipeout" key="${line.id}" @swipeout:deleted=${() => remove(line)}>
<div class="swipeout-content item-content">
<div class="item-inner">
<div class="item-title">${line.book.title}
<div class="item-footer">${line.qty} × ${money(line.book.price)}</div>
</div>
<div class="item-after">${money(line.qty * line.book.price)}</div>
</div>
</div>
<div class="swipeout-actions-left">
<a href="#" class="color-green swipeout-close" @click=${() => addOne(line)}>+1</a>
</div>
<div class="swipeout-actions-right">
<a href="#" class="swipeout-delete" data-confirm="Remove ${line.book.title}?"
data-confirm-title="Cart">Remove</a>
</div>
</li>`)}remove(line) logs and dispatches removeFromCart; addOne(line) dispatches setQty with one more. With The Quiet Harbor, Salt and Saffron and Gardens in Glass in the cart, swiping the second row left and confirming logged swiped away book 3; the Store's cart became [{"id":1,"qty":1},{"id":6,"qty":1}], the total fell from $60.29 to $36.29 and the tab badge from 3 to 2. A right swipe and +1 on the first row raised its quantity to 2.

Framework7 572,986 removes the li itself, then the Store update re-renders the list without it; with a key per row, the virtual DOM matches rows by book id, and no error appeared in the console.