@orderlyshop/web-components 0.1.0-build.7056 → 0.1.0-build.7058

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
@@ -559,15 +559,15 @@ collection.query = searchQuery;
559
559
 
560
560
  ## Components
561
561
 
562
- - `orderly-page-layout` provides reusable page regions for header, header actions, 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`.
563
- - `orderly-home-page` composes page layout, side 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.
562
+ - `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.
563
+ - `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.
564
564
  - `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.
565
- - `orderly-checkout-page` composes page layout, side 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. Configure copy through `configureShop({ defaultShop: { checkoutPageTitle, checkoutPageDescription, checkoutOrderTitle, checkoutTermsHref, checkoutLabels, basketLabels } })`, or assign `client`, `basketController`, `navigationItems`, `checkoutLabels`, and `basketLabels` from JavaScript.
565
+ - `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. Configure copy through `configureShop({ defaultShop: { checkoutPageTitle, checkoutPageDescription, checkoutOrderTitle, checkoutTermsHref, checkoutLabels, basketLabels } })`, or assign `client`, `basketController`, `navigationItems`, `checkoutLabels`, and `basketLabels` from JavaScript.
566
566
  - `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`.
567
567
  - `orderly-stored-image` accepts `image: StoredImage`, resolves image URLs from the configured prefix, and applies `RotationDeg`, crop, and full-size metadata in the browser.
568
568
  - `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`.
569
569
  - `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.
570
- - `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.
570
+ - `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.
571
571
  - `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.
572
572
  - `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.
573
573
  - `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.
@@ -575,15 +575,39 @@ collection.query = searchQuery;
575
575
  - `orderly-shop-footer` renders configurable logo, about text, address, contact information, opening hours, and information links.
576
576
  - `orderly-basket-icon` and `orderly-basket` share a `BasketController` backed by `DraftOrder` persistence. Basket state events such as `orderly-basket-open`, `orderly-basket-change`, and `orderly-basket-verified` use the current `DraftOrder` directly as `event.detail`, so consumers can derive counts and totals from Core contracts instead of an internal basket data shape. `orderly-basket` renders an item overview, verifies non-empty persisted drafts on load plus later basket mutations through `OrderService.VerifyDraft` when a client or `base-url` is configured, includes a configurable checkout link through `checkout-href` and `checkout-label`, and only exposes quantity selection for lines where `MaxQuantity > 1`. Summary rows now render only backend-provided `DraftOrder` values, never local subtotal/total math, and the component renders both `DraftOrder.Errors` and `DraftOrderLine.Errors`. Custom basket templates can project order-level errors through `data-orderly-slot="errors"`.
577
577
  - `orderly-checkout` persists checkout contact and address fields directly on `DraftOrder.Transport`, defaults the phone country picker to `+45`, validates email and phone values with built-in component logic, looks up Danish city names from the entered postal code through Dataforsyningen's `https://api.dataforsyningen.dk/postnumre/{postnr}` endpoint, loads delivery methods and service points, verifies the draft, and calls `OrderService.Create`.
578
- - `orderly-navigation` uses `NavigationController` and can be subclassed with site-specific `NavigationItem[]`. It is sticky by default, including when placed in `left`, `right`, or `primary-nav`; set `sticky="false"` to opt out. Use `layout="vertical"` for disclosure side navigation, `layout="horizontal"` for the tiered desktop bar, or `layout="burgermenu"` for an icon trigger that expands into the same nested disclosure menu inside a floating panel.
578
+ - `orderly-navigation` uses `NavigationController` and can be subclassed with site-specific `NavigationItem[]`. It is sticky by default, including when placed in `left`, `right`, or `primary-nav`; set `sticky="false"` to opt out. Use `layout="vertical"` for disclosure side navigation, `layout="horizontal"` for the tiered desktop bar, or `layout="burgermenu"` for an icon trigger that expands into the same nested disclosure menu inside a floating panel. Use `layout-desktop="horizontal" layout-mobile="burgermenu"` with `orderly-page-layout primary-nav-mobile-placement="header"` for desktop horizontal nav plus inline mobile burger.
579
579
  - `orderly-search-box`, `orderly-sort-select`, `orderly-filter-panel`, and `orderly-load-more` bind to `orderly-product-grid`.
