@orderlyshop/web-components 0.1.0-build.7063 → 0.1.0-build.7066

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/README.md CHANGED
@@ -615,13 +615,13 @@ collection.query = searchQuery;
615
615
 
616
616
  - `orderly-page-layout` provides reusable page regions for header, header actions, responsive primary navigation placement, left/right sidebars, content, footer, and overlay content. It includes a default logo image using `https://orderly.shop/home/App_Icon.svg`; override it with `logo-src`, `logo-alt`, and `logo-href`. Use `primary-nav-mobile-placement="header"` for the common mobile header burger pattern without a duplicate mobile layout template.
617
617
  - `orderly-home-page` composes page layout, responsive primary navigation, one product rail per top-level category, basket icon, basket drawer, product detail dialog, and footer. Configure it with `configureShop({ defaultShop })` plus attributes such as `title`, `eyebrow`, `rail-cta-label`, and `product-href`. The product dialog expand link follows the configured product URL mode, and compact `https://orderly.shop/...` product URLs are preserved when it builds hash or path routes.
618
- - `orderly-category-page` composes page layout, navigation, search, product grid, product detail, basket icon, and basket around a navigation category. Without properties it uses the package default shop configuration. Override with `configureShop({ defaultShop })` once per shop, set `base-url` or `product-href` in markup, or assign `category`, `navigationItems`, `sortOptions`, `client`, `defaultQuery`, and `basketController` from JavaScript for advanced cases. The product dialog expand link uses the configured product URL mode and still supports explicit per-page `product-href` overrides when a shop wants a different physical product page URL.
618
+ - `orderly-category-page` composes page layout, navigation, search, product grid, product detail, basket icon, and basket around a navigation category. Without properties it uses the package default shop configuration. Override with `configureShop({ defaultShop })` once per shop, set `base-url` or `product-href` in markup, or assign `category`, `navigationItems`, `sortOptions`, `client`, `defaultQuery`, and `basketController` from JavaScript for advanced cases. Configure `defaultShop.navigationLayout` or top-level `navigationLayout` to switch the package-owned category page from desktop side navigation to top horizontal category navigation while keeping the mobile burger in the header. The product dialog expand link uses the configured product URL mode and still supports explicit per-page `product-href` overrides when a shop wants a different physical product page URL.
619
619
  - `orderly-checkout-page` composes page layout, responsive primary navigation, checkout form, basket order summary, footer, shared basket state, delivery loading, and order-created cleanup. Delivery methods render as radio cards after address entry, service points render as radio-card pickup choices when required, and delivery changes verify the draft so totals update. If a persisted draft already contains a complete address, delivery methods are restored on mount; if it also contains a delivery choice, the draft is verified so the basket summary can show backend shipping and total prices. Configure copy through `configureShop({ defaultShop: { checkoutPageTitle, checkoutPageDescription, checkoutOrderTitle, checkoutTermsHref, checkoutLabels, basketLabels } })`, or assign `client`, `basketController`, `navigationItems`, `checkoutLabels`, and `basketLabels` from JavaScript.
620
- - `orderly-product-detail-page` composes page layout, navigation, product detail, basket drawer, and footer for a product route. Set `share-url`, the `shareUrl` property, or pass `#url=<encoded-share-url>` in the page URL; compact Orderly slugs are restored to `https://orderly.shop/...` before it calls `SearchService.Search` with `SearchQuery.ShareUrl` and renders the resolved `SearchObject`. Shops can tune outer gutters with `--orderly-product-detail-page-padding`, `--orderly-product-detail-page-mobile-padding`, `--orderly-product-detail-page-inline-padding`, and `--orderly-product-detail-page-mobile-inline-padding`.
620
+ - `orderly-product-detail-page` composes page layout, navigation, product detail, basket drawer, and footer for a product route. Set `share-url`, the `shareUrl` property, or pass `#url=<encoded-share-url>` in the page URL; compact Orderly slugs are restored to `https://orderly.shop/...` before it calls `SearchService.Search` with `SearchQuery.ShareUrl` and renders the resolved `SearchObject`. It forwards `details-before`, `purchase-note`, `secondary-cta`, and `details-after` slots to the nested product page. Shops can tune outer gutters with `--orderly-product-detail-page-padding`, `--orderly-product-detail-page-mobile-padding`, `--orderly-product-detail-page-inline-padding`, and `--orderly-product-detail-page-mobile-inline-padding`.
621
621
  - `orderly-stored-image` accepts `image: StoredImage`, resolves image URLs from the configured prefix, and applies `RotationDeg`, crop, and full-size metadata in the browser.
