@propeller-commerce/propeller-v2-vue-ui 0.3.14

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.
Files changed (129) hide show
  1. package/CHANGELOG.md +549 -0
  2. package/LICENSE +21 -0
  3. package/MIGRATION.md +178 -0
  4. package/README.md +282 -0
  5. package/STYLING.md +119 -0
  6. package/dist/ProductVideos.vue_vue_type_script_setup_true_lang-BSXOpWBD.js +1706 -0
  7. package/dist/ProductVideos.vue_vue_type_script_setup_true_lang-BSXOpWBD.js.map +1 -0
  8. package/dist/ProductVideos.vue_vue_type_script_setup_true_lang-cfRT3L_k.cjs +1705 -0
  9. package/dist/ProductVideos.vue_vue_type_script_setup_true_lang-cfRT3L_k.cjs.map +1 -0
  10. package/dist/__mocks__/decorators.d.ts +17 -0
  11. package/dist/__mocks__/fixtures.d.ts +43 -0
  12. package/dist/__mocks__/mockServices.d.ts +7 -0
  13. package/dist/components/AccountIconAndMenu.vue.d.ts +152 -0
  14. package/dist/components/ActionCode.vue.d.ts +29 -0
  15. package/dist/components/AddToCart.vue.d.ts +122 -0
  16. package/dist/components/AddToFavorite.vue.d.ts +19 -0
  17. package/dist/components/AddressCard.vue.d.ts +169 -0
  18. package/dist/components/AddressSelector.vue.d.ts +30 -0
  19. package/dist/components/Breadcrumbs.vue.d.ts +69 -0
  20. package/dist/components/CartBonusItems.vue.d.ts +21 -0
  21. package/dist/components/CartCarriers.vue.d.ts +24 -0
  22. package/dist/components/CartIconAndSidebar.vue.d.ts +104 -0
  23. package/dist/components/CartItem.vue.d.ts +178 -0
  24. package/dist/components/CartOverview.vue.d.ts +41 -0
  25. package/dist/components/CartPaymethods.vue.d.ts +23 -0
  26. package/dist/components/CartSummary.vue.d.ts +58 -0
  27. package/dist/components/CategoryDescription.vue.d.ts +29 -0
  28. package/dist/components/CategoryShortDescription.vue.d.ts +18 -0
  29. package/dist/components/ClusterCard.vue.d.ts +251 -0
  30. package/dist/components/ClusterConfigurator.vue.d.ts +41 -0
  31. package/dist/components/ClusterInfo.vue.d.ts +73 -0
  32. package/dist/components/ClusterJsonLd.vue.d.ts +10 -0
  33. package/dist/components/ClusterOptions.vue.d.ts +44 -0
  34. package/dist/components/CompanySwitcher.vue.d.ts +18 -0
  35. package/dist/components/DeliveryDate.vue.d.ts +27 -0
  36. package/dist/components/FavoriteListDetails.vue.d.ts +94 -0
  37. package/dist/components/FavoriteListItem.vue.d.ts +141 -0
  38. package/dist/components/FavoriteLists.vue.d.ts +73 -0
  39. package/dist/components/ForgotPassword.vue.d.ts +35 -0
  40. package/dist/components/GridFilters.vue.d.ts +64 -0
  41. package/dist/components/GridPagination.vue.d.ts +34 -0
  42. package/dist/components/GridTitle.vue.d.ts +22 -0
  43. package/dist/components/GridToolbar.vue.d.ts +117 -0
  44. package/dist/components/ItemListJsonLd.vue.d.ts +10 -0
  45. package/dist/components/ItemStock.vue.d.ts +31 -0
  46. package/dist/components/ItemsOverview.vue.d.ts +40 -0
  47. package/dist/components/LoginForm.vue.d.ts +139 -0
  48. package/dist/components/Menu.vue.d.ts +73 -0
  49. package/dist/components/OrderActions.vue.d.ts +25 -0
  50. package/dist/components/OrderBonusItems.vue.d.ts +19 -0
  51. package/dist/components/OrderItemCard.vue.d.ts +47 -0
  52. package/dist/components/OrderList.vue.d.ts +66 -0
  53. package/dist/components/OrderShipments.vue.d.ts +11 -0
  54. package/dist/components/OrderSummary.vue.d.ts +49 -0
  55. package/dist/components/OrderTotals.vue.d.ts +34 -0
  56. package/dist/components/PriceToggle.vue.d.ts +24 -0
  57. package/dist/components/ProductBulkPrices.vue.d.ts +35 -0
  58. package/dist/components/ProductBundles.vue.d.ts +88 -0
  59. package/dist/components/ProductCard.vue.d.ts +332 -0
  60. package/dist/components/ProductDescription.vue.d.ts +30 -0
  61. package/dist/components/ProductDownloads.vue.d.ts +22 -0
  62. package/dist/components/ProductGallery.vue.d.ts +25 -0
  63. package/dist/components/ProductGrid.vue.d.ts +290 -0
  64. package/dist/components/ProductInfo.vue.d.ts +179 -0
  65. package/dist/components/ProductJsonLd.vue.d.ts +10 -0
  66. package/dist/components/ProductPrice.vue.d.ts +42 -0
  67. package/dist/components/ProductShortDescription.vue.d.ts +18 -0
  68. package/dist/components/ProductSlider.vue.d.ts +176 -0
  69. package/dist/components/ProductSpecifications.vue.d.ts +37 -0
  70. package/dist/components/ProductTabs.vue.d.ts +83 -0
  71. package/dist/components/ProductVideos.vue.d.ts +22 -0
  72. package/dist/components/PropellerProvider.vue.d.ts +40 -0
  73. package/dist/components/PurchaseAuthorizationConfigurator.vue.d.ts +44 -0
  74. package/dist/components/PurchaseAuthorizationRequests.vue.d.ts +50 -0
  75. package/dist/components/QuoteActions.vue.d.ts +22 -0
  76. package/dist/components/RegisterForm.vue.d.ts +87 -0
  77. package/dist/components/SearchBar.vue.d.ts +71 -0
  78. package/dist/components/UserDetails.vue.d.ts +44 -0
  79. package/dist/components/defaults/DefaultProductBadges.vue.d.ts +3 -0
  80. package/dist/components/defaults/DefaultProductImage.vue.d.ts +3 -0
  81. package/dist/components/defaults/DefaultProductSurcharges.vue.d.ts +3 -0
  82. package/dist/composables/shared/usePagination.d.ts +19 -0
  83. package/dist/composables/shared/useServiceFetch.d.ts +9 -0
  84. package/dist/composables/shared/useUserIdentity.d.ts +13 -0
  85. package/dist/composables/shared/utils/cartInit.d.ts +18 -0
  86. package/dist/composables/shared/utils/fetchActiveCart.d.ts +10 -0
  87. package/dist/composables/shared/utils/mergeAnonymousCart.d.ts +12 -0
  88. package/dist/composables/vue/useAddress.d.ts +50 -0
  89. package/dist/composables/vue/useAuth.d.ts +80 -0
  90. package/dist/composables/vue/useCart.d.ts +64 -0
  91. package/dist/composables/vue/useCheckout.d.ts +41 -0
  92. package/dist/composables/vue/useClusterConfigurator.d.ts +26 -0
  93. package/dist/composables/vue/useCompany.d.ts +31 -0
  94. package/dist/composables/vue/useFavorites.d.ts +39 -0
  95. package/dist/composables/vue/useInfraProps.d.ts +27 -0
  96. package/dist/composables/vue/useMenu.d.ts +24 -0
  97. package/dist/composables/vue/useOrders.d.ts +64 -0
  98. package/dist/composables/vue/useProductBundles.d.ts +37 -0
  99. package/dist/composables/vue/useProductInfo.d.ts +33 -0
  100. package/dist/composables/vue/useProductSearch.d.ts +49 -0
  101. package/dist/composables/vue/useProductSlider.d.ts +31 -0
  102. package/dist/composables/vue/useProductSpecs.d.ts +24 -0
  103. package/dist/composables/vue/usePurchaseAuthorization.d.ts +102 -0
  104. package/dist/composables/vue/useResolvedProps.d.ts +42 -0
  105. package/dist/composables/vue/useServices.d.ts +13 -0
  106. package/dist/context/ProductGridContext.d.ts +59 -0
  107. package/dist/context/PropellerContext.d.ts +51 -0
  108. package/dist/index-BN8nyGRL.js +518 -0
  109. package/dist/index-BN8nyGRL.js.map +1 -0
  110. package/dist/index-CrrZsxTR.cjs +517 -0
  111. package/dist/index-CrrZsxTR.cjs.map +1 -0
  112. package/dist/index.cjs +20086 -0
  113. package/dist/index.cjs.map +1 -0
  114. package/dist/index.d.ts +109 -0
  115. package/dist/index.js +20088 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/plugin.d.ts +67 -0
  118. package/dist/pure.cjs +16 -0
  119. package/dist/pure.cjs.map +1 -0
  120. package/dist/pure.d.ts +37 -0
  121. package/dist/pure.js +16 -0
  122. package/dist/pure.js.map +1 -0
  123. package/dist/shared.cjs +50 -0
  124. package/dist/shared.cjs.map +1 -0
  125. package/dist/shared.d.ts +14 -0
  126. package/dist/shared.js +50 -0
  127. package/dist/shared.js.map +1 -0
  128. package/dist/styles.css +2 -0
  129. package/package.json +91 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProductVideos.vue_vue_type_script_setup_true_lang-cfRT3L_k.cjs","sources":["../src/plugin.ts","../src/context/PropellerContext.ts","../src/composables/vue/useInfraProps.ts","../src/components/ProductPrice.vue","../src/components/Breadcrumbs.vue","../src/components/ItemStock.vue","../src/components/CategoryShortDescription.vue","../src/components/GridTitle.vue","../src/components/OrderItemCard.vue","../src/components/OrderSummary.vue","../src/components/OrderTotals.vue","../src/components/ProductBulkPrices.vue","../src/components/ProductDownloads.vue","../src/components/ProductShortDescription.vue","../src/components/ProductVideos.vue"],"sourcesContent":["import type { App, InjectionKey } from 'vue';\nimport { inject } from 'vue';\nimport type { GraphQLClient } from '@propeller-commerce/propeller-sdk-v2';\nimport type { Services } from '@propeller-commerce/propeller-v2-core-ui';\n\n/**\n * Tier 1 — application-wide infrastructure. Installed once at app startup via\n * `app.use(propellerVue, { … })`. These values are app-singletons: the\n * GraphQL client, the SDK Services bundle wired to it, and the cosmetic /\n * branding defaults (currency, configuration). They do not change per\n * subtree — for per-scope state (user, companyId, language) use\n * `<PropellerProvider>` instead.\n */\nexport interface PropellerDeps {\n /**\n * The GraphQL client the consumer constructed. Exposed for code that needs\n * to pass it back into SDK helpers (rare — most code should use `services`).\n */\n graphqlClient: GraphQLClient;\n /**\n * The Services bundle (`{ product, cart, user, ... }`) wired to\n * `graphqlClient`. Build it via `createServices(graphqlClient)`.\n */\n services: Services;\n /**\n * Currency symbol used by display components when formatting prices.\n * Default: `'€'`.\n */\n currency: string;\n /**\n * Free-form configuration bag forwarded to components — kept as `unknown`\n * so consumers can stuff extra config in without changing this interface.\n */\n configuration: unknown;\n}\n\n/** Symbol-keyed so it never collides with a consumer's own provide/inject. */\nexport const PropellerDepsKey: InjectionKey<PropellerDeps> =\n Symbol('propeller-deps');\n\nexport interface PropellerVuePluginOptions extends PropellerDeps {}\n\n/**\n * Vue plugin: install the Propeller infrastructure singletons app-wide.\n *\n * Call once at startup, before mount:\n *\n * @example\n * import { propellerVue, createServices } from 'propeller-v2-vue-ui';\n * import { GraphQLClient } from '@propeller-commerce/propeller-sdk-v2';\n *\n * const graphqlClient = new GraphQLClient({ endpoint: '/api/graphql' });\n * app.use(propellerVue, {\n * graphqlClient,\n * services: createServices(graphqlClient),\n * currency: '€',\n * configuration: myConfig,\n * });\n *\n * Then wrap the routed tree with `<PropellerProvider>` to bind the per-scope\n * state (user / companyId / language / includeTax / portalMode).\n */\nexport const propellerVue = {\n install(app: App, options: PropellerVuePluginOptions) {\n if (!options || !options.graphqlClient || !options.services) {\n throw new Error(\n '[propeller-v2-vue-ui] propellerVue plugin requires { graphqlClient, services, currency, configuration }. ' +\n 'Build services once via `createServices(graphqlClient)` and pass both in.'\n );\n }\n app.provide(PropellerDepsKey, {\n graphqlClient: options.graphqlClient,\n services: options.services,\n currency: options.currency ?? '€',\n configuration: options.configuration,\n });\n },\n};\n\n/**\n * Read the installed Propeller deps. Throws when the plugin wasn't installed —\n * that's an integration error the consumer fixes at app startup.\n */\nexport function usePropellerDeps(): PropellerDeps {\n const deps = inject(PropellerDepsKey, null);\n if (!deps) {\n throw new Error(\n '[propeller-v2-vue-ui] usePropellerDeps() called without the plugin. ' +\n 'Add `app.use(propellerVue, { graphqlClient, services, currency, configuration })` at startup.'\n );\n }\n return deps;\n}\n\n/** Non-throwing variant — useful for standalone / story rendering. */\nexport function tryUsePropellerDeps(): PropellerDeps | null {\n return inject(PropellerDepsKey, null);\n}\n","import { inject, type InjectionKey } from 'vue';\nimport type { Contact, Customer } from '@propeller-commerce/propeller-sdk-v2';\nimport type { ShopMode, UserMode } from '@propeller-commerce/propeller-v2-core-ui';\nimport { deriveUserMode } from '@propeller-commerce/propeller-v2-core-ui';\nimport {\n type PropellerDeps,\n usePropellerDeps,\n tryUsePropellerDeps,\n} from '../plugin';\n\n/**\n * Tier 2 — per-scope state. Bound by `<PropellerProvider>` and replaceable\n * by nesting a second provider deeper in the tree (for impersonation,\n * multi-cart, multi-language widgets, …). Distinct from the Tier 1 deps\n * installed by the `propellerVue` plugin.\n */\nexport interface PropellerScope {\n user: Contact | Customer | null;\n companyId: number | undefined;\n language: string;\n includeTax: boolean;\n portalMode: string;\n /**\n * Shop mode declared in `propeller.json`. Combined with `user` to derive\n * `userMode` on the composite context. Defaults to `'hybrid'` when omitted\n * so existing call sites keep their current branching semantics.\n */\n shopMode?: ShopMode;\n}\n\n/** Symbol-keyed scope injection — never collides with consumer keys. */\nexport const PropellerScopeKey: InjectionKey<PropellerScope> =\n Symbol('propeller-scope');\n\n/**\n * Composite read of Tier 1 deps + Tier 2 scope. Mirrors the previous\n * `PropellerInfra` shape so existing consumers (cards, useResolvedProps,\n * useInfraProps) keep working unchanged.\n *\n * Composables that only need services should call `useServices()` /\n * `usePropellerDeps()` instead — they don't depend on a scope provider.\n */\nexport interface PropellerInfra extends PropellerDeps, PropellerScope {\n userMode: UserMode;\n}\n\n/**\n * Build a live composite of Tier 1 deps + Tier 2 scope. The returned object\n * exposes scope/userMode reads as getters that pierce through to the\n * underlying reactive scope — so callers that cache this object at setup\n * (e.g. `useInfraProps`) still see live updates when the provider's props\n * change (login, language switch, VAT toggle). Spreading `scope` would\n * snapshot the values at call time and break that reactivity.\n */\nfunction buildInfra(deps: PropellerDeps, scope: PropellerScope): PropellerInfra {\n return {\n ...deps,\n get user() {\n return scope.user;\n },\n get companyId() {\n return scope.companyId;\n },\n get language() {\n return scope.language;\n },\n get includeTax() {\n return scope.includeTax;\n },\n get portalMode() {\n return scope.portalMode;\n },\n get shopMode() {\n return scope.shopMode;\n },\n get userMode() {\n return deriveUserMode(scope.user, scope.shopMode ?? 'hybrid');\n },\n } as PropellerInfra;\n}\n\n/**\n * Non-throwing accessor: returns `null` if either tier is missing so\n * components stay usable standalone / in tests.\n */\nexport function usePropellerContext(): PropellerInfra | null {\n const deps = tryUsePropellerDeps();\n const scope = inject(PropellerScopeKey, null);\n if (!deps || !scope) return null;\n return buildInfra(deps, scope);\n}\n\n/**\n * Throwing accessor — call when both tiers are required and a missing\n * provider is an integration bug, not a render-standalone scenario.\n */\nexport function useRequiredPropellerContext(): PropellerInfra {\n const deps = usePropellerDeps();\n const scope = inject(PropellerScopeKey, null);\n if (!scope) {\n throw new Error(\n '[propeller-v2-vue-ui] useRequiredPropellerContext() called outside ' +\n 'a <PropellerProvider>. Wrap your routed tree with ' +\n '<PropellerProvider :user :companyId :language :includeTax :portalMode>.'\n );\n }\n return buildInfra(deps, scope);\n}\n\n/**\n * Read the active `userMode` directly. Returns `'anonymous'` outside the\n * provider so components stay usable standalone / in tests.\n */\nexport function useUserMode(): UserMode {\n const scope = inject(PropellerScopeKey, null);\n if (!scope) return 'anonymous';\n return deriveUserMode(scope.user, scope.shopMode ?? 'hybrid');\n}\n","import { reactive } from 'vue';\nimport { usePropellerContext, type PropellerInfra } from '../../context/PropellerContext';\n\ntype InfraKey = keyof PropellerInfra;\n\nconst INFRA_KEYS: InfraKey[] = [\n 'graphqlClient',\n 'services',\n 'user',\n 'companyId',\n 'language',\n 'includeTax',\n 'currency',\n 'configuration',\n 'portalMode',\n];\n\n/**\n * Resolves the Tier 1 (deps) + Tier 2 (scope) infrastructure props for a\n * component.\n *\n * Precedence: an explicit prop value (defined and non-null) always wins —\n * existing call sites keep working unchanged. Otherwise the value is taken\n * from the composite of plugin deps and `<PropellerProvider>` scope. Non-infra\n * props pass through untouched.\n *\n * Null-context safe: with no plugin or no provider the props are returned\n * as-is, so components still work standalone / in tests.\n *\n * MUST be called from `setup()` — Vue's `inject()` only works there. Calling\n * this lazily from inside a `computed` getter, an effect, or a click handler\n * yields `null` for the provider context (and a console warning), which is\n * what the previous \"wrap in computed\" pattern caused for any prop that hadn't\n * been read synchronously during setup.\n *\n * The returned object is a `reactive` proxy whose infra-key reads always\n * reflect (explicit prop OR provider snapshot OR undefined). Non-infra props\n * pass through unchanged via getter forwarding, so consumers can iterate or\n * destructure it as they would a plain object.\n */\nexport function useInfraProps<P extends Partial<Record<InfraKey, unknown>>>(\n props: P\n): P & Partial<PropellerInfra> {\n // Resolve once at setup — inject() is only valid here.\n const ctx = usePropellerContext();\n\n const merged: Record<string, unknown> = {};\n // Forward every non-infra key as a getter so reads on the returned object\n // pick up reactive prop updates without us having to enumerate them.\n for (const key of Object.keys(props as Record<string, unknown>)) {\n if (INFRA_KEYS.includes(key as InfraKey)) continue;\n Object.defineProperty(merged, key, {\n enumerable: true,\n configurable: true,\n get() {\n return (props as Record<string, unknown>)[key];\n },\n });\n }\n // Each infra key reads the live prop first, then falls back to the snapshot\n // ctx captured during setup. Provider mutations are still reactive because\n // `ctx` is a `reactive` object on the PropellerProvider side.\n for (const key of INFRA_KEYS) {\n Object.defineProperty(merged, key, {\n enumerable: true,\n configurable: true,\n get() {\n const explicit = (props as Record<string, unknown>)[key];\n if (explicit !== undefined && explicit !== null) return explicit;\n return ctx ? (ctx as unknown as Record<string, unknown>)[key] : undefined;\n },\n });\n }\n return reactive(merged) as unknown as P & Partial<PropellerInfra>;\n}\n","<template>\n <div\n :class=\"`propeller-product-price ${className || ''}`\"\n :data-hidden=\"isHidden() ? 'true' : 'false'\"\n >\n <template v-if=\"isHidden()\">\n <p\n class=\"propeller-product-price__login-prompt text-sm text-muted-foreground italic\"\n >\n {{ getLabel(\"loginToSeePrices\", \"Log in to see prices\") }}\n </p>\n </template>\n\n <template v-if=\"!isHidden() && !!getLeadingPrice()\">\n <div class=\"propeller-product-price__content flex flex-col gap-0.5\">\n <div class=\"propeller-product-price__primary flex items-baseline gap-2\">\n <span\n :class=\"`propeller-product-price__amount ${priceSize || 'text-3xl'} font-bold text-foreground`\"\n >{{ getLeadingPrice() }}</span\n ><span\n class=\"propeller-product-price__tax-label text-sm text-muted-foreground\"\n >{{ getTaxLabel() }}</span\n >\n </div>\n <template v-if=\"!!getSecondaryPrice()\">\n <div\n class=\"propeller-product-price__secondary text-sm text-muted-foreground flex items-baseline gap-1\"\n >\n <span class=\"propeller-product-price-secondary__amount\">{{\n getSecondaryPrice()\n }}</span>\n <span class=\"propeller-product-price-secondary__tax-label\">{{\n getSecondaryTaxLabel()\n }}</span>\n </div>\n </template>\n </div>\n </template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ClusterOption, Contact, Customer, Product, ProductPrice, YesNo } from \"@propeller-commerce/propeller-sdk-v2\";\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport { isContentHidden as _isContentHidden } from '@propeller-commerce/propeller-v2-core-ui';\nimport { formatPrice as _formatPrice } from '@propeller-commerce/propeller-v2-core-ui';\n\nexport interface ProductPriceProps {\n /**\n * ProductPrice object from the product.\n * Obtain from `product.price`.\n */\n price: ProductPrice;\n\n /** Currency symbol to display. Defaults to '€'. */\n currency?: string;\n\n /**\n * Controls portal visibility mode.\n * 'open' — full e-commerce; price is always visible.\n * 'semi-closed' — catalog-only; price is hidden for anonymous users.\n * Defaults to 'open'.\n */\n portalMode?: string;\n\n /** Authenticated user — used for semi-closed visibility. */\n user?: Contact | Customer | null;\n\n /**\n * When true, net price (incl. tax) is the leading price.\n * When false (default), gross price (excl. tax) is the leading price.\n * Note: in the Propeller SDK `price.gross` = excl. VAT, `price.net` = incl. VAT.\n */\n includeTax?: boolean;\n\n /** Tax zone code. Defaults to 'NL'. */\n taxZone?: string;\n\n /** Cluster options (cluster.options). Required option default prices are added even without an active selection. */\n options?: ClusterOption[];\n\n /** Active option product selections — pass Object.values(selectedOptionProducts). Price updates on every change. */\n selectedOptionProducts?: Product[];\n\n /**\n * Override any UI string.\n * Available keys: inclTax, exclTax, loginToSeePrices\n */\n labels?: Record<string, string>;\n\n /** Tailwind text-size class for the leading price. Defaults to 'text-3xl'. */\n priceSize?: string;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\ninterface ProductPriceState {\n isHidden: () => boolean;\n getOptionsTotal: (useNet: boolean) => number;\n getLeadingPrice: () => string;\n getSecondaryPrice: () => string;\n getTaxLabel: () => string;\n getSecondaryTaxLabel: () => string;\n getLabel: (key: string, fallback: string) => string;\n formatPrice: (value: number | null | undefined) => string;\n}\n\nconst props = defineProps<ProductPriceProps>();\n\nfunction isHidden(): ReturnType<ProductPriceState[\"isHidden\"]> {\n return _isContentHidden(props.portalMode, props.user);\n}\nfunction formatPrice(\n value: number | null | undefined,\n): ReturnType<ProductPriceState[\"formatPrice\"]> {\n return _formatPrice(value, { symbol: props.currency || \"\\u20AC\" });\n}\nfunction getOptionsTotal(\n useNet: boolean,\n): ReturnType<ProductPriceState[\"getOptionsTotal\"]> {\n const options = (props.options as ClusterOption[]) || [];\n const selected = (props.selectedOptionProducts as Product[]) || [];\n let total = 0;\n options.forEach((option: ClusterOption) => {\n if (option.hidden === YesNo.Y) return;\n\n // Find whether the user has selected a product in this option\n const selectedProduct = selected.find((p: Product) =>\n (option.products || []).some(\n (op: Product) => op.productId === p.productId,\n ),\n );\n if (selectedProduct) {\n total += useNet\n ? selectedProduct.price?.net || 0\n : selectedProduct.price?.gross || 0;\n } else if (option.isRequired === YesNo.Y && option.defaultProduct) {\n // option.defaultProduct may lack price data; look up the full\n // product record from option.products (which always has prices).\n const defaultId = (option.defaultProduct as Product).productId;\n const fullDefault =\n (option.products || []).find(\n (p: Product) => p.productId === defaultId,\n ) || option.defaultProduct;\n total += useNet\n ? (fullDefault as Product).price?.net || 0\n : (fullDefault as Product).price?.gross || 0;\n }\n });\n return total;\n}\nfunction getLeadingPrice(): ReturnType<ProductPriceState[\"getLeadingPrice\"]> {\n const price = props.price as ProductPrice;\n if (!price) return \"\";\n const useNet = !!props.includeTax;\n const base = useNet ? price.net : price.gross;\n if (base === null || base === undefined) return \"\";\n return formatPrice(base + getOptionsTotal(useNet));\n}\nfunction getSecondaryPrice(): ReturnType<\n ProductPriceState[\"getSecondaryPrice\"]\n> {\n const price = props.price as ProductPrice;\n if (!price) return \"\";\n const useNet = !props.includeTax; // opposite of leading\n const base = useNet ? price.net : price.gross;\n if (base === null || base === undefined) return \"\";\n return formatPrice(base + getOptionsTotal(useNet));\n}\nfunction getTaxLabel(): ReturnType<ProductPriceState[\"getTaxLabel\"]> {\n return props.includeTax\n ? getLabel(\"inclTax\", \"incl. VAT\")\n : getLabel(\"exclTax\", \"excl. VAT\");\n}\nfunction getSecondaryTaxLabel(): ReturnType<\n ProductPriceState[\"getSecondaryTaxLabel\"]\n> {\n return props.includeTax\n ? getLabel(\"exclTax\", \"excl. VAT\")\n : getLabel(\"inclTax\", \"incl. VAT\");\n}\nfunction getLabel(\n key: string,\n fallback: string,\n): ReturnType<ProductPriceState[\"getLabel\"]> {\n return _getLabel(props.labels, key, fallback);\n}\n</script>\n","<template>\n <nav :aria-label='getLabel(\"breadcrumbAriaLabel\", \"Breadcrumb\")' :class=\"`propeller-breadcrumbs ${className || ''}`\">\n <ol class=\"propeller-breadcrumbs__list flex flex-wrap items-center text-sm text-muted-foreground\">\n <template v-if=\"showHome !== false\">\n <li class=\"propeller-breadcrumbs__item flex items-center\" data-home=\"true\">\n <a class=\"propeller-breadcrumbs__link hover:text-foreground transition-colors\" :href=\"homeUrl || '/'\">{{\n getLabel('home', 'Home')\n }}</a>\n </li>\n </template>\n\n <li\n v-for=\"(cat, index) in getDisplayItems()\"\n :key=\"cat.categoryId || index\"\n class=\"propeller-breadcrumbs__item flex items-center\"\n :data-current=\"isCurrentItem(index) ? 'true' : 'false'\"\n >\n <span\n v-if=\"showSeparatorBefore(index)\"\n aria-hidden=\"true\"\n class=\"propeller-breadcrumbs__separator mx-2 select-none text-muted-foreground/40\"\n >{{ getLabel('separator', '/') }}</span\n >\n\n <span\n v-if=\"isCurrentItem(index)\"\n aria-current=\"page\"\n class=\"propeller-breadcrumbs__link propeller-breadcrumbs__link--current text-foreground\"\n >{{ getCategoryName(cat) }}</span\n >\n\n <a\n v-else\n class=\"propeller-breadcrumbs__link hover:text-foreground transition-colors\"\n :href=\"getCategoryUrl(cat, index)\"\n >{{ getCategoryName(cat) }}</a\n >\n </li>\n\n <template v-if=\"!!currentLabel\">\n <li\n class=\"propeller-breadcrumbs__item flex items-center\"\n data-current=\"true\"\n >\n <span aria-hidden=\"true\" class=\"propeller-breadcrumbs__separator mx-2 select-none text-muted-foreground/40\">{{\n getLabel('separator', '/')\n }}</span>\n <template v-if=\"!!currentUrl\">\n <a\n aria-current=\"page\"\n class=\"propeller-breadcrumbs__link propeller-breadcrumbs__link--current text-foreground\"\n :href=\"currentUrl\"\n >{{ currentLabel }}</a\n >\n </template>\n <template v-if=\"!currentUrl\">\n <span\n aria-current=\"page\"\n class=\"propeller-breadcrumbs__link propeller-breadcrumbs__link--current text-foreground\"\n >{{ currentLabel }}</span\n >\n </template>\n </li>\n </template>\n </ol>\n </nav>\n</template>\n\n<script setup lang=\"ts\">\nimport { Category, LocalizedString } from '@propeller-commerce/propeller-sdk-v2';\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport { getLanguageString, getLanguageUri } from '@propeller-commerce/propeller-v2-core-ui';\n\nexport interface BreadcrumbsProps {\n /**\n * The category path from the category, product or cluster response.\n * Obtain from `category.categoryPath` or `product.category.categoryPath`.\n */\n categoryPath: Category[];\n\n /**\n * When true (default), the last item in the path is displayed as the\n * current page (non-clickable, aria-current=\"page\").\n * When false, the last item is omitted.\n * Ignored when `currentLabel` is provided — the extra crumb becomes\n * the current page instead.\n */\n showCurrent?: boolean;\n\n /**\n * The category of the current page. When provided and not already\n * the last item in `categoryPath`, it is appended automatically so\n * the trail always ends at the current category. This makes the\n * component correct whether the API's categoryPath includes the\n * current category or only its ancestors.\n */\n currentCategory?: Category;\n\n /**\n * Optional trailing crumb appended after the category path — typically\n * the name of the current product or cluster on a detail page.\n * When provided, this crumb is marked as the current page and the\n * last category becomes a normal link.\n */\n currentLabel?: string;\n\n /**\n * Optional URL for the trailing `currentLabel` crumb. When omitted,\n * the crumb is rendered as a non-link `<span>`.\n */\n currentUrl?: string;\n\n /**\n * When true (default), a \"Home\" link is prepended to the trail.\n */\n showHome?: boolean;\n\n /**\n * URL for the Home link. Defaults to '/'.\n */\n homeUrl?: string;\n\n /**\n * Language code used to resolve localised category names and slugs.\n * Defaults to 'NL'.\n */\n language?: string;\n\n /**\n * Custom URL builder for category links.\n * Receives the Category object and its zero-based index in the path.\n * When omitted, URLs default to `/category/{categoryId}/{slug}`.\n */\n getUrl?: (category: Category, index: number) => string;\n\n /**\n * Override any UI string.\n * Available keys: home, separator\n */\n labels?: Record<string, string>;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n\n /** Configuration object passed to the component */\n configuration?: any;\n}\ninterface BreadcrumbsState {\n getItems: () => Category[];\n getDisplayItems: () => Category[];\n getCategoryName: (cat: Category) => string;\n getCategorySlug: (cat: Category) => string;\n getCategoryUrl: (cat: Category, index: number) => string;\n isCurrentItem: (index: number) => boolean;\n showSeparatorBefore: (index: number) => boolean;\n getLabel: (key: string, fallback: string) => string;\n}\n\nconst props = withDefaults(defineProps<BreadcrumbsProps>(), {\n showHome: true,\n showCurrent: true,\n});\n\nfunction getItems(): ReturnType<BreadcrumbsState['getItems']> {\n const path = (props.categoryPath as Category[]) || [];\n const baseId = props.configuration?.baseCategoryId;\n const filtered = baseId\n ? path.filter((cat: Category) => cat.categoryId !== baseId)\n : path;\n const current = props.currentCategory;\n if (current) {\n const last = filtered[filtered.length - 1];\n if (!last || last.categoryId !== current.categoryId) {\n return [...filtered, current];\n }\n }\n return filtered;\n}\nfunction getDisplayItems(): ReturnType<BreadcrumbsState['getDisplayItems']> {\n const items = getItems();\n if (props.showCurrent === false && items.length > 0) {\n return items.slice(0, items.length - 1);\n }\n return items;\n}\nfunction getCategoryName(cat: Category): ReturnType<BreadcrumbsState['getCategoryName']> {\n return getLanguageString(cat.name, props.language || 'NL', '');\n}\nfunction getCategorySlug(cat: Category): ReturnType<BreadcrumbsState['getCategorySlug']> {\n return getLanguageString(cat.slug, props.language || 'NL', '');\n}\nfunction getCategoryUrl(\n cat: Category,\n index: number\n): ReturnType<BreadcrumbsState['getCategoryUrl']> {\n if (props.getUrl) {\n return (props.getUrl as (cat: Category, index: number) => string)(cat, index);\n }\n // Consumer-provided URL builder takes precedence. Fall back to the\n // configuration helper when present (legacy boilerplate pattern), then\n // to the documented default `/category/{categoryId}/{slug}` URL.\n // Reading configuration.urls.getCategoryUrl unconditionally crashed pages\n // that don't thread `configuration` into Breadcrumbs.\n //\n // The helper is invoked as a method (not via an extracted reference) so\n // that `this` is still bound to `configuration.urls` — some boilerplates\n // write it as `getCategoryUrl(...) { return ...this.pattern... }` and\n // detaching the reference crashes with \"Cannot read properties of\n // undefined (reading 'pattern')\".\n const urls = props.configuration?.urls;\n if (urls && typeof urls.getCategoryUrl === 'function') {\n return urls.getCategoryUrl(cat, props.language);\n }\n const slug = getLanguageString(cat.slug, props.language || 'NL', '');\n return `/category/${cat.categoryId}/${slug}`;\n}\nfunction isCurrentItem(index: number): ReturnType<BreadcrumbsState['isCurrentItem']> {\n if (props.showCurrent === false) return false;\n if (props.currentLabel) return false;\n return index === getDisplayItems().length - 1;\n}\nfunction showSeparatorBefore(index: number): ReturnType<BreadcrumbsState['showSeparatorBefore']> {\n // Show separator when Home precedes this item, or when a previous category item exists.\n return props.showHome !== false || index > 0;\n}\nfunction getLabel(key: string, fallback: string): ReturnType<BreadcrumbsState['getLabel']> {\n return _getLabel(props.labels, key, fallback);\n}\n</script>\n","<template>\n <template v-if=\"hasInventory()\">\n <div\n :class=\"`propeller-item-stock flex flex-wrap items-center gap-1.5 ${className || ''}`\"\n :data-available=\"isAvailable() ? 'true' : 'false'\"\n :data-stock=\"getStockStatusData()\"\n >\n <template v-if=\"showAvailability !== false\">\n <span\n :class=\"`propeller-item-stock__availability inline-flex items-center gap-1 whitespace-nowrap rounded-full border px-2 py-0.5 text-[11px] font-medium ${getAvailabilityClass()}`\"\n ><span\n :class=\"`propeller-item-stock__availability-dot h-1.5 w-1.5 flex-shrink-0 rounded-full ${getAvailabilityDotClass()}`\"\n ></span\n >{{ getAvailabilityLabel() }}</span\n >\n </template>\n\n <template v-if=\"showStock !== false && !!getStockStatusLabel()\">\n <span\n :class=\"`propeller-item-stock__status inline-flex items-center gap-1 whitespace-nowrap rounded-full border px-2 py-0.5 text-[11px] font-medium ${getStockStatusClass()}`\"\n >{{ getStockStatusLabel() }}\n <template v-if=\"getTotalQuantity() > 0\">\n <span class=\"propeller-item-stock__count opacity-70\">\n ({{ getTotalQuantity() }}{{ getLabel('pieces', 'pcs') }})\n </span>\n </template>\n </span>\n </template>\n </div>\n </template>\n</template>\n\n<script setup lang=\"ts\">\nimport { ProductInventory } from '@propeller-commerce/propeller-sdk-v2';\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\n\nexport interface ItemStockProps {\n /**\n * Product inventory to display stock and availability for.\n * May be undefined when the product carries no inventory record — the\n * component then renders its unknown-stock state.\n */\n inventory?: ProductInventory;\n\n /**\n * Shows whether the product is available or not available.\n * Defaults to true.\n */\n showAvailability?: boolean;\n\n /**\n * Shows the actual stock quantity (`inventory.totalQuantity`).\n * Defaults to true.\n */\n showStock?: boolean;\n\n /**\n * UI string overrides.\n * Available keys: inStock, outOfStock, lowStock, available, notAvailable, pieces\n */\n labels?: Record<string, string>;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\n\nconst props = withDefaults(defineProps<ItemStockProps>(), {\n showAvailability: true,\n showStock: true,\n});\n\nfunction getLabel(key: string, fallback: string): string {\n return _getLabel(props.labels, key, fallback);\n}\nfunction getTotalQuantity(): number {\n const qty = (props.inventory as ProductInventory)?.totalQuantity;\n return qty !== undefined && qty !== null ? qty : -1;\n}\nfunction isAvailable(): boolean {\n return getTotalQuantity() > 0;\n}\nfunction getStockStatusLabel(): string {\n const qty = getTotalQuantity();\n if (qty < 0) return '';\n if (qty === 0) return getLabel('outOfStock', 'Out of stock');\n if (qty <= 5) return getLabel('lowStock', 'Low stock');\n return getLabel('inStock', 'In stock');\n}\nfunction getStockStatusClass(): string {\n const qty = getTotalQuantity();\n if (qty <= 0) return 'text-destructive bg-destructive/10 border-destructive';\n if (qty <= 5) return 'text-warning bg-warning/10 border-warning';\n return 'text-success bg-success/10 border-success';\n}\nfunction getStockStatusData(): string {\n const qty = getTotalQuantity();\n if (qty <= 0) return 'out';\n if (qty <= 5) return 'low';\n return 'in';\n}\nfunction getAvailabilityLabel(): string {\n return isAvailable()\n ? getLabel('available', 'Available')\n : getLabel('notAvailable', 'Not available');\n}\nfunction getAvailabilityClass(): string {\n return isAvailable()\n ? 'text-success bg-success/10 border-success'\n : 'text-destructive bg-destructive/10 border-destructive';\n}\nfunction getAvailabilityDotClass(): string {\n return isAvailable() ? 'bg-success' : 'bg-destructive';\n}\nfunction hasInventory(): boolean {\n return !!(props.inventory as ProductInventory) && getTotalQuantity() >= 0;\n}\n</script>\n","<template>\n <template v-if=\"!!html\">\n <div :class=\"`propeller-category-short-description mb-6 ${className || ''}`\">\n <div\n class=\"propeller-category-short-description__content prose prose-slate max-w-none text-muted-foreground\"\n v-html=\"html\"\n ></div>\n </div>\n </template>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from \"vue\";\n\nimport type { Category } from '@propeller-commerce/propeller-sdk-v2';\nimport { getLanguageString } from '@propeller-commerce/propeller-v2-core-ui';\nimport { useInfraProps } from '../composables/vue/useInfraProps';\n\nexport interface CategoryShortDescriptionProps {\n // ── Required ────────────────────────────────────────────────────────────\n\n /**\n * Language code used to resolve the correct localised short description\n * from `category.shortDescription`.\n */\n language: string;\n\n // ── Optional ────────────────────────────────────────────────────────────\n\n /**\n * Propeller Category object.\n * The component reads `category.shortDescription` (an array of LocalizedString)\n * and renders the matching language entry as HTML.\n */\n category?: Category;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\ninterface CategoryShortDescriptionState {\n html: string;\n}\n\nconst props = defineProps<CategoryShortDescriptionProps>();\nconst infra = useInfraProps(props);\n\nconst html = computed(() => {\n return getLanguageString(props.category?.shortDescription, infra.language || 'NL', '');\n});\n</script>\n","<template>\n <div :class=\"`propeller-grid-title mb-8 ${className || ''}`\">\n <div class=\"propeller-grid-title__row flex items-baseline gap-3 mb-3\">\n <template v-if=\"headingLevel === 'h2'\">\n <h2 class=\"propeller-grid-title__heading text-3xl sm:text-4xl font-bold tracking-tight\">\n {{ title }}\n </h2>\n </template>\n\n <template v-if=\"headingLevel !== 'h2'\">\n <h1 class=\"propeller-grid-title__heading text-3xl sm:text-4xl font-bold tracking-tight\">\n {{ title }}\n </h1>\n </template>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nexport interface GridTitleProps {\n // ── Required ────────────────────────────────────────────────────────────\n\n /**\n * The main heading text to display.\n * Typically the category name, search term, or brand name.\n */\n title: string;\n\n /**\n * Language code for the content.\n * Defaults to 'NL'.\n */\n language: string;\n\n // ── Optional ────────────────────────────────────────────────────────────\n\n /**\n * Override the heading tag level.\n * Defaults to 'h1'. Use 'h2' when the grid is embedded inside\n * a page that already has an h1.\n */\n headingLevel?: string;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\n\nconst props = defineProps<GridTitleProps>();\n</script>\n","<template>\n <tbody class=\"propeller-order-item-card\">\n <tr\n :class=\"`propeller-order-item-card__row ${isChildItem ? 'border-0' : 'hover:bg-surface-hover transition'}`\"\n :data-child=\"isChildItem ? 'true' : 'false'\"\n >\n <td\n :class=\"`propeller-order-item-card__cell propeller-order-item-card__cell--product ${isChildItem ? 'px-6 py-2 pl-28' : 'px-6 py-4'}`\"\n >\n <div class=\"flex items-center gap-4\">\n <template v-if=\"showImage\">\n <template v-if=\"productImage\">\n <div\n class=\"propeller-order-item-card__media relative w-16 h-16 flex-shrink-0 rounded overflow-hidden\"\n >\n <img\n class=\"propeller-order-item-card__image object-cover w-full h-full\"\n :src=\"productImage\"\n :alt=\"productName\"\n />\n </div>\n </template>\n\n <template v-if=\"!productImage\">\n <div\n class=\"propeller-order-item-card__image-placeholder w-16 h-16 bg-surface-hover rounded flex items-center justify-center text-foreground-subtle text-xs\"\n >\n {{ getLabel('noImage', 'No Img') }}\n </div>\n </template>\n </template>\n\n <div>\n <template v-if=\"titleLinkable && productUrl && !isChildItem\">\n <a\n class=\"propeller-order-item-card__title font-medium text-foreground hover:text-primary hover:underline\"\n :href=\"productUrl\"\n >{{ productName }}</a\n >\n </template>\n\n <template v-if=\"!titleLinkable || !productUrl || isChildItem\">\n <span\n :class=\"`propeller-order-item-card__title ${isChildItem ? 'text-sm text-muted-foreground' : 'font-medium'}`\"\n >{{ productName }}</span\n >\n </template>\n\n <template v-if=\"showSku && productSku\">\n <p\n class=\"propeller-order-item-card__sku text-sm text-muted-foreground mt-1\"\n >\n SKU: {{ productSku }}\n </p>\n </template>\n\n <template v-if=\"showItemNotes && notes\">\n <p\n class=\"propeller-order-item-card__notes text-sm text-foreground-subtle mt-1 italic\"\n >\n {{ notes }}\n </p>\n </template>\n\n <!-- Delegate to the injected stock slot, or fall back to the\n default stock display. Replaces the prior literal \"Stock info\"\n placeholder text. The `inventory` guard bridges the\n contract-vs-default mismatch: shared StockComponentProps.inventory\n is optional while DefaultItemStock requires it, so we only\n render when the SDK actually returned inventory data. -->\n <component\n v-if=\"showStockComponent !== false && orderItem?.product?.inventory\"\n :is=\"StockImpl\"\n :inventory=\"orderItem.product.inventory\"\n :show-stock=\"true\"\n :show-availability=\"true\"\n :labels=\"labels\"\n />\n </div>\n </div>\n </td>\n <template v-if=\"showQuantity\">\n <td\n :class=\"\n isChildItem\n ? 'propeller-order-item-card__cell propeller-order-item-card__cell--quantity px-6 py-2 text-center text-sm text-muted-foreground'\n : 'propeller-order-item-card__cell propeller-order-item-card__cell--quantity px-6 py-4 text-center'\n \"\n >\n {{ quantity }}\n </td>\n </template>\n\n <template v-if=\"showDiscount\">\n <td\n :class=\"\n isChildItem\n ? 'propeller-order-item-card__cell propeller-order-item-card__cell--discount px-6 py-2 text-right text-sm text-muted-foreground'\n : 'propeller-order-item-card__cell propeller-order-item-card__cell--discount px-6 py-4 text-right whitespace-nowrap text-orange-600'\n \"\n >\n <template v-if=\"discount > 0\">\n {{ formatDiscountDisplay() }}\n </template>\n </td>\n </template>\n\n <template v-if=\"showPrice\">\n <td\n :class=\"\n isChildItem\n ? 'propeller-order-item-card__cell propeller-order-item-card__cell--price px-6 py-2 text-right whitespace-nowrap text-sm text-muted-foreground'\n : 'propeller-order-item-card__cell propeller-order-item-card__cell--price px-6 py-4 text-right whitespace-nowrap'\n \"\n >\n <!-- When the consumer injects a priceComponent, delegate to it;\n otherwise keep the existing inline line-total rendering.\n Contract-vs-data note (same as CartItem): the\n PriceComponentProps.price contract expects an SDK ProductPrice\n (catalog/unit price), while this cell historically renders the\n line total `orderItem.priceTotal`. We pass `orderItem.product.price`\n (catalog price) to the injected component to honour the contract;\n consumers who need the line total can compute their own. The\n default (uninjected) path is unchanged. -->\n <component\n v-if=\"props.priceComponent\"\n :is=\"PriceImpl\"\n :price=\"orderItem?.product?.price\"\n :currency=\"currency\"\n :labels=\"labels\"\n />\n <span v-else>{{ formatItemPrice(priceTotal) }}</span>\n </td>\n </template>\n </tr>\n <template v-if=\"hasChildren\">\n <template\n :key=\"child.id || child.uuid\"\n v-for=\"(child, index) in childItems || []\"\n >\n <tr\n class=\"propeller-order-item-card__child-row border-0\"\n data-child=\"true\"\n >\n <td\n class=\"propeller-order-item-card__cell propeller-order-item-card__cell--product px-6 py-2 pl-28\"\n >\n <span\n class=\"propeller-order-item-card__child-title text-sm text-muted-foreground\"\n >{{\n child.product?.names?.[0]?.value || child.name || \"Unknown\"\n }}</span\n >\n </td>\n <template v-if=\"showQuantity\">\n <td\n class=\"propeller-order-item-card__cell propeller-order-item-card__cell--quantity px-6 py-2 text-center text-sm text-muted-foreground\"\n >\n {{ child.quantity || 0 }}\n </td>\n </template>\n\n <template v-if=\"showDiscount\">\n <td\n class=\"propeller-order-item-card__cell propeller-order-item-card__cell--discount px-6 py-2 text-right text-sm text-muted-foreground\"\n ></td>\n </template>\n\n <template v-if=\"showPrice\">\n <td\n class=\"propeller-order-item-card__cell propeller-order-item-card__cell--price px-6 py-2 text-right whitespace-nowrap text-sm text-muted-foreground\"\n >\n {{ formatItemPrice(child.priceTotal || 0) }}\n </td>\n </template>\n </tr>\n </template>\n </template>\n </tbody>\n</template>\n\n<script setup lang=\"ts\">\nimport type { OrderItem } from \"@propeller-commerce/propeller-sdk-v2\";\nimport { computed, type Component } from \"vue\";\nimport { formatPrice as _formatPrice, getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport DefaultProductPrice from './ProductPrice.vue';\nimport DefaultItemStock from './ItemStock.vue';\n\nexport interface OrderItemCardProps {\n /** The order item to display */\n orderItem: OrderItem;\n\n /** Currency symbol to display. Defaults to '€'. */\n currency?: string;\n\n /** Child order items (rendered as indented sub-rows beneath the parent) */\n childItems?: OrderItem[];\n\n /** Should the item title be a link to the PDP */\n titleLinkable?: boolean;\n\n /** Display a small thumbnail of the order item */\n showImage?: boolean;\n\n /** Should stock info be displayed */\n showStockComponent?: boolean;\n\n /** Display the SKU of the order item beneath the item name */\n showSku?: boolean;\n\n /** Display the quantity of the order item */\n showQuantity?: boolean;\n\n /** Display the price of the order item */\n showPrice?: boolean;\n\n /** Display the discount column */\n showDiscount?: boolean;\n\n /** Should the order item notes field be displayed */\n showItemNotes?: boolean;\n\n /** Render as a child/sub-item (indented, no image) */\n isChildItem?: boolean;\n\n /** Custom price formatting function */\n formatPrice?: (price: number) => string;\n\n /** Translated labels keyed by the slugs used inside the component (see\n * `getLabel` calls). Missing keys fall back to the English defaults. */\n labels?: Record<string, string>;\n\n // ───── Extension API (no resolver — direct prop fallback) ─────\n priceComponent?: Component;\n stockComponent?: Component;\n}\ninterface OrderItemCardState {\n titleLinkable: boolean;\n showImage: boolean;\n showSku: boolean;\n showQuantity: boolean;\n showPrice: boolean;\n showDiscount: boolean;\n showStockComponent: boolean;\n showItemNotes: boolean;\n isChildItem: boolean;\n productName: string;\n productSku: string;\n productImage: string;\n productId: number | undefined;\n productSlug: string;\n productUrl: string;\n quantity: number;\n price: number;\n priceTotal: number;\n discount: number;\n originalPrice: number;\n discountPercentage: number;\n notes: string;\n hasChildren: boolean;\n formatItemPrice: (price: number) => string;\n formatDiscountDisplay: () => string;\n}\n\nconst props = withDefaults(defineProps<OrderItemCardProps>(), {\n titleLinkable: true,\n showImage: true,\n showSku: true,\n showQuantity: true,\n showPrice: true,\n showDiscount: false,\n showStockComponent: false,\n showItemNotes: false,\n isChildItem: false,\n});\n\n// Direct prop > default. No `useResolvedProps` here — mirrors React's\n// RSC-safe design where OrderItemCard skips the resolver to stay safe to\n// render in server contexts.\nconst PriceImpl = computed(() => props.priceComponent ?? DefaultProductPrice);\nconst StockImpl = computed(() => props.stockComponent ?? DefaultItemStock);\n\nconst titleLinkable = computed(() => {\n return props.titleLinkable !== undefined ? props.titleLinkable : true;\n});\nconst showImage = computed(() => {\n if (props.isChildItem) return false;\n return props.showImage !== undefined ? props.showImage : true;\n});\nconst showSku = computed(() => {\n if (props.isChildItem) return false;\n return props.showSku !== undefined ? props.showSku : true;\n});\nconst showQuantity = computed(() => {\n return props.showQuantity !== undefined ? props.showQuantity : true;\n});\nconst showPrice = computed(() => {\n return props.showPrice !== undefined ? props.showPrice : true;\n});\nconst showDiscount = computed(() => {\n return props.showDiscount !== undefined ? props.showDiscount : false;\n});\nconst showStockComponent = computed(() => {\n return props.showStockComponent !== undefined\n ? props.showStockComponent\n : false;\n});\nconst showItemNotes = computed(() => {\n return props.showItemNotes !== undefined ? props.showItemNotes : false;\n});\nconst isChildItem = computed(() => {\n return props.isChildItem || false;\n});\nconst productName = computed(() => {\n const item = props.orderItem;\n return item?.product?.names?.[0]?.value || item?.name || \"Unknown Product\";\n});\nconst productSku = computed(() => {\n return props.orderItem?.product?.sku || props.orderItem?.sku || \"\";\n});\nconst productImage = computed(() => {\n return (\n props.orderItem?.product?.media?.images?.items?.[0]?.imageVariants?.[0]\n ?.url || \"\"\n );\n});\nconst productId = computed(() => {\n return props.orderItem?.product?.productId;\n});\nconst productSlug = computed(() => {\n return props.orderItem?.product?.slugs?.[0]?.value || \"\";\n});\nconst clusterUrl = computed(() => {\n const cluster = (props.orderItem?.product as any)?.cluster;\n if (!cluster) return \"\";\n const id = cluster.clusterId ?? cluster.urlId;\n const slug = cluster.slugs?.[0]?.value || cluster.slug?.[0]?.value || \"\";\n if (!id || !slug) return \"\";\n return \"/cluster/\" + id + \"/\" + slug;\n});\nconst productUrl = computed(() => {\n if (clusterUrl.value) return clusterUrl.value;\n if (productId.value && productSlug.value) {\n return \"/product/\" + productId.value + \"/\" + productSlug.value;\n }\n return \"\";\n});\nconst quantity = computed(() => {\n return props.orderItem?.quantity || 0;\n});\nconst price = computed(() => {\n return props.orderItem?.price || 0;\n});\nconst priceTotal = computed(() => {\n return props.orderItem?.priceTotal || 0;\n});\nconst discount = computed(() => {\n return props.orderItem?.discount || 0;\n});\nconst originalPrice = computed(() => {\n return props.orderItem?.originalPrice || 0;\n});\nconst discountPercentage = computed(() => {\n if (originalPrice.value > 0 && discount.value > 0) {\n return (discount.value / originalPrice.value) * 100;\n }\n return 0;\n});\nconst notes = computed(() => {\n return props.orderItem?.notes || \"\";\n});\nconst hasChildren = computed(() => {\n return (props.childItems || []).length > 0;\n});\n\nfunction getLabel(key: string, fallback: string): string {\n return _getLabel(props.labels, key, fallback);\n}\nfunction formatItemPrice(\n price: number,\n): ReturnType<OrderItemCardState[\"formatItemPrice\"]> {\n if (props.formatPrice) {\n return props.formatPrice(price);\n }\n if (!price && price !== 0) return \"-\";\n return _formatPrice(price, { symbol: props.currency ?? \"€\" });\n}\nfunction formatDiscountDisplay(): ReturnType<\n OrderItemCardState[\"formatDiscountDisplay\"]\n> {\n const discountStr = formatItemPrice(discount.value);\n if (discountPercentage.value > 0) {\n return (\n discountStr +\n \" (\" +\n discountPercentage.value.toFixed(2).replace(\".\", \",\") +\n \"%)\"\n );\n }\n return discountStr;\n}\n</script>\n","<template>\n <div :class=\"`propeller-order-summary ${containerClass}`\">\n <template v-if=\"title\">\n <h2 class=\"propeller-order-summary__title text-xl font-bold mb-4\">\n {{ title }}\n </h2>\n </template>\n\n <div\n class=\"propeller-order-summary__meta grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 pb-5 border-b border-border mb-5\"\n >\n <template v-if=\"showOrderNumber && orderNumber\">\n <div\n class=\"propeller-order-summary__meta-item\"\n data-meta=\"order-number\"\n >\n <p\n class=\"propeller-order-summary__meta-label text-sm text-muted-foreground mb-1\"\n >\n {{ getLabel(\"orderNumber\", \"Order Number\") }}\n </p>\n <p class=\"propeller-order-summary__meta-value font-semibold\">\n {{ orderNumber }}\n </p>\n </div>\n </template>\n\n <template v-if=\"showOrderDate && orderDate\">\n <div class=\"propeller-order-summary__meta-item\" data-meta=\"order-date\">\n <p\n class=\"propeller-order-summary__meta-label text-sm text-muted-foreground mb-1\"\n >\n {{ getLabel(\"orderDate\", \"Order Date\") }}\n </p>\n <p class=\"propeller-order-summary__meta-value font-semibold\">\n {{ formatOrderDate(orderDate) }}\n </p>\n </div>\n </template>\n\n <template v-if=\"showOrderStatus && orderStatus\">\n <div class=\"propeller-order-summary__meta-item\" data-meta=\"status\">\n <p\n class=\"propeller-order-summary__meta-label text-sm text-muted-foreground mb-1\"\n >\n {{ getLabel(\"status\", \"Status\") }}\n </p>\n <span\n class=\"propeller-order-summary__status inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-secondary/10 text-secondary\"\n >{{ orderStatus }}</span\n >\n </div>\n </template>\n\n <template v-if=\"showOrderTotal\">\n <div class=\"propeller-order-summary__meta-item\" data-meta=\"total\">\n <p\n class=\"propeller-order-summary__meta-label text-sm text-muted-foreground mb-1\"\n >\n {{ getLabel(\"total\", \"Total\") }}\n </p>\n <p class=\"propeller-order-summary__total font-bold text-lg\">\n {{ formatItemPrice(orderTotal) }}\n </p>\n </div>\n </template>\n </div>\n <div\n class=\"propeller-order-summary__addresses grid grid-cols-1 md:grid-cols-2 gap-6 pb-5\"\n >\n <template v-if=\"showInvoiceAddress\">\n <div\n class=\"propeller-order-summary__address space-y-2\"\n data-address=\"invoice\"\n >\n <h3\n class=\"propeller-order-summary__address-title text-sm font-semibold text-muted-foreground uppercase tracking-wide\"\n >\n {{ getLabel(\"invoiceAddress\", \"Invoice Address\") }}\n </h3>\n <template v-if=\"invoiceAddress && invoiceAddress.street\">\n <div class=\"text-sm space-y-1\">\n <template v-if=\"invoiceAddress.company\">\n <p class=\"font-medium\">{{ invoiceAddress.company }}</p>\n </template>\n\n <p>\n {{\n [\n invoiceAddress.firstName,\n invoiceAddress.middleName,\n invoiceAddress.lastName,\n ]\n .filter(Boolean)\n .join(\" \")\n }}\n </p>\n <p>\n {{\n [\n invoiceAddress.street,\n invoiceAddress.number,\n invoiceAddress.numberExtension,\n ]\n .filter(Boolean)\n .join(\" \")\n }}\n </p>\n <p>\n {{\n [invoiceAddress.postalCode, invoiceAddress.city]\n .filter(Boolean)\n .join(\" \")\n }}\n </p>\n <template v-if=\"invoiceAddress.country\">\n <p>{{ getCountryName(invoiceAddress.country) }}</p>\n </template>\n\n <template v-if=\"invoiceAddress.email\">\n <p\n class=\"propeller-order-summary__address-email text-muted-foreground\"\n >\n {{ invoiceAddress.email }}\n </p>\n </template>\n </div>\n </template>\n </div>\n </template>\n\n <template v-if=\"showDeliveryAddress\">\n <div\n class=\"propeller-order-summary__address space-y-2\"\n data-address=\"delivery\"\n >\n <h3\n class=\"propeller-order-summary__address-title text-sm font-semibold text-muted-foreground uppercase tracking-wide\"\n >\n {{ getLabel(\"deliveryAddress\", \"Delivery Address\") }}\n </h3>\n <template v-if=\"deliveryAddress && deliveryAddress.street\">\n <div class=\"text-sm space-y-1\">\n <template v-if=\"deliveryAddress.company\">\n <p class=\"font-medium\">{{ deliveryAddress.company }}</p>\n </template>\n\n <p>\n {{\n [\n deliveryAddress.firstName,\n deliveryAddress.middleName,\n deliveryAddress.lastName,\n ]\n .filter(Boolean)\n .join(\" \")\n }}\n </p>\n <p>\n {{\n [\n deliveryAddress.street,\n deliveryAddress.number,\n deliveryAddress.numberExtension,\n ]\n .filter(Boolean)\n .join(\" \")\n }}\n </p>\n <p>\n {{\n [deliveryAddress.postalCode, deliveryAddress.city]\n .filter(Boolean)\n .join(\" \")\n }}\n </p>\n <template v-if=\"deliveryAddress.country\">\n <p>{{ getCountryName(deliveryAddress.country) }}</p>\n </template>\n\n <template v-if=\"deliveryAddress.email\">\n <p\n class=\"propeller-order-summary__address-email text-muted-foreground\"\n >\n {{ deliveryAddress.email }}\n </p>\n </template>\n </div>\n </template>\n </div>\n </template>\n </div>\n <template\n v-if=\"showDeliveryInfo && (paymentMethod || carrierName || requestDate)\"\n >\n <div\n class=\"propeller-order-summary__info-panel bg-surface-hover p-4 rounded-[var(--radius-control)] border border-border space-y-2 text-sm\"\n >\n <template v-if=\"paymentMethod\">\n <div class=\"flex justify-between\">\n <span class=\"font-medium\">{{\n getLabel(\"payment\", \"Payment:\")\n }}</span\n ><span>{{ paymentMethod }}</span>\n </div>\n </template>\n\n <template v-if=\"carrierName\">\n <div class=\"flex justify-between\">\n <span class=\"font-medium\">{{\n getLabel(\"carrier\", \"Carrier:\")\n }}</span\n ><span>{{ carrierName }}</span>\n </div>\n </template>\n\n <template v-if=\"requestDate\">\n <div class=\"flex justify-between\">\n <span class=\"font-medium\">{{\n getLabel(\"deliveryDate\", \"Delivery Date:\")\n }}</span\n ><span>{{ requestDate }}</span>\n </div>\n </template>\n </div>\n </template>\n\n <template v-if=\"showRemarks && (orderReference || orderRemarks)\">\n <div\n class=\"propeller-order-summary__remarks-panel bg-surface-hover p-4 rounded-[var(--radius-control)] border border-border space-y-2 text-sm mt-4\"\n >\n <template v-if=\"orderReference\">\n <div class=\"flex justify-between\">\n <span class=\"font-medium\">{{\n getLabel(\"reference\", \"Reference:\")\n }}</span\n ><span>{{ orderReference }}</span>\n </div>\n </template>\n\n <template v-if=\"orderRemarks\">\n <div class=\"flex justify-between\">\n <span class=\"font-medium\">{{\n getLabel(\"remarks\", \"Remarks:\")\n }}</span\n ><span>{{ orderRemarks }}</span>\n </div>\n </template>\n </div>\n </template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport type { Order } from \"@propeller-commerce/propeller-sdk-v2\";\nimport { computed } from \"vue\";\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport { formatPrice as _formatPrice } from '@propeller-commerce/propeller-v2-core-ui';\nimport { getCountryName as _getCountryName } from '@propeller-commerce/propeller-v2-core-ui';\nimport { useInfraProps } from '../composables/vue/useInfraProps';\n\nexport interface OrderSummaryProps {\n /** The order object from propeller-sdk-v2 */\n order: Order;\n\n /** Currency symbol to display. Defaults to '€'. */\n currency?: string;\n\n /** The CSS class for the order summary container */\n orderSummaryContainerClass?: string;\n\n /** Title of the order summary */\n title?: string;\n\n /** Show the order number */\n showOrderNumber?: boolean;\n\n /** Show the order date */\n showOrderDate?: boolean;\n\n /** Show the order status */\n showOrderStatus?: boolean;\n\n /** Show the order total */\n showOrderTotal?: boolean;\n\n /** Custom price formatting function */\n formatPrice?: (price: number) => string;\n\n /** Show the invoice address */\n showInvoiceAddress?: boolean;\n\n /** Show the delivery address */\n showDeliveryAddress?: boolean;\n\n /** Show payment, carrier, and delivery date info */\n showDeliveryInfo?: boolean;\n\n /** Show order remarks and reference */\n showRemarks?: boolean;\n\n /** Custom date formatting function */\n formatDate?: (dateString: string) => string;\n\n /** Labels for the component */\n labels?: Record<string, string>;\n\n /** List of countries for resolving codes to names [{code: 'NL', name: 'Netherlands'}, ...] */\n countries?: {\n code: string;\n name: string;\n }[];\n}\ninterface OrderSummaryState {\n containerClass: string;\n showOrderNumber: boolean;\n showOrderDate: boolean;\n showOrderStatus: boolean;\n showInvoiceAddress: boolean;\n showDeliveryAddress: boolean;\n showOrderTotal: boolean;\n formatItemPrice: (price: number) => string;\n showDeliveryInfo: boolean;\n showRemarks: boolean;\n orderReference: string;\n orderRemarks: string;\n getLabel: (key: string, fallback: string) => string;\n getCountryName: (code: string) => string;\n formatOrderDate: (dateString: string) => string;\n orderNumber: string;\n orderDate: string;\n orderStatus: string;\n orderTotal: number;\n invoiceAddress: any;\n deliveryAddress: any;\n paymentMethod: string;\n carrierName: string;\n requestDate: string;\n}\n\nconst props = withDefaults(defineProps<OrderSummaryProps>(), {\n showOrderNumber: true,\n showOrderDate: true,\n showOrderStatus: true,\n showOrderTotal: true,\n showInvoiceAddress: true,\n showDeliveryAddress: true,\n showDeliveryInfo: true,\n showRemarks: true,\n});\nconst infra = useInfraProps(props);\n\nconst containerClass = computed(() => {\n return props.orderSummaryContainerClass || \"order-summary\";\n});\nconst showOrderNumber = computed(() => {\n return props.showOrderNumber !== undefined ? props.showOrderNumber : true;\n});\nconst showOrderDate = computed(() => {\n return props.showOrderDate !== undefined ? props.showOrderDate : true;\n});\nconst showOrderStatus = computed(() => {\n return props.showOrderStatus !== undefined ? props.showOrderStatus : true;\n});\nconst showInvoiceAddress = computed(() => {\n return props.showInvoiceAddress !== undefined\n ? props.showInvoiceAddress\n : true;\n});\nconst showDeliveryAddress = computed(() => {\n return props.showDeliveryAddress !== undefined\n ? props.showDeliveryAddress\n : true;\n});\nconst showOrderTotal = computed(() => {\n return props.showOrderTotal !== undefined ? props.showOrderTotal : true;\n});\nconst showDeliveryInfo = computed(() => {\n return props.showDeliveryInfo !== undefined ? props.showDeliveryInfo : true;\n});\nconst showRemarks = computed(() => {\n return props.showRemarks !== undefined ? props.showRemarks : true;\n});\nconst orderReference = computed(() => {\n return props.order?.reference || \"\";\n});\nconst orderRemarks = computed(() => {\n return props.order?.remarks || \"\";\n});\nconst orderNumber = computed(() => {\n return props.order?.id || \"\";\n});\nconst orderDate = computed(() => {\n return props.order?.createdAt || \"\";\n});\nconst orderStatus = computed(() => {\n return props.order?.status || \"\";\n});\nconst orderTotal = computed(() => {\n return Number(props.order?.total?.net || 0);\n});\nconst invoiceAddress = computed(() => {\n const addresses = props.order?.addresses || [];\n return addresses.find((a: any) => a.type === \"invoice\") || null;\n});\nconst deliveryAddress = computed(() => {\n const addresses = props.order?.addresses || [];\n return addresses.find((a: any) => a.type === \"delivery\") || null;\n});\nconst paymentMethod = computed(() => {\n return props.order?.paymentData?.method || \"\";\n});\nconst carrierName = computed(() => {\n return props.order?.postageData?.carrier || \"\";\n});\nconst requestDate = computed(() => {\n const date = props.order?.postageData?.requestDate;\n if (!date) return \"\";\n if (props.formatDate) {\n return props.formatDate(date);\n }\n try {\n // Short locale format (e.g. 4/27/2026 in en-US) — matches CartOverview's\n // delivery-date rendering so checkout review and order confirmation stay\n // consistent. Override via the `formatDate` prop if a longer layout is needed.\n return new Date(date).toLocaleDateString(\"en-US\");\n } catch {\n return date;\n }\n});\n\nfunction formatItemPrice(\n price: number,\n): ReturnType<OrderSummaryState[\"formatItemPrice\"]> {\n if (props.formatPrice) {\n return props.formatPrice(price);\n }\n return _formatPrice(price || 0, { symbol: infra.currency ?? \"€\" });\n}\nfunction getLabel(\n key: string,\n fallback: string,\n): ReturnType<OrderSummaryState[\"getLabel\"]> {\n return _getLabel(props.labels, key, fallback);\n}\nfunction getCountryName(\n code: string,\n): ReturnType<OrderSummaryState[\"getCountryName\"]> {\n return _getCountryName(code, props.countries);\n}\nfunction formatOrderDate(\n dateString: string,\n): ReturnType<OrderSummaryState[\"formatOrderDate\"]> {\n if (props.formatDate) {\n return props.formatDate(dateString);\n }\n try {\n // Short locale format (e.g. 4/27/2026 in en-US) for visual consistency\n // with the delivery-date row directly above. Override via `formatDate`.\n return new Date(dateString).toLocaleDateString(\"en-US\");\n } catch {\n return dateString;\n }\n}\n</script>\n","<template>\n <div class=\"propeller-order-totals w-full md:w-80 bg-card p-6 rounded-[var(--radius-container)] shadow space-y-3\">\n <template v-if=\"showSubtotal\">\n <div class=\"propeller-order-totals__row flex justify-between text-muted-foreground\" data-row=\"subtotal\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('subtotal', 'Subtotal:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(subtotal) }}</span>\n </div>\n </template>\n\n <template v-if=\"showDiscount && hasDiscount\">\n <div class=\"propeller-order-totals__row flex justify-between text-secondary\" data-row=\"discount\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('discount', 'Discount:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ discountDisplay }}</span>\n </div>\n <div class=\"propeller-order-totals__row flex justify-between text-muted-foreground border-t pt-2 border-dashed\" data-row=\"subtotal-with-discount\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('subtotalWithDiscount', 'Subtotal with discount:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(subtotalWithDiscount) }}</span>\n </div>\n </template>\n\n <template v-if=\"hasTransactionCosts\">\n <div class=\"propeller-order-totals__row flex justify-between text-muted-foreground\" data-row=\"transaction-costs\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('transactionCosts', 'Transaction costs:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(transactionCosts) }}</span>\n </div>\n </template>\n\n <template v-if=\"showShippingCosts && hasShippingCosts\">\n <div class=\"propeller-order-totals__row flex justify-between text-muted-foreground\" data-row=\"shipping-costs\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('shippingCosts', 'Shipping costs:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(shippingCosts) }}</span>\n </div>\n </template>\n\n <template v-if=\"showTotalExclVat\">\n <div class=\"propeller-order-totals__row flex justify-between text-muted-foreground pt-2 border-t\" data-row=\"total-excl-vat\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('totalExclVat', 'Total excl. VAT:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(totalExclVat) }}</span>\n </div>\n </template>\n\n <template v-if=\"showVATs && taxPercentages.length > 0\">\n <template :key=\"index\" v-for=\"(tax, index) in taxPercentages\">\n <div class=\"propeller-order-totals__row flex justify-between text-muted-foreground text-sm\" data-row=\"vat-line\">\n <span class=\"propeller-order-totals__label\">{{ tax.percentage }}% {{ getLabel('vat', 'VAT') }}:</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(Number(tax.total)) }}</span>\n </div>\n </template>\n </template>\n\n <template v-if=\"showTotalVat\">\n <div class=\"propeller-order-totals__row flex justify-between text-muted-foreground text-sm\" data-row=\"total-vat\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('totalVat', 'Total VAT:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(totalVat) }}</span>\n </div>\n </template>\n\n <div class=\"propeller-order-totals__row propeller-order-totals__row--total flex justify-between text-xl font-bold pt-4 border-t text-foreground mt-2\" data-row=\"total\">\n <span class=\"propeller-order-totals__label\">{{ getLabel('total', 'Total:') }}</span\n ><span class=\"propeller-order-totals__value\">{{ formatItemPrice(totalInclVat) }}</span>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed } from \"vue\";\n\nimport { Order, OrderDiscountType } from '@propeller-commerce/propeller-sdk-v2';\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport { formatPrice as _formatPrice } from '@propeller-commerce/propeller-v2-core-ui';\nimport { useInfraProps } from '../composables/vue/useInfraProps';\n\nexport interface OrderTotalsProps {\n /** The order/quote used to populate the summary data */\n order: Order;\n\n /** Currency symbol to display. Defaults to '€'. */\n currency?: string;\n\n /** Order summary block title */\n title?: string;\n\n /** Labels for the component */\n labels?: Record<string, string>;\n\n /** Display the subtotal of the order/quote */\n showSubtotal?: boolean;\n\n /** Display the total discount of the order/quote */\n showDiscount?: boolean;\n\n /** Display the shipping costs of the order/quote */\n showShippingCosts?: boolean;\n\n /** Display all VATs of the order/quote */\n showVATs?: boolean;\n\n /** Display the total of the order/quote excluding the VAT */\n showTotalExclVat?: boolean;\n\n /** Display the total VAT of the order/quote */\n showTotalVat?: boolean;\n\n /** Custom price formatting function */\n formatPrice?: (price: number) => string;\n}\ninterface OrderTotalsState {\n title: string;\n showSubtotal: boolean;\n showDiscount: boolean;\n showShippingCosts: boolean;\n showVATs: boolean;\n showTotalExclVat: boolean;\n showTotalVat: boolean;\n getLabel: (key: string, fallback: string) => string;\n formatItemPrice: (price: number) => string;\n subtotal: number;\n hasDiscount: boolean;\n discountDisplay: string;\n subtotalWithDiscount: number;\n hasTransactionCosts: boolean;\n transactionCosts: number;\n hasShippingCosts: boolean;\n shippingCosts: number;\n totalExclVat: number;\n taxPercentages: any[];\n totalInclVat: number;\n totalVat: number;\n}\n\nconst props = withDefaults(defineProps<OrderTotalsProps>(), {\n showSubtotal: true,\n showDiscount: true,\n showShippingCosts: true,\n showVATs: true,\n showTotalExclVat: true,\n showTotalVat: true,\n});\nconst infra = useInfraProps(props);\n\nconst title = computed(() => {\n return props.title || 'Order summary';\n});\nconst showSubtotal = computed(() => {\n return props.showSubtotal !== undefined ? props.showSubtotal : true;\n});\nconst showDiscount = computed(() => {\n return props.showDiscount !== undefined ? props.showDiscount : true;\n});\nconst showShippingCosts = computed(() => {\n return props.showShippingCosts !== undefined ? props.showShippingCosts : true;\n});\nconst showVATs = computed(() => {\n return props.showVATs !== undefined ? props.showVATs : true;\n});\nconst showTotalExclVat = computed(() => {\n return props.showTotalExclVat !== undefined ? props.showTotalExclVat : true;\n});\nconst showTotalVat = computed(() => {\n return props.showTotalVat !== undefined ? props.showTotalVat : true;\n});\nconst subtotal = computed(() => {\n return (props.order as any)?.total?.gross || 0;\n});\nconst hasDiscount = computed(() => {\n const total = (props.order as any)?.total;\n return (\n total?.discountType &&\n total.discountType !== OrderDiscountType.N &&\n total.discountValue > 0\n );\n});\nconst discountDisplay = computed(() => {\n const total = (props.order as any)?.total;\n if (!total) return '';\n if (total.discountType === OrderDiscountType.A) {\n return '-' + formatItemPrice(total.discountValue);\n }\n if (total.discountType === OrderDiscountType.P) {\n return '- ' + total.discountValue + '%';\n }\n return '-' + formatItemPrice(total.discountValue);\n});\nconst subtotalWithDiscount = computed(() => {\n const total = (props.order as any)?.total;\n return (total?.gross || 0) - (total?.discountValue || 0);\n});\nconst hasTransactionCosts = computed(() => {\n return (props.order as any)?.paymentData?.gross > 0;\n});\nconst transactionCosts = computed(() => {\n return Number((props.order as any)?.paymentData?.gross || 0);\n});\nconst hasShippingCosts = computed(() => {\n return (props.order as any)?.postageData?.gross > 0;\n});\nconst shippingCosts = computed(() => {\n return Number((props.order as any)?.postageData?.gross || 0);\n});\nconst totalExclVat = computed(() => {\n return (props.order as any)?.total?.gross || 0;\n});\nconst taxPercentages = computed(() => {\n const taxes = (props.order as any)?.total?.taxPercentages || [];\n return taxes.filter((tax: any) => tax.percentage > 0 && tax.total > 0);\n});\nconst totalInclVat = computed(() => {\n return (props.order as any)?.total?.net || 0;\n});\nconst totalVat = computed(() => {\n let sum = 0;\n const taxes = taxPercentages.value;\n for (let i = 0; i < taxes.length; i++) {\n sum += Number(taxes[i].total || 0);\n }\n return sum;\n});\n\nfunction getLabel(key: string, fallback: string): ReturnType<OrderTotalsState['getLabel']> {\n return _getLabel(props.labels, key, fallback);\n}\nfunction formatItemPrice(price: number): ReturnType<OrderTotalsState['formatItemPrice']> {\n if (props.formatPrice) {\n return props.formatPrice(price);\n }\n return _formatPrice(price || 0, { symbol: infra.currency ?? '€' });\n}\n</script>\n","<template>\n <template v-if=\"!isHidden() && hasItems()\">\n <div\n :class=\"`propeller-product-bulk-prices ${className || ''}`\"\n :data-include-tax=\"getIncludeTax() ? 'true' : 'false'\"\n >\n <template v-if=\"getLabel('title', 'Volume pricing')\">\n <h3\n class=\"propeller-product-bulk-prices__title text-base font-semibold text-foreground mb-3\"\n >\n {{ getLabel(\"title\", \"Volume pricing\") }}\n </h3>\n </template>\n\n <div\n class=\"propeller-product-bulk-prices__table-wrapper overflow-hidden rounded-[var(--radius-container)] border border-border\"\n >\n <table class=\"propeller-product-bulk-prices__table w-full text-sm\">\n <thead\n class=\"propeller-product-bulk-prices__thead bg-surface-hover/50\"\n >\n <tr>\n <th\n class=\"propeller-product-bulk-prices__th propeller-product-bulk-prices__th--quantity px-4 py-2 text-left font-medium text-muted-foreground\"\n >\n {{ getLabel(\"quantityFrom\", \"Qty from\") }}\n </th>\n <th\n class=\"propeller-product-bulk-prices__th propeller-product-bulk-prices__th--price px-4 py-2 text-right font-medium text-muted-foreground\"\n >\n {{ getLabel(\"price\", \"Price\")\n }}<span\n class=\"propeller-product-bulk-prices__tax-label font-normal text-xs\"\n >\n (\n <template v-if=\"getIncludeTax()\">\n {{ getLabel(\"inclTax\", \"incl. VAT\") }}\n </template>\n\n <template v-else>\n {{ getLabel(\"exclTax\", \"excl. VAT\") }}\n </template>\n )\n </span>\n </th>\n </tr>\n </thead>\n <tbody\n class=\"propeller-product-bulk-prices__tbody divide-y divide-border\"\n >\n <template :key=\"index\" v-for=\"(tier, index) in getBulkPrices()\">\n <tr\n class=\"propeller-product-bulk-prices__row bg-card hover:bg-surface-hover/20 transition-colors\"\n >\n <td\n class=\"propeller-product-bulk-prices__cell propeller-product-bulk-prices__cell--quantity px-4 py-2 text-foreground font-medium\"\n >\n {{ getQuantityLabel(tier, index) }}\n </td>\n <td\n class=\"propeller-product-bulk-prices__cell propeller-product-bulk-prices__cell--price px-4 py-2 text-right text-foreground font-semibold\"\n >\n {{ getPrice(tier) }}\n </td>\n </tr>\n </template>\n </tbody>\n </table>\n </div>\n </div>\n </template>\n</template>\n\n<script setup lang=\"ts\">\nimport { ProductPrice, Contact, Customer } from \"@propeller-commerce/propeller-sdk-v2\";\nimport type { IDiscount } from \"@propeller-commerce/propeller-sdk-v2\";\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport { formatPrice as _formatPrice } from '@propeller-commerce/propeller-v2-core-ui';\n\nexport interface ProductBulkPricesProps {\n /**\n * Bulk price tiers from the product.\n * Obtain from `product.bulkPrices`.\n */\n bulkPrices: ProductPrice[];\n\n /** Currency symbol to display. Defaults to '€'. */\n currency?: string;\n\n /**\n * When true, net price (incl. tax) is the leading price.\n * Defaults to false — gross (excl. VAT) is shown.\n * Note: in the Propeller SDK `price.gross` = excl. VAT, `price.net` = incl. VAT.\n */\n includeTax?: boolean;\n\n /**\n * Controls portal visibility mode.\n * 'semi-closed' — component is hidden for anonymous users.\n * Defaults to 'open'.\n */\n portalMode?: string;\n\n /** Authenticated user — used for semi-closed visibility. */\n user?: Contact | Customer | null;\n\n /** Tax zone code. Defaults to 'NL'. */\n taxZone?: string;\n\n /**\n * Override any UI string.\n * Available keys: title, quantityFrom, price, inclTax, exclTax\n */\n labels?: Record<string, string>;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\ninterface ProductBulkPricesState {\n isHidden: () => boolean;\n hasItems: () => boolean;\n getIncludeTax: () => boolean;\n getTierQuantity: (tier: ProductPrice) => number | null;\n getBulkPrices: () => ProductPrice[];\n getPrice: (tier: ProductPrice) => string;\n getQuantityLabel: (tier: ProductPrice, index: number) => string;\n getLabel: (key: string, fallback: string) => string;\n}\n\nconst props = defineProps<ProductBulkPricesProps>();\n\nfunction isHidden(): ReturnType<ProductBulkPricesState[\"isHidden\"]> {\n return (props.portalMode as string) === \"semi-closed\" && !props.user;\n}\nfunction getIncludeTax(): ReturnType<ProductBulkPricesState[\"getIncludeTax\"]> {\n return props.includeTax !== undefined ? !!props.includeTax : false;\n}\nfunction getTierQuantity(\n tier: ProductPrice,\n): ReturnType<ProductBulkPricesState[\"getTierQuantity\"]> {\n const discount = tier.discount as\n | (IDiscount & {\n quantityFrom?: number;\n })\n | undefined;\n return discount?.quantityFrom ?? tier.quantity ?? null;\n}\nfunction getBulkPrices(): ReturnType<ProductBulkPricesState[\"getBulkPrices\"]> {\n const rawAll = (props.bulkPrices as ProductPrice[]) || [];\n const all = rawAll.filter((tier) => {\n const t = tier as ProductPrice & {\n type?: string;\n discountType?: string;\n };\n const priceType =\n t.type ??\n (\n t.discount as\n | {\n type?: string;\n }\n | undefined\n )?.type;\n const discountType =\n t.discountType ??\n (\n t.discount as\n | {\n discountType?: string;\n }\n | undefined\n )?.discountType;\n return !(priceType === \"PRICESHEET\" && discountType === \"LIST_PRICE_MIN\");\n });\n if (all.length === 0) return [];\n const now = new Date();\n const groups = new Map<number, ProductPrice[]>();\n for (const tier of all) {\n const qty = getTierQuantity(tier);\n if (qty === null) continue;\n const list = groups.get(qty) || [];\n list.push(tier);\n groups.set(qty, list);\n }\n const filtered: ProductPrice[] = [];\n for (const [, prices] of groups) {\n const validDated: ProductPrice[] = [];\n const nullDated: ProductPrice[] = [];\n for (const tier of prices) {\n const discount = tier.discount as\n | (IDiscount & {\n validFrom?: string;\n validTo?: string;\n })\n | undefined;\n if (!discount) {\n filtered.push(tier);\n continue;\n }\n const validFrom = discount.validFrom ?? null;\n const validTo = discount.validTo ?? null;\n if (validFrom === null && validTo === null) {\n nullDated.push(tier);\n continue;\n }\n let isValid = true;\n if (validFrom !== null && now < new Date(validFrom)) isValid = false;\n if (isValid && validTo !== null && now > new Date(validTo))\n isValid = false;\n if (isValid) validDated.push(tier);\n }\n if (validDated.length > 0) filtered.push(validDated[0]);\n else if (nullDated.length > 0) filtered.push(nullDated[0]);\n }\n filtered.sort(\n (a, b) => (getTierQuantity(a) ?? 0) - (getTierQuantity(b) ?? 0),\n );\n if (filtered.length === 1 && getTierQuantity(filtered[0]) === 1) return [];\n return filtered;\n}\nfunction hasItems(): ReturnType<ProductBulkPricesState[\"hasItems\"]> {\n return getBulkPrices().length > 0;\n}\nfunction getPrice(\n tier: ProductPrice,\n): ReturnType<ProductBulkPricesState[\"getPrice\"]> {\n const useTax: boolean = getIncludeTax();\n const value: number | undefined = useTax ? tier.net : tier.gross;\n if (value === null || value === undefined) return \"\";\n return _formatPrice(Number(value), { symbol: props.currency ?? \"€\" });\n}\nfunction getQuantityLabel(\n tier: ProductPrice,\n index: number,\n): ReturnType<ProductBulkPricesState[\"getQuantityLabel\"]> {\n const prices = getBulkPrices();\n const discount = tier.discount as\n | (IDiscount & {\n quantityFrom?: number;\n })\n | undefined;\n const qty = discount?.quantityFrom || tier.quantity || 1;\n const nextTier = prices[index + 1];\n const nextDiscount = nextTier?.discount as\n | (IDiscount & {\n quantityFrom?: number;\n })\n | undefined;\n const nextQty = nextDiscount?.quantityFrom || nextTier?.quantity;\n if (nextQty) {\n return `${qty}\\u2013${nextQty - 1}`;\n }\n return `${qty}+`;\n}\nfunction getLabel(\n key: string,\n fallback: string,\n): ReturnType<ProductBulkPricesState[\"getLabel\"]> {\n return _getLabel(props.labels, key, fallback);\n}\n</script>\n","<template>\n <div :class=\"`propeller-product-downloads ${className || ''}`\">\n <template v-if=\"hasItems()\">\n <h3\n class=\"propeller-product-downloads__title text-base font-semibold text-foreground mb-3\"\n >\n {{ getLabel(\"title\", \"Downloads\") }}\n </h3>\n </template>\n\n <template v-if=\"hasItems()\">\n <ul class=\"propeller-product-downloads__list space-y-2\">\n <template :key=\"index\" v-for=\"(doc, index) in getDownloadItems()\">\n <li class=\"propeller-product-downloads__item\">\n <template v-if=\"!!getDocumentUrl(doc)\">\n <a\n target=\"_blank\"\n class=\"propeller-product-downloads__link flex items-center gap-3 rounded-[var(--radius-container)] border border-border bg-card px-4 py-3 text-sm text-foreground hover:bg-surface-hover/30 hover:border-primary/40 transition-colors group\"\n :href=\"getDocumentUrl(doc)\"\n :download=\"true\"\n ><svg\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n class=\"h-5 w-5 flex-shrink-0 text-muted-foreground group-hover:text-primary transition-colors\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n :strokeWidth=\"1.5\"\n ></path></svg\n ><span class=\"flex-1 min-w-0 truncate\">{{\n getDocumentName(doc)\n }}</span\n ><svg\n fill=\"none\"\n stroke=\"currentColor\"\n viewBox=\"0 0 24 24\"\n class=\"h-4 w-4 flex-shrink-0 text-muted-foreground group-hover:text-primary transition-colors\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4\"\n :strokeWidth=\"2\"\n ></path></svg\n ></a>\n </template>\n </li>\n </template>\n </ul>\n </template>\n\n <template v-if=\"!hasItems()\">\n <p\n class=\"propeller-product-downloads__empty text-sm text-muted-foreground\"\n >\n {{ getLabel(\"empty\", \"No downloads\") }}\n </p>\n </template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport {\n getLanguageString,\n getLanguageUri,\n} from '@propeller-commerce/propeller-v2-core-ui';\nimport {\n PaginatedMediaDocumentResponse,\n MediaDocument,\n LocalizedDocument,\n LocalizedString,\n} from \"@propeller-commerce/propeller-sdk-v2\";\n\nexport interface ProductDownloadsProps {\n /**\n * Media documents for the product.\n * Obtain from `product.media?.documents` — may be undefined when the\n * product has no documents; the component renders an empty state.\n */\n downloads?: PaginatedMediaDocumentResponse;\n\n /**\n * Language code used to resolve the correct localised document URL and label.\n */\n language: string;\n\n /**\n * Override any UI string.\n * Available keys: title, download, empty\n */\n labels?: Record<string, string>;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\ninterface ProductDownloadsState {\n hasItems: () => boolean;\n getDownloadItems: () => MediaDocument[];\n getDocumentUrl: (doc: MediaDocument) => string;\n getDocumentName: (doc: MediaDocument) => string;\n getDocumentMime: (doc: MediaDocument) => string;\n getLabel: (key: string, fallback: string) => string;\n}\n\nconst props = defineProps<ProductDownloadsProps>();\n\nfunction hasItems(): ReturnType<ProductDownloadsState[\"hasItems\"]> {\n const d = props.downloads as PaginatedMediaDocumentResponse;\n return !!d?.items && d.items.length > 0;\n}\nfunction getDownloadItems(): ReturnType<\n ProductDownloadsState[\"getDownloadItems\"]\n> {\n const d = props.downloads as PaginatedMediaDocumentResponse;\n return d?.items || [];\n}\nfunction getDocumentUrl(\n doc: MediaDocument,\n): ReturnType<ProductDownloadsState[\"getDocumentUrl\"]> {\n const lang = (props.language as string) || \"NL\";\n const docs = doc.documents || [];\n const match = docs.find((d: LocalizedDocument) => d.language === lang);\n return match?.originalUrl || docs?.[0]?.originalUrl || \"\";\n}\nfunction getDocumentName(\n doc: MediaDocument,\n): ReturnType<ProductDownloadsState[\"getDocumentName\"]> {\n return getLanguageString(doc.alt, props.language || \"NL\", \"Download\");\n}\nfunction getDocumentMime(\n doc: MediaDocument,\n): ReturnType<ProductDownloadsState[\"getDocumentMime\"]> {\n const lang = (props.language as string) || \"NL\";\n const docs = doc.documents || [];\n const match = docs.find((d: LocalizedDocument) => d.language === lang);\n return match?.mimeType || docs?.[0]?.mimeType || \"\";\n}\nfunction getLabel(\n key: string,\n fallback: string,\n): ReturnType<ProductDownloadsState[\"getLabel\"]> {\n return _getLabel(props.labels, key, fallback);\n}\n</script>\n","<template>\n <template v-if=\"!!html\">\n <div\n v-html=\"html\"\n :class=\"`propeller-product-short-description prose prose-slate max-w-none text-muted-foreground ${\n className || ''\n }`\"\n ></div>\n </template>\n</template>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch } from \"vue\";\n\nimport type { Product, Cluster, LocalizedString } from '@propeller-commerce/propeller-sdk-v2';\nimport { getLanguageString, getLanguageUri } from '@propeller-commerce/propeller-v2-core-ui';\nimport { useInfraProps } from '../composables/vue/useInfraProps';\n\nexport interface ProductShortDescriptionProps {\n /**\n * Product or Cluster object.\n * The component reads `product.shortDescriptions` (an array of LocalizedString)\n * and renders the matching language entry as HTML.\n */\n product: Product | Cluster;\n\n /**\n * Language code used to resolve the correct localised short description.\n * Defaults to 'NL'.\n */\n language?: string;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\ninterface ProductShortDescriptionState {\n html: string;\n getShortDescription: () => string;\n}\n\nconst props = defineProps<ProductShortDescriptionProps>();\nconst infra = useInfraProps(props);\nconst html = ref<ProductShortDescriptionState['html']>('');\n\nwatch(\n () => [props.product, infra.language],\n () => {\n html.value = getShortDescription();\n },\n { immediate: true }\n);\nfunction getShortDescription(): ReturnType<ProductShortDescriptionState['getShortDescription']> {\n const product = props.product as Product;\n if (!product?.shortDescriptions) return '';\n return getLanguageString(product.shortDescriptions, infra.language || 'NL', '');\n}\n</script>\n","<template>\n <div :class=\"`propeller-product-videos ${className || ''}`\">\n <template v-if=\"hasItems()\">\n <h3 class=\"propeller-product-videos__title text-base font-semibold text-foreground mb-3\">\n {{ getLabel('title', 'Videos') }}\n </h3>\n </template>\n\n <template v-if=\"hasItems()\">\n <div class=\"propeller-product-videos__list space-y-4\">\n <template :key=\"index\" v-for=\"(video, index) in getVideoItems()\">\n <div\n class=\"propeller-product-videos__item rounded-[var(--radius-container)] overflow-hidden border border-border bg-black\"\n :data-embedded=\"!!getVideoUri(video) && isEmbeddable(getVideoUri(video)) ? 'true' : 'false'\"\n >\n <template v-if=\"!!getVideoUri(video)\">\n <template v-if=\"isEmbeddable(getVideoUri(video))\">\n <div\n class=\"propeller-product-videos__embed relative w-full\"\n :style=\"{\n paddingBottom: '56.25%',\n }\"\n >\n <iframe\n loading=\"lazy\"\n allow=\"\n accelerometer;\n autoplay;\n clipboard-write;\n encrypted-media;\n gyroscope;\n picture-in-picture;\n \"\n class=\"propeller-product-videos__iframe absolute inset-0 w-full h-full\"\n :src=\"getEmbedUrl(getVideoUri(video))\"\n :title=\"getVideoTitle(video)\"\n :allowFullScreen=\"true\"\n ></iframe>\n </div>\n </template>\n\n <template v-if=\"!isEmbeddable(getVideoUri(video))\">\n <video preload=\"metadata\" class=\"propeller-product-videos__video w-full\" :controls=\"true\">\n <source :src=\"getVideoUri(video)\" />\n </video>\n </template>\n </template>\n </div>\n </template>\n </div>\n </template>\n\n <template v-if=\"!hasItems()\">\n <p class=\"propeller-product-videos__empty text-sm text-muted-foreground\">\n {{ getLabel('empty', 'No videos') }}\n </p>\n </template>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { getLabel as _getLabel } from '@propeller-commerce/propeller-v2-core-ui';\nimport { getLanguageString, getLanguageUri } from '@propeller-commerce/propeller-v2-core-ui';\nimport {\n PaginatedMediaVideoResponse,\n MediaVideo,\n LocalizedVideo,\n LocalizedString,\n} from '@propeller-commerce/propeller-sdk-v2';\n\nexport interface ProductVideosProps {\n /**\n * Media videos for the product.\n * Obtain from `product.media?.videos` — may be undefined when the\n * product has no videos; the component renders an empty state.\n */\n videos?: PaginatedMediaVideoResponse;\n\n /**\n * Language code used to resolve the correct localised video URI.\n */\n language: string;\n\n /**\n * Override any UI string.\n * Available keys: title, empty\n */\n labels?: Record<string, string>;\n\n /** Extra CSS class applied to the root element. */\n className?: string;\n}\ninterface ProductVideosState {\n hasItems: () => boolean;\n getVideoItems: () => MediaVideo[];\n getVideoUri: (video: MediaVideo) => string;\n getVideoTitle: (video: MediaVideo) => string;\n isEmbeddable: (uri: string) => boolean;\n getEmbedUrl: (uri: string) => string;\n getLabel: (key: string, fallback: string) => string;\n}\n\nconst props = defineProps<ProductVideosProps>();\n\nfunction hasItems(): ReturnType<ProductVideosState['hasItems']> {\n const v = props.videos as PaginatedMediaVideoResponse;\n return !!v?.items && v.items.length > 0;\n}\nfunction getVideoItems(): ReturnType<ProductVideosState['getVideoItems']> {\n const v = props.videos as PaginatedMediaVideoResponse;\n return v?.items || [];\n}\nfunction getVideoUri(video: MediaVideo): ReturnType<ProductVideosState['getVideoUri']> {\n const lang = (props.language as string) || 'NL';\n const vids = video.videos || [];\n const match = vids.find((v: LocalizedVideo) => v.language === lang);\n return match?.uri || vids?.[0]?.uri || '';\n}\nfunction getVideoTitle(video: MediaVideo): ReturnType<ProductVideosState['getVideoTitle']> {\n return getLanguageString(video.alt, props.language || 'NL', 'Video');\n}\nfunction isEmbeddable(uri: string): ReturnType<ProductVideosState['isEmbeddable']> {\n return uri.includes('youtube.com') || uri.includes('youtu.be') || uri.includes('vimeo.com');\n}\nfunction getEmbedUrl(uri: string): ReturnType<ProductVideosState['getEmbedUrl']> {\n // Already an embed URL — return as-is\n if (uri.includes('youtube.com/embed/') || uri.includes('player.vimeo.com/video/')) {\n return uri;\n }\n // YouTube watch URL → embed URL\n if (uri.includes('youtube.com/watch')) {\n const url = new URL(uri);\n const videoId = url.searchParams.get('v') || '';\n return `https://www.youtube.com/embed/${videoId}`;\n }\n // YouTube short URL\n if (uri.includes('youtu.be/')) {\n const videoId = uri.split('youtu.be/')[1]?.split('?')[0] || '';\n return `https://www.youtube.com/embed/${videoId}`;\n }\n // Vimeo standard URL (https://vimeo.com/ID or https://vimeo.com/ID/HASH)\n if (uri.includes('vimeo.com/')) {\n const parts = uri.split('vimeo.com/')[1]?.split('?')[0]?.split('/') || [];\n const videoId = parts[0] || '';\n const hash = parts[1] || '';\n return hash\n ? `https://player.vimeo.com/video/${videoId}?h=${hash}`\n : `https://player.vimeo.com/video/${videoId}`;\n }\n return uri;\n}\nfunction getLabel(key: string, fallback: string): ReturnType<ProductVideosState['getLabel']> {\n return _getLabel(props.labels, key, fallback);\n}\n</script>\n"],"names":["inject","deriveUserMode","reactive","_isContentHidden","_formatPrice","YesNo","_getLabel","_createElementBlock","_hoisted_2","_toDisplayString","_openBlock","_hoisted_3","_createElementVNode","_hoisted_4","_hoisted_5","_hoisted_6","_hoisted_7","_hoisted_8","getLanguageString","index","_Fragment","_renderList","_hoisted_9","_hoisted_10","_hoisted_11","_hoisted_12","_createTextVNode","computed","_hoisted_1","DefaultProductPrice","DefaultItemStock","price","_createBlock","_resolveDynamicComponent","_normalizeClass","_hoisted_13","_hoisted_14","_hoisted_15","_getCountryName","_hoisted_16","_hoisted_17","_hoisted_18","_hoisted_19","_hoisted_20","_hoisted_21","_hoisted_22","_hoisted_23","_hoisted_24","_hoisted_25","_hoisted_26","_hoisted_27","OrderDiscountType","ref","watch"],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { Decorator } from '@storybook/vue3-vite';
2
+ /**
3
+ * Wrap a story so it runs inside the Propeller plugin + provider with mock infra.
4
+ *
5
+ * Override individual scope/deps fields per-story via the `propeller` parameter:
6
+ *
7
+ * export const Anonymous: Story = {
8
+ * parameters: { propeller: { user: null } },
9
+ * };
10
+ */
11
+ export declare const withPropeller: Decorator;
12
+ /**
13
+ * Constrain a story's width — many components (cards, cart items) are built
14
+ * to fill their container; an unconstrained Storybook canvas stretches them
15
+ * edge to edge. Wrap with a sensible max-width.
16
+ */
17
+ export declare function withMaxWidth(px: number): Decorator;
@@ -0,0 +1,43 @@
1
+ import { Product, Cluster, Cart, CartMainItem, Order, OrderItem, Category, Contact, Customer, ProductPrice, LocalizedString } from '@propeller-commerce/propeller-sdk-v2';
2
+ /**
3
+ * Override bag for the builders. The SDK domain types are large and the
4
+ * builders carry a few non-SDK convenience fields (a string `id`, a flat
5
+ * `total`) that components read via permissive access. A loose record lets a
6
+ * story tweak one field without re-stating the full SDK shape; the single
7
+ * `as unknown as T` at each builder's return is the honest type boundary.
8
+ */
9
+ type Loose = Record<string, unknown>;
10
+ /** Build a LocalizedString list — defaults to an EN + NL pair. */
11
+ export declare function localized(value: string, language?: string): LocalizedString[];
12
+ export declare const PLACEHOLDER_IMAGE: string;
13
+ export declare function makeProductPrice(overrides?: Loose): ProductPrice;
14
+ /** A price carrying a discount — `list` is the was-price, `gross` the now-price. */
15
+ export declare function makeDiscountedPrice(overrides?: Loose): ProductPrice;
16
+ export declare function makeProduct(overrides?: Loose): Product;
17
+ /** A product with no stock — for ItemStock / AddToCart "out of stock" stories. */
18
+ export declare function makeOutOfStockProduct(overrides?: Loose): Product;
19
+ export declare function makeCluster(overrides?: Loose): Cluster;
20
+ export declare function makeCartItem(overrides?: Loose): CartMainItem;
21
+ export declare function makeCart(overrides?: Loose): Cart;
22
+ export declare function makeOrderItem(overrides?: Loose): OrderItem;
23
+ export declare function makeOrder(overrides?: Loose): Order;
24
+ export declare function makeCategory(overrides?: Loose): Category;
25
+ /** A category path (breadcrumb trail) — Home > Tools > Power Tools. */
26
+ export declare function makeCategoryPath(): Category[];
27
+ export declare function makeContact(overrides?: Loose): Contact;
28
+ export declare function makeCustomer(overrides?: Loose): Customer;
29
+ /** A ProductInventory — `totalQuantity` drives stock-status display. */
30
+ export declare function makeInventory(totalQuantity?: number): import('@propeller-commerce/propeller-sdk-v2').ProductInventory;
31
+ /** A document-media response — for ProductDownloads. */
32
+ export declare function makeDocuments(overrides?: Loose): import('@propeller-commerce/propeller-sdk-v2').PaginatedMediaDocumentResponse;
33
+ /** A video-media response — for ProductVideos. */
34
+ export declare function makeVideos(overrides?: Loose): import('@propeller-commerce/propeller-sdk-v2').PaginatedMediaVideoResponse;
35
+ /** A cluster-option list — for ClusterOptions / ClusterConfigurator. */
36
+ export declare function makeClusterOptions(): import('@propeller-commerce/propeller-sdk-v2').ClusterOption[];
37
+ /** An Address — defaults to a default delivery address. */
38
+ export declare function makeAddress(overrides?: Loose): import('@propeller-commerce/propeller-sdk-v2').Address;
39
+ /** An attribute-filter list — for GridFilters (a colour facet + a brand facet). */
40
+ export declare function makeFilters(): import('@propeller-commerce/propeller-sdk-v2').AttributeFilter[];
41
+ /** A ProductsResponse page — for GridPagination / ProductGrid. */
42
+ export declare function makeProductsResponse(overrides?: Loose): import('@propeller-commerce/propeller-sdk-v2').ProductsResponse;
43
+ export {};
@@ -0,0 +1,7 @@
1
+ import { Services } from '@propeller-commerce/propeller-v2-core-ui';
2
+ /**
3
+ * Build the mock Services bundle. Every `services.x.y(...)` call returns a
4
+ * resolved Promise — fixture data for known methods, `{}` otherwise.
5
+ */
6
+ export declare function createMockServices(): Services;
7
+ export declare const mockServices: Services;
@@ -0,0 +1,152 @@
1
+ import { Component } from 'vue';
2
+ import { Cart, Contact, Customer, GraphQLClient } from '@propeller-commerce/propeller-sdk-v2';
3
+ export interface AccountMenuLink {
4
+ /** Display label for the link */
5
+ label: string;
6
+ /** URL path for the link */
7
+ href: string;
8
+ /** Optional icon name */
9
+ icon?: string;
10
+ }
11
+ export interface AccountIconAndMenuProps {
12
+ /**
13
+ * Contact/Customer that this component will operate with.
14
+ * When present, shows account navigation. When null, shows login form.
15
+ */
16
+ user?: Contact | Customer | null;
17
+ /**
18
+ * Icon for the account icon in header.
19
+ * @default 'default-account-icon'
20
+ */
21
+ icon?: string;
22
+ /**
23
+ * Show account dropdown at the bottom of the icon when account icon is clicked.
24
+ * If false, fires onAccountIconClick() instead.
25
+ * @default true
26
+ */
27
+ showAccountMenuOnClick?: boolean;
28
+ /**
29
+ * Title for the account dropdown menu.
30
+ * @default 'My account'
31
+ */
32
+ accountMenuTitle?: string;
33
+ /**
34
+ * Show login form in dropdown for immediate login when user is not logged in.
35
+ * @default true
36
+ */
37
+ accountHeaderLoginForm?: boolean;
38
+ /**
39
+ * GraphQL client for self-contained login.
40
+ * When provided (and onLoginSubmit is not), LoginForm handles authentication internally.
41
+ */
42
+ graphqlClient?: GraphQLClient;
43
+ /**
44
+ * Title displayed inside the login form.
45
+ * @default 'Welcome Back'
46
+ */
47
+ loginFormTitle?: string;
48
+ /** Subtitle displayed inside the login form. */
49
+ loginFormSubtitle?: string;
50
+ /**
51
+ * Label for the login submit button.
52
+ * @default 'Log In'
53
+ */
54
+ loginButtonText?: string;
55
+ /** Translated labels forwarded to the embedded `<LoginForm>` shown
56
+ * in the dropdown when no user is signed in.
57
+ * See `LoginFormProps.labels` for slugs (email, password, forgotPassword,
58
+ * registerText, registerLink, noAccount, loggingIn, etc.). */
59
+ loginFormLabels?: Record<string, string>;
60
+ /**
61
+ * Show/hide the forgot password link inside the login form.
62
+ * @default true
63
+ */
64
+ displayForgotPasswordLink?: boolean;
65
+ /**
66
+ * Show/hide the register link inside the login form.
67
+ * @default true
68
+ */
69
+ displayRegisterLink?: boolean;
70
+ /**
71
+ * Show/hide the guest checkout link inside the login form.
72
+ * @default false
73
+ */
74
+ displayGuestCheckoutLink?: boolean;
75
+ /** Fires when the guest checkout link is clicked. */
76
+ onGuestCheckoutClick?: () => void;
77
+ /**
78
+ * Error message shown inside the login form.
79
+ * Used in delegation mode (when onLoginSubmit is provided).
80
+ */
81
+ loginError?: string;
82
+ /** Callback fired before the login process starts. */
83
+ beforeLogin?: () => void;
84
+ /**
85
+ * Callback fired after successful self-contained login.
86
+ * Not called in delegation mode — the parent handles the result there.
87
+ */
88
+ afterLogin?: (user: Contact | Customer, accessToken?: string, refreshToken?: string, expiresAt?: string, anonymousCart?: Cart | null) => void;
89
+ /** Anonymous cart snapshot — forwarded to the embedded `LoginForm` so its `afterLogin` receives it. */
90
+ cart?: Cart | null;
91
+ /**
92
+ * Fires when login form is submitted (delegation mode).
93
+ * Parent should handle actual authentication.
94
+ */
95
+ onLoginSubmit?: (email: string, password: string) => void;
96
+ /**
97
+ * Fires when account icon is clicked and showAccountMenuOnClick is false.
98
+ */
99
+ onAccountIconClick?: () => void;
100
+ /**
101
+ * Fires when a menu item is clicked. Receives the href.
102
+ */
103
+ onMenuItemClick?: (href: string) => void;
104
+ /**
105
+ * Fires when logout is clicked.
106
+ */
107
+ onLogoutClick?: () => void;
108
+ /**
109
+ * Fires when "Forgot Password" link is clicked.
110
+ */
111
+ onForgotPasswordClick?: () => void;
112
+ /**
113
+ * Fires when "Register" link is clicked.
114
+ */
115
+ onRegisterClick?: () => void;
116
+ /**
117
+ * Whether login is currently in progress (shows loading state on button).
118
+ * @default false
119
+ */
120
+ loginLoading?: boolean;
121
+ /**
122
+ * Account navigation links shown when user is authenticated.
123
+ * @default [{ label: 'Dashboard', href: '/account' }, ...]
124
+ */
125
+ menuLinks?: AccountMenuLink[];
126
+ /**
127
+ * Labels for the menu UI.
128
+ * Available keys: accountLabel, loginTitle, loginSubtitle, loginButton,
129
+ * signedInAs, logoutLabel, accountMenuTitle.
130
+ * To translate the embedded LoginForm, use `loginFormLabels` instead.
131
+ */
132
+ labels?: Record<string, string>;
133
+ /** Additional class name for the account icon button. */
134
+ iconClassName?: string;
135
+ /** Additional class name for the dropdown menu. */
136
+ menuClassName?: string;
137
+ /**
138
+ * Component variant.
139
+ * - 'dropdown' (default): Header icon with popup menu
140
+ * - 'sidebar': Always-visible vertical navigation for account layout
141
+ */
142
+ variant?: "dropdown" | "sidebar";
143
+ /**
144
+ * Current route path, used in sidebar variant to highlight the active link.
145
+ */
146
+ currentPath?: string;
147
+ loginFormComponent?: Component;
148
+ }
149
+ declare const _default: import('vue').DefineComponent<AccountIconAndMenuProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<AccountIconAndMenuProps> & Readonly<{}>, {
150
+ showAccountMenuOnClick: boolean;
151
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
152
+ export default _default;
@@ -0,0 +1,29 @@
1
+ import { GraphQLClient, Cart } from '@propeller-commerce/propeller-sdk-v2';
2
+ export interface ActionCodeProps {
3
+ /** GraphQL client for the Propeller SDK */
4
+ graphqlClient: GraphQLClient;
5
+ /** The shopping cart used to populate the cart summary data */
6
+ cart: Cart;
7
+ /** Action code block title */
8
+ title?: string;
9
+ /** Labels for the component */
10
+ labels?: Record<string, string>;
11
+ /** Display the option to remove the action code of the shopping cart. Defaults to true. */
12
+ showRemoveCode?: boolean;
13
+ /** Action handler when action code is added to the cart */
14
+ onActionCodeApply?: (code: string, cart: Cart) => void;
15
+ /** Action handler when action code is removed from the cart */
16
+ onActionCodeRemove?: (code: string, cart: Cart) => void;
17
+ /** Action callback method after action code is applied */
18
+ afterActionCodeApply?: (cart: Cart) => void;
19
+ /** Action callback method after action code is removed */
20
+ afterActionCodeRemove?: (cart: Cart) => void;
21
+ /** Configuration object for image filters */
22
+ configuration?: any;
23
+ /** Language code for CartService operations. Defaults to 'NL'. */
24
+ language?: string;
25
+ }
26
+ declare const _default: import('vue').DefineComponent<ActionCodeProps, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {}, string, import('vue').PublicProps, Readonly<ActionCodeProps> & Readonly<{}>, {
27
+ showRemoveCode: boolean;
28
+ }, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
29
+ export default _default;