580
580
 
581
+ ## Navigation Patterns
582
+
583
+ There are two different mobile navigation patterns:
584
+
585
+ - `layout="horizontal"` means the navigation owns its responsive fallback where it is placed. It renders the desktop horizontal category bar and automatically falls back to drawer-style mobile navigation on narrow viewports, but it does not move the trigger into the page header action row.
586
+ - `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.
587
+ - 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.
588
+
589
+ ```html
590
+ <orderly-page-layout primary-nav-mobile-placement="header">
591
+ <a slot="header" href="/">Shop name</a>
592
+ <orderly-search-box slot="header-actions" mode="icon"></orderly-search-box>
593
+ <orderly-basket-icon slot="header-actions"></orderly-basket-icon>
594
+ <orderly-navigation
595
+ slot="primary-nav"
596
+ layout-desktop="horizontal"
597
+ layout-mobile="burgermenu"
598
+ ></orderly-navigation>
599
+ <main slot="content">...</main>
600
+ </orderly-page-layout>
601
+ ```
602
+
581
603
  ## Rendering And Styling
582
604
 
583
605
  The package ships baseline default CSS and uses light DOM. Default markup uses stable `orderly-*` class names and CSS variables, so host CSS can style or replace the default look directly.
584
606
 
585
607
  For consistent theming across the whole package, start with the semantic design contract in [`DESIGN.md`](./DESIGN.md). In practice that means overriding `--orderly-color-primary`, `--orderly-color-primary-soft`, `--orderly-color-primary-contrast`, the `--orderly-action-primary-*` and `--orderly-action-secondary-*` tokens, plus shared tokens such as `--orderly-link-accent-color`, `--orderly-selection-*`, and `--orderly-badge-*`. `--orderly-color-accent` is kept as a compatibility alias, but new themes should treat `--orderly-color-primary` as the source of truth.
586
608
 
609
+ The package declares its fallback tokens with `:where(:root)`, which has zero selector specificity. If your shop sets tokens on `:root`, those values win even when `defineOrderlyWebComponents()` injects the package CSS after your stylesheet. You should not need to duplicate token overrides on `body` unless you intentionally want a scoped override.
610
+
587
611
  Example:
588
612
 
589
613
  ```css
@@ -652,7 +676,7 @@ Rendering can be replaced with templates:
652
676
 
653
677
  For dynamic paging, `orderly-product-grid` keeps the returned `PageResult.Continuation` as an opaque `ContinuationToken` and sends it as `SearchQuery.Continuation` when the sentinel enters the viewport. Dynamic and infinite paging do not render a load-more button. Use `paging="button"` only when a visible load-more button is desired, `paging="manual"` when another control calls `loadNextPage()`, and `paging="dynamic"` or `paging="infinite"` for automatic loading.
654
678
 
655
- 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 galleries use `data-orderly-slot="thumbnails"` and `data-orderly-action="select-image"` for custom thumbnail markup. 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`.
679
+ 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. 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`.
656
680
 
657
681
  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">`.
658
682
 
@@ -188,6 +188,7 @@ Use \`npm run generate:categories\` when you want to inspect generated source pa
188
188
  - \`src/includes/head.html\` calls \`configureShop(...)\`.
189
189
  - \`src/templates/*.html\` contains global component templates.
190
190
  - \`src/style.css\` owns the shop look and feel.
191
+ - The default page layout supports desktop horizontal navigation with an inline mobile burger through \`primary-nav-mobile-placement="header"\` plus \`orderly-navigation layout-desktop="horizontal" layout-mobile="burgermenu"\`.
191
192
  `;
192
193
  }
193
194
 
@@ -11,16 +11,22 @@
11
11
  "name": "OrderlyPageLayoutElement",
12
12
  "tagName": "orderly-page-layout",
13
13
  "customElement": true,
