@vio-live/web-sdk 0.29.0 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +171 -0
- package/README.md +108 -15
- package/dist/{chunk-L6YYYKQK.js → chunk-C5Q6W4B2.js} +1392 -202
- package/dist/chunk-C5Q6W4B2.js.map +1 -0
- package/dist/{chunk-AG4G2S2M.js → chunk-IR4XYTZL.js} +493 -79
- package/dist/chunk-IR4XYTZL.js.map +1 -0
- package/dist/chunk-QGJUBVH3.js +3 -0
- package/dist/{chunk-67QESEV2.js.map → chunk-QGJUBVH3.js.map} +1 -1
- package/dist/core/index.d.ts +147 -3
- package/dist/core/index.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/react/index.d.ts +2 -2
- package/dist/react/index.js +3 -3
- package/dist/{tokens-Dok4d21V.d.ts → tokens-D1DCVzOf.d.ts} +311 -21
- package/dist/ui/index.d.ts +1 -1
- package/dist/ui/index.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-67QESEV2.js +0 -3
- package/dist/chunk-AG4G2S2M.js.map +0 -1
- package/dist/chunk-L6YYYKQK.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,177 @@ How to keep this file: see [CONTRIBUTING → Changelog](CONTRIBUTING.md#changelo
|
|
|
14
14
|
The details of each feature live in the [README](README.md); this file says *what*
|
|
15
15
|
and *when*, and links there.
|
|
16
16
|
|
|
17
|
+
## 0.32.0 — 2026-10-28
|
|
18
|
+
|
|
19
|
+
> First version published to npm since 0.29.0: **0.30.0 and 0.31.0 were never published on their own** — their
|
|
20
|
+
> changes (below) ship in this version too. A host on 0.29.0 should read the three sections.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **Options for the product detail** (README → *Options of the detail and the product cards*):
|
|
24
|
+
`gallery="carousel"` (every photo in one swipeable row with dots, no thumbnails),
|
|
25
|
+
`description-mode` (`preview` · `folded` · `open`), `highlights`, `delivery-time`,
|
|
26
|
+
`carrier-logos`; theme keys `detailGallery`, `detailCarouselPeek`, `detailDescriptionMode`,
|
|
27
|
+
`detailDescriptionPreviewLines`, `detailHighlightsDisplay`, `detailShippingReturnsDisplay`.
|
|
28
|
+
- **The brand's promises** under the buy zone (icon, title, line of text — up to three), from the
|
|
29
|
+
sponsor block's `highlights` (dashboard Settings → Brand) unless the host passes its own.
|
|
30
|
+
- **«Frakt & retur»** fold after «Beskrivelse»: one row per carrier (its logo from Commerce's
|
|
31
|
+
`logo_url`, or `carrier-logos`, or a line icon by the kind of delivery), how it delivers, the
|
|
32
|
+
price; the delivery time the brand wrote on the rate («Leveringstid 1-5 dager»); the right of
|
|
33
|
+
withdrawal and the brand's pages.
|
|
34
|
+
- **Product cards:** `<vio-product-carousel layout="list">` (one under the other),
|
|
35
|
+
`show-description` / `descriptions` (the catalogue's text or the editor's own per product),
|
|
36
|
+
`button-style` (`icon` · `bar` · `hidden`) and `button-label` (the Vev card's «Kjøp» bar); card
|
|
37
|
+
look through theme keys `card*` and `--vio-card-*`.
|
|
38
|
+
- `commerce.channel.product.getShippingRates` returns each rate's `description` and `logoUrl`.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
- **The detail's order is the same on every screen**: sizes first in the buy zone, «Frakt fra …»
|
|
42
|
+
under them, stock on the name's line, «Beskrivelse» at the very bottom. The buy zone no longer
|
|
43
|
+
pins itself on desktop (`detailBuyPosition: 'sticky'` brings that back).
|
|
44
|
+
- **«Beskrivelse» shows a preview** (the first three lines and «Les mer») instead of being folded
|
|
45
|
+
shut. `description-mode="folded"` keeps the old behaviour.
|
|
46
|
+
- **The sheets close with a pull down from anywhere** while their content is at the top, not only
|
|
47
|
+
from the grab bar or the top bar (detail, cart, checkout).
|
|
48
|
+
|
|
49
|
+
### ⚠️ Upgrade notes
|
|
50
|
+
- Rates are asked with `logo_url`; a gateway without the field is asked again without it once
|
|
51
|
+
(and not again on that page), so the rates never go missing over a logo.
|
|
52
|
+
- A host that styled `details.description-block` for «Beskrivelse» now gets
|
|
53
|
+
`.description-preview` (`part="description"` unchanged).
|
|
54
|
+
|
|
55
|
+
## 0.31.0 — 2026-10-28
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
- **Delivery and returns under the price in the product detail.** It reads «Frakt fra X · 14
|
|
59
|
+
dagers angrerett», where X is the product's cheapest shipping rate for the page's market (the
|
|
60
|
+
same `product_shipping` rates the backend cart offers). A cheapest rate of 0 reads «Gratis frakt».
|
|
61
|
+
With no known rate, only «14 dagers angrerett» is shown (`part="delivery-note"`). The rates come
|
|
62
|
+
from a separate query (`commerce.channel.product.getShippingRates`), so a failure there only
|
|
63
|
+
loses this line.
|
|
64
|
+
- **The cart drawer shows shipping and the total including it.** It uses the rate chosen on the
|
|
65
|
+
server cart, or the cheapest rate offered. Without a known rate it reads «Frakt: Beregnes i
|
|
66
|
+
kassen» and shows no total (`part="cart-shipping"`, `part="cart-total"`).
|
|
67
|
+
- **«Lagt i handlekurven» after «Legg i handlekurv».** The detail closes and a small toast offers
|
|
68
|
+
**«Til kassen»** and **«Fortsett å handle»** (`part="added-toast"`). «Til kassen» dispatches
|
|
69
|
+
`vio:checkout-open` for that brand, the same event the cart's «Til kassen» sends. It does nothing
|
|
70
|
+
when the cart was emptied in the meantime. The toast closes by itself after 8 s.
|
|
71
|
+
- **A line under «Kjøp nå med Vipps» in the product detail:** «Vipps fyller inn navn og adresse –
|
|
72
|
+
du godkjenner og betaler i appen» (`part="vipps-note"`). It is shown only when that button goes
|
|
73
|
+
straight to the app: Express is on for the brand and the brand's cart is empty. In other cases
|
|
74
|
+
the button opens the checkout first.
|
|
75
|
+
### Changed
|
|
76
|
+
- **The product detail no longer picks a size for the shopper.** Only an option with a single
|
|
77
|
+
value is preselected. The chosen value is shown beside the option's name («Størrelse: M») and
|
|
78
|
+
on its pill. Every buy button (Vipps, «Legg i handlekurv», «Kjøp nå», Stripe, Klarna, Apple Pay)
|
|
79
|
+
checks for a missing choice first: it shows «Velg størrelse» (or «Velg farge», etc.) and adds or
|
|
80
|
+
pays nothing. «Få igjen — N stk» now counts only the variant actually chosen. Before a size is
|
|
81
|
+
chosen it says «På lager» if any size is in stock.
|
|
82
|
+
- **Two Vipps paths.** The product detail's «Kjøp nå med Vipps» stays **Express**. The
|
|
83
|
+
**cart's** Vipps button now opens the checkout with Vipps preselected. It no longer starts
|
|
84
|
+
Express or hands over to Vipps. **The checkout's Vipps is always the standard payment**, even
|
|
85
|
+
when the brand has Express on:
|
|
86
|
+
- the address form, the delivery and its price are required before paying, as for Stripe;
|
|
87
|
+
- the summary counts our shipping rate, so «Velges i Vipps» is gone;
|
|
88
|
+
- the payment is `startVippsPayment(sponsorId, form, { express: false })`, which now puts the
|
|
89
|
+
form's complete address on the checkout's shipping and billing address.
|
|
90
|
+
|
|
91
|
+
`COLLECTS_OWN_ADDRESS` no longer lists Vipps. See
|
|
92
|
+
[README → Two Vipps paths](README.md#the-hand-over-to-vipps-028).
|
|
93
|
+
- **«Mobilnummer» in the checkout's address form.** It is required only for the standard Vipps
|
|
94
|
+
payment, and optional for every other method; it never blocks their buttons or widgets.
|
|
95
|
+
- It accepts any market's number. A `+`/`00` prefix sets the calling code; without one, the
|
|
96
|
+
shipping country does (NO 47, SE 46, DK 45, FI 358, DE 49, GB 44…), falling back to the
|
|
97
|
+
page's country. A trunk 0 is dropped.
|
|
98
|
+
- A number that cannot be read shows «Skriv et gyldig mobilnummer…».
|
|
99
|
+
- It is sent as `phone` (national digits) + `phone_code` (digits, no plus) on the shipping and
|
|
100
|
+
billing address of every method that takes our form. `CheckoutAddress.phone` is new.
|
|
101
|
+
- **The checkout's Vipps refuses to start without the delivery saved.** If the chosen rate cannot
|
|
102
|
+
be saved on the cart, the Vipps or Stripe-link payment does not start and the checkout says
|
|
103
|
+
«Kunne ikke lagre fraktmetoden. Prøv igjen.». This covers a failed save and a rate without a
|
|
104
|
+
supplier. `startVippsPayment(…, { express: false })` also throws before creating anything when
|
|
105
|
+
the address is incomplete or has no usable mobile.
|
|
106
|
+
|
|
107
|
+
### Fixed
|
|
108
|
+
- **«Velg størrelse» no mueve las tallas.** El aviso sale en la misma línea que el nombre de la opción, así que tocar comprar sin talla ya no desplaza los botones bajo el dedo.
|
|
109
|
+
- **No checkout and no payment for an empty cart or a total of 0 kr.** `Vio.checkout.open()`
|
|
110
|
+
throws for a cart that totals 0, as it already did for an empty one. Vipps (`startVippsPayment`,
|
|
111
|
+
`startVippsExpress`), the Stripe link, native Stripe and Adyen read the cart from the server and
|
|
112
|
+
refuse to create a checkout or a payment when it is empty or 0 kr. The buttons check the same
|
|
113
|
+
thing first: the cart's «Til kassen» is disabled, the checkout's pay buttons are disabled and
|
|
114
|
+
say «Handlekurven er tom.», and the detail shows no Vipps or Apple Pay button for a product at 0 kr.
|
|
115
|
+
- **Desktop: the product detail's pinned buy bar no longer covers the size picker.** The option
|
|
116
|
+
pickers now sit at the top of the buy zone (`part="buy-options"`), so they move with the
|
|
117
|
+
buttons whether the zone is static or sticky.
|
|
118
|
+
- **No buttons for payment methods the brand does not have while its methods load.** The
|
|
119
|
+
product detail and the cart drawer show a neutral placeholder (`part="buy-pending"` /
|
|
120
|
+
`.methods-pending`) until `getAvailablePaymentMethods` answers. They used to show every method,
|
|
121
|
+
so a Vipps-only brand flashed Stripe and Klarna. «Legg i handlekurv» and «Til kassen» are there
|
|
122
|
+
from the start. A failed lookup still shows every button, as before.
|
|
123
|
+
- **Storage never blocks add to cart or checkout (in-app browsers, private modes).** Every read
|
|
124
|
+
and write of `localStorage`/`sessionStorage` goes through one guard, `src/core/safe-storage.ts`.
|
|
125
|
+
A storage property that throws on access, a `null` storage or a refused write now falls back to
|
|
126
|
+
the page's memory. This covers the cart, the customer session id, the market's
|
|
127
|
+
currency/country/locale and the Klarna return. Before, `typeof localStorage` outside a `try`
|
|
128
|
+
could throw while the SDK started. Without storage, every browser also sent the same customer
|
|
129
|
+
session id, `cs_session_default`. It is now one id per page.
|
|
130
|
+
|
|
131
|
+
### ⚠️ Upgrade notes
|
|
132
|
+
- The detail's buy buttons stay enabled before a size is chosen. Tapping one shows the prompt
|
|
133
|
+
instead of buying. A host that clicks `.add-to-cart` from a script needs a value in every option
|
|
134
|
+
first.
|
|
135
|
+
- A host's `vio:checkout-open` handler that calls `Vio.checkout.open()` must still catch the throw
|
|
136
|
+
(it already threw for an empty cart). It now also throws for a cart of 0 kr.
|
|
137
|
+
- Host CSS that placed `::part(option-group)` relative to `::part(buy)` should be checked: the
|
|
138
|
+
option groups are now inside `buy`.
|
|
139
|
+
- A host that already answers `vio:added-to-cart` with its own UI (for example, opening its cart
|
|
140
|
+
drawer) can turn the new toast off with `<vio-product-detail no-added-toast>`. The toast's
|
|
141
|
+
«Til kassen» relies on the host's `vio:checkout-open` handler, like the cart's does.
|
|
142
|
+
- **Backend (shopcart):** the checkout's Vipps payment is now `express: false` with the address
|
|
143
|
+
already on the checkout. shopcart must not request the Vipps profile on these standard
|
|
144
|
+
payments, and must carry the address `phone`/`phone_code` through to the order. Until that is
|
|
145
|
+
deployed, check a QA order to confirm the phone arrives.
|
|
146
|
+
- Hosts that pre-fill the checkout form through `Vio.checkout.setAddress()` should include
|
|
147
|
+
`phone`, or the shopper has to type it when paying with Vipps. Other methods do not need it.
|
|
148
|
+
- **The cart's Vipps button now opens the checkout through `vio:checkout-open`**, with
|
|
149
|
+
`paymentMethod: 'vipps'`. A host without a handler for that event loses direct Vipps from the
|
|
150
|
+
cart. The `vio:payment-redirect-*` events with `source: 'cart'` are gone; those with
|
|
151
|
+
`'detail'` and `'checkout'` remain.
|
|
152
|
+
- **`startVippsPayment(sponsorId, form, { express: false })` writes the full address**, including
|
|
153
|
+
the mobile, to the checkout's shipping and billing address before it creates the payment.
|
|
154
|
+
Without the flag, or with `express: true`, nothing changes.
|
|
155
|
+
- `Vio.checkout.open()` throws on a cart that totals 0, as well as on an empty one.
|
|
156
|
+
- The «Lagt i handlekurven» toast is on by default. Use `<vio-product-detail no-added-toast>` to
|
|
157
|
+
turn it off.
|
|
158
|
+
|
|
159
|
+
## 0.30.0 — 2026-10-27
|
|
160
|
+
|
|
161
|
+
### Added
|
|
162
|
+
- **Internal traffic** (ADR-0041): opening any page with **`?vio_internal=1`** marks the browser
|
|
163
|
+
(`localStorage`, `vio.internal.v1`) and `?vio_internal=0` clears it; read once at `Vio.init()`.
|
|
164
|
+
While marked, every analytics event carries **`client.internal: true`** and the collector's
|
|
165
|
+
reads leave it out. **`Vio.analytics.setInternal(boolean)`** / `Vio.analytics.isInternal` for
|
|
166
|
+
hosts; one `console.info` when marked. See
|
|
167
|
+
[README → Internal traffic](README.md#internal-traffic--mark-your-browser-as-a-tester-unreleased).
|
|
168
|
+
|
|
169
|
+
### Changed
|
|
170
|
+
- **Stripe.js (~300 KB) is downloaded only for a brand that uses Stripe.** It used to load on
|
|
171
|
+
every page as soon as the SDK started, to have Apple Pay ready. Now it loads when the brand's
|
|
172
|
+
payment methods come back with a Stripe key (or when the host passes `stripePublishableKey`
|
|
173
|
+
to `Vio.init`). A brand that only takes Vipps never downloads it. Apple Pay still has it before
|
|
174
|
+
the tap: its button waits for the same key.
|
|
175
|
+
- **`component_impression` of `<vio-product-carousel>` carries `commerce.items`** — the products
|
|
176
|
+
shown, like its `view_item_list` — so the collector can count per-product impressions
|
|
177
|
+
(ADR-0041). The impression is observed once the products have loaded (the 1 s dwell starts
|
|
178
|
+
then); a failed fetch still counts it, without items. `Vio.analytics.observeImpression()` takes
|
|
179
|
+
a `commerce` getter, read when the impression fires. See
|
|
180
|
+
[README → Impressions carry the products shown](README.md#impressions-carry-the-products-shown-unreleased).
|
|
181
|
+
- Events never carry more than 100 `commerce.items` (the collector rejects the whole event above
|
|
182
|
+
its cap).
|
|
183
|
+
|
|
184
|
+
### ⚠️ Upgrade notes
|
|
185
|
+
- `client.internal` needs the collector that knows the field; an older one strips it (the event is
|
|
186
|
+
kept, just not marked). Nothing to do on the host.
|
|
187
|
+
|
|
17
188
|
## 0.29.0 — 2026-10-24
|
|
18
189
|
|
|
19
190
|
### Added
|
package/README.md
CHANGED
|
@@ -519,6 +519,49 @@ redirect }` — which is what analytics listens to; a host with its own sink can
|
|
|
519
519
|
listen to it too. With `dataLayer: true` it is pushed as GA4's `add_payment_info`
|
|
520
520
|
with `payment_type`.
|
|
521
521
|
|
|
522
|
+
### Impressions carry the products shown (unreleased)
|
|
523
|
+
|
|
524
|
+
`<vio-product-carousel>`'s **`component_impression`** (≥50% visible for ≥1 s, once
|
|
525
|
+
per session and carousel) carries the products it shows in **`commerce.items`**
|
|
526
|
+
(`product_id`, `name`, `price`) and `commerce.currency` — the same lines as its
|
|
527
|
+
`view_item_list`. The collector counts the per-product "saw" step of the funnel
|
|
528
|
+
from them (ADR-0041). While the products load nothing is observed: the 1 s dwell
|
|
529
|
+
starts once they are on screen. A carousel whose fetch failed (slotted fallback)
|
|
530
|
+
still counts its impression, without items. A host calling
|
|
531
|
+
`Vio.analytics.observeImpression(el, context, { commerce: () => ({ items, currency }) })`
|
|
532
|
+
does the same for its own elements: the getter is read when the impression fires.
|
|
533
|
+
|
|
534
|
+
### Internal traffic — mark your browser as a tester (unreleased)
|
|
535
|
+
|
|
536
|
+
Our own visits (testers, the team, agents) must not count in the dashboard. Mark
|
|
537
|
+
**each browser you test with** once:
|
|
538
|
+
|
|
539
|
+
1. Open any page of the site that runs the SDK with **`?vio_internal=1`** added to
|
|
540
|
+
the URL — e.g. `https://example.com/article?vio_internal=1` (or
|
|
541
|
+
`…?utm_source=x&vio_internal=1` when the URL already has a query).
|
|
542
|
+
2. Open the browser's console: the SDK says once
|
|
543
|
+
`[Vio.analytics] this browser is marked as internal traffic …`.
|
|
544
|
+
3. That's it. The mark is remembered in this browser (`localStorage`,
|
|
545
|
+
`vio.internal.v1`, per site) for every page and every later visit, and every
|
|
546
|
+
analytics event it sends carries **`client.internal: true`**; the collector's
|
|
547
|
+
reads leave those events out.
|
|
548
|
+
|
|
549
|
+
To **undo** it, open any page with **`?vio_internal=0`**. Things to know:
|
|
550
|
+
|
|
551
|
+
- The mark is per browser and per site: Safari and Chrome on the same phone, a
|
|
552
|
+
private window, or another site are marked separately. Clearing the site's data
|
|
553
|
+
clears the mark.
|
|
554
|
+
- In-app browsers (Instagram, Facebook) and private windows may not keep
|
|
555
|
+
`localStorage`: there, only the page opened with `?vio_internal=1` is marked.
|
|
556
|
+
Prefer a regular browser for testing.
|
|
557
|
+
- The URL is read once per page load (at `Vio.init()`), not on client-side
|
|
558
|
+
navigation.
|
|
559
|
+
- The mark is the tester's own choice, not a tracking id: it is written even
|
|
560
|
+
before consent (`requireConsent`).
|
|
561
|
+
- A host can mark from code: **`Vio.analytics.setInternal(true | false)`**
|
|
562
|
+
(`Vio.analytics.isInternal` reads it). `resolveInternal()` / `INTERNAL_KEY` are
|
|
563
|
+
exported from `/core`.
|
|
564
|
+
|
|
522
565
|
## Sponsor identity — name and logo
|
|
523
566
|
|
|
524
567
|
The elements say **who sells**: the sponsor's (brand's) display name and logo.
|
|
@@ -650,7 +693,7 @@ or on the element (`vio-product-detail { --vio-detail-logo-height: 48px; }`).
|
|
|
650
693
|
| `detailOptionHeight` / `detailOptionGap` | `--vio-detail-option-height` / `--vio-detail-option-gap` | `36px` / `6px` | Size / option buttons (height is also their min width) |
|
|
651
694
|
| `detailOptionRadius` / `detailOptionWrap` | `--vio-detail-option-radius` / `--vio-detail-option-wrap` | `0` / `wrap` | `nowrap` = one line that scrolls sideways |
|
|
652
695
|
| `detailButtonHeight` / `detailButtonRadius` | `--vio-detail-button-height` / `--vio-detail-button-radius` | `52px` / `0` | Quantity stepper and «Legg i handlekurv» |
|
|
653
|
-
| `detailBuyPosition` / `detailBuyShadow` | `--vio-detail-buy-position` / `--vio-detail-buy-shadow` |
|
|
696
|
+
| `detailBuyPosition` / `detailBuyShadow` | `--vio-detail-buy-position` / `--vio-detail-buy-shadow` | `static` | `sticky` pins the buy zone (Vipps, quantity, add to cart) to the bottom of the panel while scrolling |
|
|
654
697
|
| `cartWidth` / `checkoutWidth` | `--vio-cart-width` / `--vio-checkout-width` | `440px` | Drawer widths (desktop) |
|
|
655
698
|
| `confirmLogoHeight` / `confirmTitleSize` / `confirmCheckBg` | `--vio-confirm-logo-height` / `--vio-confirm-title-size` / `--vio-confirm-check-bg` | `40px` / `24px` / green | The confirmation |
|
|
656
699
|
| `redirectBg` / `redirectSpinner` | `--vio-redirect-bg` / `--vio-redirect-spinner` | translucent white / Vipps orange | The «Åpner Vipps …» overlay |
|
|
@@ -666,10 +709,14 @@ Also settable as CSS only: `--vio-detail-logo-max-width` (`220px`), `--vio-detai
|
|
|
666
709
|
**`::part` names**, for what the properties do not cover:
|
|
667
710
|
|
|
668
711
|
- `<vio-product-detail>`: `topbar`, `sponsor`, `close`, `gallery`, `image`, `thumbs`, `thumb`
|
|
669
|
-
(+ `thumb-active`), `thumbs-arrow`, `info`, `brand`, `title`, `price`, `
|
|
670
|
-
`
|
|
671
|
-
`
|
|
672
|
-
`
|
|
712
|
+
(+ `thumb-active`), `thumbs-arrow`, `info`, `brand`, `title`, `price`, `delivery-note`
|
|
713
|
+
(`delivery-shipping`, `delivery-withdrawal`), `stock`, `buy`, `buy-options`, `option-group`,
|
|
714
|
+
`option-label`, `option-chosen`, `option-prompt`, `options`, `option` (+ `option-selected`),
|
|
715
|
+
`buy-pending`, `buy-vipps`, `vipps-note`, `quantity-row`, `add-to-cart`, `seller-note`,
|
|
716
|
+
`seller-terms`, `seller-refund`, `description`, `highlights`, `highlight`, `shipping-returns`,
|
|
717
|
+
`slide`, `image-dots`, `carousel-arrow`, `added-toast` (`added-toast-checkout`,
|
|
718
|
+
`added-toast-continue`).
|
|
719
|
+
- `<vio-cart>`: `cart-shipping`, `cart-total`.
|
|
673
720
|
- `<vio-checkout>`: `sponsor`, `confirmation`, `confirm-title`, `confirm-sponsor`, `confirm-details`.
|
|
674
721
|
|
|
675
722
|
```css
|
|
@@ -677,14 +724,51 @@ vio-product-detail::part(add-to-cart) { letter-spacing: 0; text-transform: none;
|
|
|
677
724
|
vio-product-detail::part(option-selected) { background: #2b2b2b; }
|
|
678
725
|
```
|
|
679
726
|
|
|
680
|
-
**The detail's order:** the selling brand top left; the
|
|
681
|
-
name
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
the
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
727
|
+
**The detail's order:** the selling brand top left; the images (thumbnails, or a carousel);
|
|
728
|
+
name and stock on one line, the price; the buy zone — the sizes (none preselected; every buy
|
|
729
|
+
button asks «Velg størrelse» first), «Frakt fra X · 14 dagers angrerett», **Vipps first** (when
|
|
730
|
+
the channel has it), quantity + «Legg i handlekurv», the other ways to pay, and under them «Du
|
|
731
|
+
handler direkte hos {brand}.» (the product's brand, never the article's) with links to the
|
|
732
|
+
brand's «Kjøpsvilkår» and «Angrerett og retur» when it gave them (the sponsor block's
|
|
733
|
+
`termsUrl` / `refundPolicyUrl`, https only, new tab); the brand's promises; «Beskrivelse»; and
|
|
734
|
+
«Frakt & retur». The same order on every screen.
|
|
735
|
+
|
|
736
|
+
### Options of the detail and the product cards (0.32)
|
|
737
|
+
|
|
738
|
+
Every one is off or as before unless the host sets it: per element (attribute), or for the
|
|
739
|
+
whole page through `applyVioTheme` (theme key → custom property). The element wins.
|
|
740
|
+
|
|
741
|
+
**`<vio-product-detail>`**
|
|
742
|
+
|
|
743
|
+
| Attribute | Theme key | Values | What |
|
|
744
|
+
|---|---|---|---|
|
|
745
|
+
| `gallery` | `detailGallery` | `thumbs` (default) · `carousel` | `carousel`: every photo in one swipeable row with a dot per photo, no thumbnails — less height. `detailCarouselPeek` (`--vio-detail-carousel-peek`) shows the edge of the next one |
|
|
746
|
+
| `description-mode` | `detailDescriptionMode` | `preview` (default) · `folded` · `open` | «Beskrivelse»: the first lines fading out + «Les mer» (`detailDescriptionPreviewLines`, `3`); only the heading until a tap; or all of it |
|
|
747
|
+
| `highlights` | — | `[{ icon, title, text }]` (JSON) | The brand's promises under the buy zone. By default the brand's own (dashboard Settings → Brand, sponsor block `highlights`); this list replaces them on the page. Icons: `plane heart shirt truck return leaf star shield mailbox home pin clock`, or an image URL. `detailHighlightsDisplay: 'none'` hides the strip |
|
|
748
|
+
| `delivery-time` | — | text, e.g. `2-5 virkedager` | «Leveringstid …» in «Frakt & retur» for a brand whose rates do not say it (each rate's own text in Commerce — «Leveringstid 1-5 dager» — wins) |
|
|
749
|
+
| `carrier-logos` | — | `{ "Bring": "https://…" }` (JSON) | Carrier logos by the name the rate starts with («Bring - Pakke i postkasse»), for rates without their own logo in Commerce (`logo_url`, which wins); otherwise a line icon by the kind of delivery |
|
|
750
|
+
| — | `detailShippingReturnsDisplay` | `block` (default) · `none` | «Frakt & retur»: one row per carrier (logo or icon, carrier, how it delivers, price), the delivery time, the right of withdrawal and the brand's pages |
|
|
751
|
+
|
|
752
|
+
The sheet closes with a pull down from its top bar, or from anywhere while its content is at the top.
|
|
753
|
+
|
|
754
|
+
**`<vio-product-carousel>`** (and its cards, `<vio-product>`)
|
|
755
|
+
|
|
756
|
+
| Attribute | Theme key | Values | What |
|
|
757
|
+
|---|---|---|---|
|
|
758
|
+
| `layout` | `carouselLayout` | `carousel` (default) · `list` | `list`: one card under the other, as wide as the column (`--vio-carousel-list-max-width`, `480px`) |
|
|
759
|
+
| `show-description` | — | boolean | Each card shows its product's description (`cardDescriptionLines`, `4`) |
|
|
760
|
+
| `descriptions` | — | `{ "<productId>": "text" }` (JSON) | The editor's own text for a product, over the catalogue's — shown even without `show-description`; `""` hides that one |
|
|
761
|
+
| `button-style` | — | `icon` (default) · `bar` · `hidden` | The buy button: the round bag on the image, a full-width «Kjøp» bar under the price (as the Vev card), or none. Both add to the cart, or open the product when it has sizes |
|
|
762
|
+
| `button-label` | — | text, default `Kjøp` | The bar's text («Kjøp · 2» once two are in the cart) |
|
|
763
|
+
|
|
764
|
+
Card look, by theme key (custom property): `cardFont`, `cardBorder`, `cardImageAspect`,
|
|
765
|
+
`cardImageFit`, `cardImageBg`, `cardImagePadding`, `cardMetaPadding`, `cardPriceFont`,
|
|
766
|
+
`cardAccent`, `cardBarRadius`, `cardDescriptionLines`, `cardRetailerOrder` (`-1` lifts the seller
|
|
767
|
+
line above the name). CSS only: `--vio-card-border-hover-color`, `--vio-card-add-size`,
|
|
768
|
+
`--vio-card-add-icon-size`, `--vio-card-brand-{size,tracking,weight,color,gap}`,
|
|
769
|
+
`--vio-card-name-{font,size,weight,gap}`, `--vio-card-price-{size,weight,gap}`,
|
|
770
|
+
`--vio-card-retailer-{display,size,tracking,weight,color,margin}`,
|
|
771
|
+
`--vio-card-description-{size,color,gap}`, `--vio-card-accent-text`.
|
|
688
772
|
|
|
689
773
|
### The hand-over to Vipps (0.28)
|
|
690
774
|
|
|
@@ -706,8 +790,17 @@ detail adds the product to the sponsor's cart and the checkout is built on that
|
|
|
706
790
|
every line in it. It goes straight to Vipps only when the cart was **empty**; with lines
|
|
707
791
|
already in it, the product is added and the checkout opens first (`vio:checkout-open`
|
|
708
792
|
with `paymentMethod: 'vipps'`, no hand-over events), every line and the total on screen,
|
|
709
|
-
so what the Vipps page lists is what the shopper saw.
|
|
710
|
-
|
|
793
|
+
so what the Vipps page lists is what the shopper saw.
|
|
794
|
+
|
|
795
|
+
**Two Vipps paths (2026-10-28).** The detail's «Kjøp nå med Vipps» is **Express**: the app
|
|
796
|
+
fills in name and address. The **cart's** Vipps button opens the checkout with Vipps
|
|
797
|
+
preselected, and the checkout's Vipps is always the **standard** payment, even when the
|
|
798
|
+
brand has Express on. Our form collects name, e-mail, **Mobilnummer**, address and the
|
|
799
|
+
delivery with its price before paying. The mobile is required for Vipps only and accepts any
|
|
800
|
+
market's number: the `+` prefix or the shipping country sets the calling code. The delivery is
|
|
801
|
+
saved on the cart first; if that fails, no payment starts. The payment goes out with
|
|
802
|
+
`express: false`, and the address (with `phone` + `phone_code`) is on the checkout's shipping
|
|
803
|
+
and billing address. **Apple Pay on the detail follows the same
|
|
711
804
|
rule**: its sheet's amount is fixed before the tap, so it opens only on an empty cart, for the
|
|
712
805
|
product × the chosen quantity; otherwise the checkout opens (`paymentMethod: 'apple-pay'`).
|
|
713
806
|
|