622
622
  - `orderly-credit` accepts `credit: Credit` or declarative `amount` and `currency` attributes, then renders stylable money markup. DKK values are formatted as `kr. <pris>`, for example `kr. 100,00`.
623
623
  - `orderly-product-tile` accepts `product: SearchObject` and emits `orderly-product-selected`, `orderly-add-to-basket`, and `orderly-remove-from-basket`. Templates can bind the product share URL with `data-orderly-bind="share-url"`; anchors without an existing `href` keep the raw share URL, while anchors that already point at a product page are rewritten to the configured physical product route using hash or path mode. Default tiles and statically hydrated category tiles include `schema.org/Product` and `schema.org/Offer` microdata for name, image, URL, description, SKU, brand, price, currency, and in-stock availability when those fields are present. When a `BasketController` is assigned through `basketController`, the default action button toggles between add and remove, using an icon-only button next to the price. Keyboard focus is indicated on the product title instead of a frame around the whole tile; custom tile templates should keep a title element with `data-orderly-bind="title"` or `.orderly-product-tile__title`.
624
- - `orderly-product-page` accepts `product: SearchObject`, renders all product image thumbnails, switches the selected image on thumbnail click, and exposes product details plus add-to-basket behavior. Product-page templates bind `title`, `description`, `brand`, `size`, `color`, `condition`, `price`, `image`, `addLabel`, and `closeLabel`; they also support `basket-action-label`, `basket-action-icon`, and `basket-action-state` so product-page add-to-basket markup can share the same binding names as product tiles. The fullscreen image viewer is package-owned, so custom product templates only need inline image markup plus optional thumbnail markup; the overlay, click/wheel zoom behavior, labels, focus handling, square image viewport, and overlay thumbnails are injected by the component itself unless `image-viewer="false"` is set. When opened inside an existing product dialog, the viewer is portaled into that open `<dialog>` so it stays above the product overlay; otherwise it is portaled to `document.body`. Main image frame styling lives on the default wrapper, not the inner `orderly-stored-image`, and shops can tune spacing/image framing with `--orderly-product-page-gap`, `--orderly-product-page-mobile-gap`, `--orderly-product-page-media-gap`, `--orderly-product-page-padding`, `--orderly-product-page-mobile-padding`, `--orderly-product-page-details-padding`, `--orderly-product-page-mobile-details-padding`, `--orderly-product-page-image-border`, `--orderly-product-page-image-radius`, `--orderly-product-page-image-background`, and `--orderly-product-page-thumbnail-border`.
624
+ - `orderly-product-page` accepts `product: SearchObject`, renders all product image thumbnails, switches the selected image on thumbnail click, and exposes product details plus add-to-basket behavior. Product-page templates bind `title`, `description`, `brand`, `size`, `color`, `condition`, `price`, `image`, `addLabel`, and `closeLabel`; they also support `basket-action-label`, `basket-action-icon`, and `basket-action-state` so product-page add-to-basket markup can share the same binding names as product tiles. The default product template has extension slots `details-before`, `purchase-note`, `secondary-cta`, and `details-after`; use these for shop-specific notices or links without replacing the whole product template. For simple default content, configure `defaultShop.productDetail.trustNote` and `defaultShop.productDetail.secondaryCta`. The fullscreen image viewer is package-owned, so custom product templates only need inline image markup plus optional thumbnail markup; the overlay, click/wheel zoom behavior, labels, focus handling, square image viewport, and overlay thumbnails are injected by the component itself unless `image-viewer="false"` is set. When opened inside an existing product dialog, the viewer is portaled into that open `<dialog>` so it stays above the product overlay; otherwise it is portaled to `document.body`. Main image frame styling lives on the default wrapper, not the inner `orderly-stored-image`, and shops can tune spacing/image framing with `--orderly-product-page-gap`, `--orderly-product-page-mobile-gap`, `--orderly-product-page-media-gap`, `--orderly-product-page-padding`, `--orderly-product-page-mobile-padding`, `--orderly-product-page-details-padding`, `--orderly-product-page-mobile-details-padding`, `--orderly-product-page-image-border`, `--orderly-product-page-image-radius`, `--orderly-product-page-image-background`, and `--orderly-product-page-thumbnail-border`.
625
625
  - `orderly-search-box` binds to a target `orderly-product-grid`. Use `mode="textbox"` for an inline search input or `mode="icon"` for a header icon that opens a full-page search overlay. Icon mode searches automatically with a 500ms debounce and renders matching product tiles below the search field. Default home and category pages use icon mode next to the basket icon.