14
- "description": "Reusable storefront page structure with utility, header, navigation, sidebars, content, footer, and overlay regions.",
14
+ "description": "Reusable storefront page structure with utility, header, responsive primary navigation placement, sidebars, content, footer, and overlay regions.",
15
15
  "attributes": [
16
16
  { "name": "logo-src", "description": "Logo image URL." },
17
17
  { "name": "logo-alt", "description": "Logo alt text and logo link accessible label." },
18
- { "name": "logo-href", "description": "Logo link URL." }
18
+ { "name": "logo-href", "description": "Logo link URL." },
19
+ { "name": "primary-nav-placement", "description": "Default placement for the primary-nav slot: primary-nav, header, left, or right." },
20
+ { "name": "primary-nav-desktop-placement", "description": "Desktop placement override for the primary-nav slot." },
21
+ { "name": "primary-nav-mobile-placement", "description": "Mobile placement override for the primary-nav slot. Use header for an inline burger next to header actions." }
19
22
  ],
20
23
  "members": [
21
24
  { "kind": "field", "name": "logoSrc", "type": { "text": "string" } },
22
25
  { "kind": "field", "name": "logoAlt", "type": { "text": "string" } },
23
- { "kind": "field", "name": "logoHref", "type": { "text": "string" } }
26
+ { "kind": "field", "name": "logoHref", "type": { "text": "string" } },
27
+ { "kind": "field", "name": "primaryNavPlacement", "type": { "text": "PageLayoutPrimaryNavPlacement" } },
28
+ { "kind": "field", "name": "primaryNavDesktopPlacement", "type": { "text": "PageLayoutPrimaryNavPlacement" } },
29
+ { "kind": "field", "name": "primaryNavMobilePlacement", "type": { "text": "PageLayoutPrimaryNavPlacement" } }
24
30
  ],
25
31
  "slots": [
26
32
  { "name": "utility", "description": "Top utility strip." },
@@ -331,7 +337,7 @@
331
337
  "name": "OrderlyProductPageElement",
332
338
  "tagName": "orderly-product-page",
333
339
  "customElement": true,
334
- "description": "Product detail view with gallery thumbnails and add-to-basket behavior.",
340
+ "description": "Product detail view with gallery thumbnails, add-to-basket behavior, and product-page template bindings including basket-action aliases.",
335
341
  "attributes": [
336
342
  { "name": "add-label", "description": "Add-to-basket button label." }
337
343
  ],
@@ -456,15 +462,19 @@
456
462
  "name": "OrderlyNavigationMenuElement",
457
463
  "tagName": "orderly-navigation",
458
464
  "customElement": true,
459
- "description": "Navigation menu with vertical, horizontal, or burgermenu layouts, nested disclosure behavior, desktop tiered horizontal navigation support, horizontal overflow scrolling, projected inline content, and selection events.",
465
+ "description": "Navigation menu with vertical, horizontal, burgermenu, or responsive desktop/mobile layouts, nested disclosure behavior, desktop tiered horizontal navigation support, horizontal overflow scrolling, projected inline content, and selection events.",
460
466
  "attributes": [
461
467
  { "name": "layout", "description": "Navigation layout. Use vertical for a side menu, horizontal for a tiered desktop menu with a scrolling top row, full-width second row, and third-level dropdowns, or burgermenu for an icon trigger that opens a nested disclosure menu inside a floating panel." },
468
+ { "name": "layout-desktop", "description": "Desktop layout override. Use layout-desktop=\"horizontal\" with layout-mobile=\"burgermenu\" for the standard storefront desktop nav plus mobile header burger pattern." },
469
+ { "name": "layout-mobile", "description": "Mobile layout override. Use burgermenu for a compact icon button inside a mobile header." },
462
470
  { "name": "sticky", "description": "Set to false to opt out of sticky positioning." }
463
471
  ],
464
472
  "members": [
465
473
  { "kind": "field", "name": "items", "type": { "text": "NavigationItem[]" } },
466
474
  { "kind": "field", "name": "controller", "type": { "text": "NavigationController" } },
467
475
  { "kind": "field", "name": "layout", "type": { "text": "NavigationLayout" } },
476
+ { "kind": "field", "name": "layoutDesktop", "type": { "text": "NavigationLayout" } },
477
+ { "kind": "field", "name": "layoutMobile", "type": { "text": "NavigationLayout" } },
468
478
  { "kind": "field", "name": "sticky", "type": { "text": "boolean" } }
469
479
  ],
470
480
  "events": [