626
626
  - `orderly-product-grid` accepts `query: SearchQuery`, merges the configured shop query scope, calls `SearchService.Search`, renders its own sort control from `sortOptions`, supports opaque `ContinuationToken` paging, manual paging, dynamic/infinite scroll, and default loading placeholders while the first page is pending.
627
627
  - `orderly-product-rail` accepts `query: SearchQuery`, title, CTA label, and CTA href, then renders the search as a horizontal scroll list by composing `orderly-product-grid`. It is useful for homepages and editorial rows where several category searches should be stacked vertically.
@@ -640,6 +640,19 @@ There are two different mobile navigation patterns:
640
640
  - `layout-desktop="horizontal" layout-mobile="burgermenu"` plus `primary-nav-mobile-placement="header"` means desktop horizontal navigation and an inline mobile burger in the page header next to search, basket, or other icon buttons. This is the recommended setup for the common storefront header pattern.
641
641
  - Custom `data-orderly-viewport="mobile"` page-layout templates are only needed when a shop replaces the whole page layout and wants manual control over where `data-orderly-slot="primary-nav"` is rendered.
642
642
 
643
+ Package-owned home, category, product, checkout, and payment pages read the same pattern from configuration:
644
+
645
+ ```ts
646
+ configureShop({
647
+ navigationLayout: {
648
+ primaryNavDesktopPlacement: "primary-nav",
649
+ primaryNavMobilePlacement: "header",
650
+ layoutDesktop: "horizontal",
651
+ layoutMobile: "burgermenu"
652
+ }
653
+ });
654
+ ```
655
+
643
656
  ```html
644
657
  <orderly-page-layout primary-nav-mobile-placement="header">
645
658
  <a slot="header" href="/">Shop name</a>
@@ -732,6 +745,18 @@ For dynamic paging, `orderly-product-grid` keeps the returned `PageResult.Contin
732
745
 
733
746
  Every component has a default light-DOM implementation and matching template hooks. Use `data-orderly-bind` for values, `data-orderly-action` for behavior, and `data-orderly-slot` for repeated or projected content. Product tile templates can bind `basket-action-icon`, `basket-action-label`, and `basket-action-state` and use `data-orderly-action="add-to-basket"` for the add/remove toggle. Product page templates keep the existing `addLabel` binding and also support `basket-action-label`, `basket-action-icon`, and `basket-action-state` for the same add-to-basket concept; use `data-orderly-action="add-to-basket"` for the action. Product page galleries use `data-orderly-slot="thumbnails"` and `data-orderly-action="select-image"` for custom thumbnail markup, while the fullscreen viewer overlay stays package-owned; shops can optionally mark a custom trigger with `data-orderly-image-viewer-trigger`, otherwise the inline `data-orderly-bind="image"` element becomes the trigger automatically. The viewer overlay may be moved outside the product-page host while open, either to `document.body` or to the nearest open `<dialog>`, so custom CSS or tests should target `[data-orderly-image-overlay]` instead of assuming the overlay remains inside `orderly-product-page`. Basket templates can add `data-orderly-slot="errors"` to place order-level `DraftOrder.Errors` exactly where a shop wants them. Product rail templates can replace the outer `layout`, inner `grid`, product item, loading state, and empty state. The main template names are `layout`, `grid`, `footer`, `product`, `thumbnail`, `image`, `basket`, `basket-icon`, `line`, `checkout`, `navigation`, `item`, `search-box`, `sort`, `sort-select`, `filter-panel`, `load-more`, `address-line`, `contact-item`, `opening-hour`, and `information-link`.
734
747
 
748
+ Use product page detail slots for small shop-specific content without replacing the package product template:
749
+
750
+ ```html
751
+ <orderly-product-detail-page>
752
+ <section slot="purchase-note">
753
+ <strong>Kurateret secondhand</strong>
754
+ <p>Alle varer er udvalgt og pakket i butikken.</p>
755
+ </section>
756
+ <a slot="secondary-cta" href="/butik/">Besøg butikken på Nørrebrogade</a>
757
+ </orderly-product-detail-page>
758
+ ```
759
+
735
760
  Product sorting belongs to `orderly-product-grid`: assign `grid.sortOptions = [{ label, orderBy }]` or pass sort options through `orderly-collection-page.sortOptions`. The default grid layout renders the sort select above the products. Custom grid layouts should include `data-orderly-slot="sort"` where the control should appear, and custom sort templates can use `data-orderly-template="sort"` with a `<select data-orderly-action="sort">`.
736
761
 
737
762
  Simple product queries can be declared in markup on `orderly-product-grid`, `orderly-product-rail`, and `orderly-collection-page`:
@@ -285,7 +285,7 @@
285
285
  "name": "OrderlyProductDetailPageElement",
286
286
  "tagName": "orderly-product-detail-page",
287
287
  "customElement": true,
288
- "description": "Default product detail page that resolves a SearchObject through SearchService.Search using SearchQuery.ShareUrl from share-url or #url.",
288
+ "description": "Default product detail page that resolves a SearchObject through SearchService.Search using SearchQuery.ShareUrl from share-url or #url and forwards product detail extension slots to the nested product page.",
289
289
  "attributes": [
290
290
  { "name": "base-url", "description": "Backend URL used when no client property is assigned." },
291
291
  { "name": "share-url", "description": "Product share URL mapped to SearchQuery.ShareUrl." },
@@ -306,6 +306,12 @@
306
306
  { "kind": "field", "name": "navigationItems", "type": { "text": "NavigationItem[]" } },
307
307
  { "kind": "field", "name": "basketLabels", "type": { "text": "BasketLabels" } }
308
308
  ],
309
+ "slots": [
310
+ { "name": "details-before", "description": "Forwarded to the nested product page before package-owned details." },
311
+ { "name": "purchase-note", "description": "Forwarded to the nested product page after the add-to-basket button." },
312
+ { "name": "secondary-cta", "description": "Forwarded to the nested product page after the purchase note." },
313
+ { "name": "details-after", "description": "Forwarded to the nested product page after package-owned details." }
314
+ ],
309
315
  "events": [
310
316
  { "name": "orderly-product-loaded", "type": { "text": "CustomEvent<{ product: SearchObject; shareUrl: string }>" } },
311
317
  { "name": "orderly-product-not-found", "type": { "text": "CustomEvent<{ shareUrl: string }>" } },
@@ -337,7 +343,7 @@
337
343
  "name": "OrderlyProductPageElement",
338
344
  "tagName": "orderly-product-page",
339
345
  "customElement": true,
340
- "description": "Product detail view with gallery thumbnails, package-owned fullscreen image viewer with a square viewport, add-to-basket behavior, and product-page template bindings including basket-action aliases.",
346
+ "description": "Product detail view with gallery thumbnails, package-owned fullscreen image viewer with a square viewport, add-to-basket behavior, product detail extension slots, and product-page template bindings including basket-action aliases.",
341
347
  "attributes": [
342
348
  { "name": "add-label", "description": "Add-to-basket button label." },
343
349
  { "name": "image-viewer", "description": "Controls the package-owned fullscreen image viewer. Set to false to disable it; when open, the viewer is portaled to document.body or the nearest open dialog." }
@@ -348,6 +354,12 @@
348
354
  { "kind": "field", "name": "basketController", "type": { "text": "BasketController | undefined" } },
349
355
  { "kind": "field", "name": "imageViewer", "type": { "text": "boolean" } }
350
356
  ],
357
+ "slots": [
358
+ { "name": "details-before", "description": "Content rendered before package-owned product details in the default template." },
359
+ { "name": "purchase-note", "description": "Content rendered after the add-to-basket button in the default template." },
360
+ { "name": "secondary-cta", "description": "Secondary call-to-action rendered after the purchase note in the default template." },
361
+ { "name": "details-after", "description": "Content rendered after package-owned product details in the default template." }
362
+ ],
351
363
  "events": [
352
364
  { "name": "orderly-add-to-basket", "type": { "text": "CustomEvent<ProductEventDetail>" } },
353
365
  { "name": "orderly-product-image-selected", "type": { "text": "CustomEvent<{ product?: SearchObject; image?: StoredImage; index: number }>" } }