@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
package/CHANGELOG.md ADDED
@@ -0,0 +1,549 @@
1
+ # Changelog
2
+
3
+ All notable changes to `propeller-v2-vue-ui` are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and the project aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
7
+ once it reaches 1.0. Until then (the `0.x` line) the public API may change
8
+ between minor versions; breaking changes are called out below and in
9
+ [MIGRATION.md](./MIGRATION.md).
10
+
11
+ ## [0.3.14] - 2026-06-09
12
+
13
+ ### Fixed
14
+
15
+ - **`FavoriteListDetails` stuck on "Loading..." forever** when the consumer
16
+ doesn't pass `:graphqlClient` / `:user` / `:configuration` explicitly. Routed
17
+ every infra read through `useInfraProps`.
18
+ - **`PurchaseAuthorizationRequests` rendered no rows** for the same reason.
19
+ Routed every infra read through `useInfraProps`.
20
+
21
+ ## [0.3.13] - 2026-06-09
22
+
23
+ ### Fixed
24
+
25
+ Three more components silently ignored the documented "resolve from
26
+ `<PropellerProvider>`" contract because they read infrastructure off
27
+ `props.*` directly instead of through `useInfraProps`. Consumers that follow
28
+ the contract and DON'T pass these props (e.g. propeller-vue) got broken
29
+ features with no error. This is the same class of bug as 0.3.8 / 0.3.9 and
30
+ brings the Vue package to parity with `propeller-v2-react-ui`, whose
31
+ `ProductSlider` / `ProductGrid` already resolve these via `useInfraProps`:
32
+
33
+ - **`ProductGrid` never fetched on the client.** It passed `props.graphqlClient`
34
+ to `useProductSearch`; with no client the fetch short-circuits, so the grid
35
+ only ever showed SSR-seeded items and went empty on every client-side
36
+ category/search navigation (products "only appeared after a hard refresh").
37
+ Now resolves `graphqlClient`, `configuration`, `user`, `companyId`,
38
+ `language`, `includeTax`, `portalMode` via `useInfraProps`; nested
39
+ ProductCard/ClusterCard pass-throughs read the resolved values too.
40
+ (Complements the 0.3.12 `useProductSearch` watcher-timing fix — that made
41
+ the fetch *fire* on SPA nav; this gives it a *client* to fire with.)
42
+
43
+ - **`ProductSlider` rendered nothing on PDP / cluster pages.** Same root cause:
44
+ `props.graphqlClient` was undefined, so the crossupsell fetch threw, was
45
+ swallowed, and the cross/up-sell sliders never appeared. Now resolves infra
46
+ via `useInfraProps`. `graphqlClient` and `language` props relaxed to optional.
47
+
48
+ - **`AccountIconAndMenu` stayed in its signed-out state forever.** It called
49
+ `useInfraProps` but the template/helpers still read `props.user`, which is
50
+ `undefined` for provider-driven consumers — so the header dropdown kept
51
+ showing the login form after login, and the account-page sidebar variant
52
+ rendered empty. Template + `getUserName()` + the menu-close watch now read a
53
+ script-level `const user = computed(() => infra.user ?? null)`. Also removed
54
+ a stray debug `console.log` from `handleIconClick`.
55
+
56
+ ## [0.3.12] - 2026-06-09
57
+
58
+ ### Fixed
59
+
60
+ - **`useProductSearch` stayed stuck on the previous category's data after
61
+ an SPA navigation between catalog pages.** The composable's input watcher
62
+ fired when `categoryId` changed, but early-returned via
63
+ `if (!isControlled.value) fetchProducts()` because `isControlled` was still
64
+ `true` at that tick — the parent boilerplate's flip from controlled mode
65
+ (SSR-seeded items) to uncontrolled mode (`:products="undefined"`) was queued
66
+ in a separate, later-flushing watcher. Once controlled mode flipped off,
67
+ no input the composable tracked had changed again, so the fetch that
68
+ should have run for the new category never started. The visible symptom
69
+ was an empty "No products found" grid on the destination category until
70
+ the user pressed F5 (which re-ran SSR and re-seeded the new category).
71
+ Added `isControlled` to the watcher's tracked sources so a parent that
72
+ flips controlled mode off re-fires the watcher with the now-uncontrolled
73
+ flag and the deferred fetch runs.
74
+ - **`UserDetails` template tripped vue-tsc in CI** with `TS18048:
75
+ '__VLS_ctx.user' is possibly 'undefined'`. The 0.3.11 fix switched the
76
+ `user` prop to optional and added a script-level `const user = computed(...)`
77
+ resolved via `useInfraProps`, but the template binding for the email field
78
+ still read `{{ user.email }}` unconditionally. Switched to `{{ user?.email }}`,
79
+ matching the optional-chaining pattern the rest of the template
80
+ (`getActiveCompany()?.name`, etc.) already uses.
81
+
82
+ ## [0.3.11] - 2026-06-09
83
+
84
+ ### Fixed
85
+
86
+ - **`UserDetails` crash on the account dashboard** (`TypeError: Cannot read
87
+ properties of undefined (reading 'email')`). Mirror of the 0.3.9
88
+ `CompanySwitcher` fix: the template binds to `user.email` via Vue's
89
+ auto-exposed `props.user`; consumers that follow the documented "resolve
90
+ from `<PropellerProvider>`" contract and don't pass `:user` blew up the
91
+ render. Wired `useInfraProps(props)` + a script-level `const user = computed(...)`
92
+ that overrides the auto-exposure with the provider fallback. Switched
93
+ the `user` prop to optional.
94
+
95
+ ## [0.3.10] - 2026-06-09
96
+
97
+ ### Fixed
98
+
99
+ - **`ProductInfo` rendered an empty image/badges column on every legacy call
100
+ site.** The `useNewShell` heuristic — which decides whether to render the
101
+ composable PDP shell or the legacy SKU+title block — included the nine
102
+ Boolean `show*` props in its presence check (`props[k] !== undefined`).
103
+ Vue 3 runtime-normalizes any declared Boolean prop the parent doesn't pass
104
+ to `false`, not `undefined`, so every consumer doing
105
+ `<ProductInfo :product="…" />` flipped the heuristic to the new shell.
106
+ Inside the new shell the per-slot `v-if="show* !== false"` then evaluated
107
+ `false !== false` → `false`, so the image, badges, favourite, price, stock,
108
+ add-to-cart, bundles, bulk-prices and surcharges sections silently
109
+ skipped their default content — the visible symptom was an empty
110
+ `propeller-product-info__media` column on the PDP. Removed the Boolean
111
+ `show*` keys from `NEW_SHELL_KEYS`; only `*Component` injection props now
112
+ opt the consumer into the new shell. The per-section `show*` flags still
113
+ work inside the new shell once it is opted into.
114
+
115
+ ## [0.3.9] - 2026-06-09
116
+
117
+ ### Fixed
118
+
119
+ - **`CompanySwitcher` crash on first render after login** (`TypeError: Cannot
120
+ read properties of undefined (reading 'companies')`). The component read
121
+ `props.user.companies` directly without falling back to the propellerVue
122
+ plugin scope or guarding against `user === undefined`, so any consumer that
123
+ relied on the documented "resolved from `<PropellerProvider>`" contract
124
+ blew up Vue's render. Wired `useInfraProps(props)`, switched the `user`
125
+ prop to optional, and added a `(infra.user ?? props.user)` guard.
126
+ - **`CartIconAndSidebar` silent no-op + reactivity gaps.** Same provider
127
+ gap: `useCart` received `props.graphqlClient!` (undefined → SDK crash on
128
+ any drawer mutation), and `showCheckoutButton` / `showRequestAuthorizationButton`
129
+ + currency formatting all read `props.user` / `props.companyId` /
130
+ `props.currency` directly. Routed every infra read through `useInfraProps`
131
+ so AppHeader can mount the drawer with just `:cart="..."` and have
132
+ everything else resolve.
133
+
134
+ ## [0.3.8] - 2026-06-09
135
+
136
+ ### Fixed
137
+
138
+ - **`LoginForm`, `AccountIconAndMenu`, `AddToCart`, `CartItem` silently no-op
139
+ when the consumer doesn't pass `:graphqlClient` explicitly.** These four
140
+ components were reading `props.graphqlClient` directly instead of resolving
141
+ it through `useInfraProps` / `useResolvedProps`, so the value never fell
142
+ back from the `propellerVue` plugin scope. The login button submitted
143
+ nothing, PDP "Add to cart" did nothing, and the cart row +/- / delete
144
+ buttons did nothing — every handler hit a `if (!props.graphqlClient) return;`
145
+ guard.
146
+ - `LoginForm.vue`: added `useInfraProps(props)` and routed `useAuth` +
147
+ the submit guard through it.
148
+ - `AccountIconAndMenu.vue`: added `useInfraProps(props)` and passes
149
+ `infra.graphqlClient` to the embedded `<LoginForm>`.
150
+ - `AddToCart.vue`: added `useInfraProps(props)` and routes `useCart`
151
+ + the submit guard through it.
152
+ - `CartItem.vue`: extended `RESOLVE_SPEC` with the Tier 1 infra keys
153
+ (`graphqlClient`, `user`, `companyId`, `configuration`, `language`,
154
+ `currency`, `includeTax`) so the spec matches `ProductCard` /
155
+ `ClusterCard`. Direct-prop precedence preserved.
156
+
157
+ ## [0.3.7] - 2026-06-08
158
+
159
+ ### Fixed
160
+
161
+ - **SSR crash on catalog pages when consumer omits `:configuration` prop.**
162
+ `ProductCard.getProductUrl()`, `ClusterCard.getClusterUrl()`, and
163
+ `Breadcrumbs.getCategoryUrl()` dereferenced `props.configuration.urls`
164
+ without optional chaining, throwing `Cannot read properties of undefined
165
+ (reading 'urls')` at SSR time. Guarded all three with `?.urls?.` and a
166
+ `?? '#'` fallback so the components render harmlessly when the consumer
167
+ hasn't wired `:configuration` through (e.g. on `<ProductGrid>` cards
168
+ inside SearchView / CategoryView). Matches the guard `CartItem` already
169
+ had. No API change.
170
+
171
+ ## [0.3.6] - 2026-06-04
172
+
173
+ ### Changed
174
+
175
+ - **SDK dependency switched from GitHub tarball to npm.** Both the
176
+ `peerDependencies` entry and the `devDependencies` test pin now point
177
+ at `@propeller-commerce/propeller-sdk-v2@^0.11.1` instead of
178
+ `github:propeller-commerce/propeller-sdk-v2#master`. All 121 source +
179
+ test files (incl. `.vue` SFCs) renamed accordingly
180
+ (`from 'propeller-sdk-v2'` →
181
+ `from '@propeller-commerce/propeller-sdk-v2'`).
182
+
183
+ ### Dependencies
184
+
185
+ - Bumps `propeller-v2-core-ui` to 0.2.4 (its own SDK switch to npm).
186
+
187
+ ### Why
188
+
189
+ The SDK is now published on npm as a properly scoped package. Pinning
190
+ via npm removes the GitLab→GitHub mirror dependency from the install
191
+ chain and gives consumers semver ranges instead of a moving master tip.
192
+ Behaviour is unchanged.
193
+
194
+ ## [0.3.5] - 2026-06-04
195
+
196
+ ### Fixed
197
+
198
+ - **`CartItem` now resolves product / bundle / crossupsell / cluster
199
+ option names via `getLanguageString`** (from
200
+ `propeller-v2-core-ui@0.2.3`), matching the active language and
201
+ walking the localised entries for the first non-empty value before
202
+ falling back to `'Product'` / `'Option'`. Previously each template
203
+ binding and helper hard-coded `names?.[0]?.value || 'Product'`, which
204
+ always picked the first SDK entry regardless of language and rendered
205
+ blank when that first entry's `value` was empty. Cart pages now show
206
+ the correct localised name and never collapse to invisible rows on
207
+ datasets with sparse localisation.
208
+
209
+ ### Dependencies
210
+
211
+ - Bumps `propeller-v2-core-ui` to 0.2.3 (the resolver fix that powers
212
+ the above).
213
+
214
+ ## [0.3.4] - 2026-06-03
215
+
216
+ **Menu pre-fetch fix.** `<Menu :tree="...">` previously treated *any*
217
+ array (including `[]`) as a successful host pre-fetch and locked itself
218
+ into the empty state — no client-side fallback fetch, no recovery.
219
+
220
+ This bit SSR setups whose `lib/server.ts` `fetchMenu` swallows errors
221
+ and returns `[]` by design (so a transient backend hiccup doesn't break
222
+ the whole render). The consumer stored the empty result in its menu
223
+ store, AppHeader passed `:tree="[]"`, and `<Menu>` showed
224
+ "No categories found" with no way out, even after the backend recovered.
225
+
226
+ ### Changed
227
+
228
+ - `hasPrefetchedTree` now requires `props.tree` to be a NON-empty array.
229
+ `[]` is no longer treated as a pre-fetch; the component falls back to
230
+ its internal `useMenu` fetch, which can succeed where the SSR
231
+ pre-fetch failed. A legitimately-empty backend still renders the
232
+ empty state because the client fetch also returns `[]`.
233
+
234
+ ## [0.3.2] - 2026-06-03
235
+
236
+ **Reactivity fix** for the provider snapshot. After 0.3.1 fixed the
237
+ `inject()`-inside-`computed` bug, components that read infra props via
238
+ `useInfraProps()` still went stale on provider updates. Symptom:
239
+ `AccountIconAndMenu` rendered the anonymous state until the page was
240
+ refreshed after login — `auth.user` updated on the store and propagated
241
+ into `<PropellerProvider :user>`, but the package-side `AccountIconAndMenu`
242
+ kept reading the old value.
243
+
244
+ Root cause: `usePropellerContext()` returned `{ ...deps, ...scope, userMode }`
245
+ — spreading the reactive `scope` snapshotted its current values into a
246
+ plain object. `useInfraProps()` (correctly) caches that object at setup,
247
+ so every subsequent infra read was reading a frozen copy and missed all
248
+ provider updates.
249
+
250
+ ### Changed
251
+
252
+ - **`usePropellerContext()` / `useRequiredPropellerContext()`** now build
253
+ the composite via getters that pierce through to the live reactive
254
+ scope (user, companyId, language, includeTax, portalMode, userMode).
255
+ Consumers that capture the returned object at setup keep getting live
256
+ reads — login / language switch / VAT toggle propagate without a
257
+ refresh. No call-site changes required.
258
+
259
+ ### Verification
260
+
261
+ - `vue-tsc --noEmit` clean.
262
+ - `npm run test` — 183 tests pass unchanged (none asserted on the
263
+ snapshot semantics, so no test churn).
264
+ - Manual smoke: scaffolded `vue-shop` from the accelerator + logged in
265
+ via AccountIconAndMenu's embedded form → menu re-renders to the
266
+ authenticated layout on the same page tick, no refresh required.
267
+
268
+ ## [0.3.1] - 2026-06-02
269
+
270
+ **Critical fix** for the 0.3.0 retrofit. The previous release wrapped
271
+ `useInfraProps(props)` in `computed(() => useInfraProps(props))` in
272
+ every component. The composable internally calls Vue's `inject()`, which
273
+ only works inside `setup()`. When the computed re-ran later (during a
274
+ click handler, an effect, or any reactive recalc), `inject()` returned
275
+ the default value (`null`) and the component silently lost its provider
276
+ context — graphqlClient, user, language, configuration all undefined.
277
+
278
+ Symptom in 0.3.0: **anonymous "Add to cart" did nothing**. The
279
+ `handleAddToCart` early-returns when `infra.value.graphqlClient` is
280
+ falsy. Logged-in flows that happened to capture the resolved infra on
281
+ the very first synchronous read during setup looked fine until any
282
+ reactive dependency invalidated the computed.
283
+
284
+ ### Changed
285
+
286
+ - **`useInfraProps()`** now resolves the `PropellerContext` exactly once
287
+ at setup time (where `inject()` is legal) and returns a `reactive`
288
+ object whose infra-key reads forward to either the live prop or the
289
+ ctx snapshot. Reactivity is preserved (the provider scope is itself
290
+ reactive) without a wrapping computed.
291
+ - **All 51 retrofitted components** change from
292
+ `const infra = computed(() => useInfraProps(props))` →
293
+ `const infra = useInfraProps(props)`, and every `infra.value.X` →
294
+ `infra.X`. No behaviour change on the happy path; the previously
295
+ broken late-read path now works.
296
+
297
+ ### Verification
298
+
299
+ - `vue-tsc --noEmit` clean.
300
+ - 22 / 22 vitest pass.
301
+ - `npm run build` emits identical dts shape.
302
+ - Browser repro of anonymous AddToCart on the cluster page in
303
+ propeller-vue now logs `infra.graphqlClient` truthy and reaches
304
+ `addItem` → `initCart` → cart creation.
305
+
306
+ ## [0.3.0] - 2026-06-02
307
+
308
+ Wires every component into the existing `<PropellerProvider>` via the
309
+ `useInfraProps()` composable. Consumers can now omit Tier 1 / Tier 2
310
+ infra props (`graphqlClient`, `services`, `user`, `companyId`,
311
+ `language`, `includeTax`, `currency`, `configuration`, `portalMode`) and
312
+ the component resolves them from the provider — bringing the Vue
313
+ package in line with what React UI already did in 30 of its 66
314
+ components.
315
+
316
+ Before 0.3.0, only `CartBonusItems` and `OrderBonusItems` honoured the
317
+ provider; the other 50 components required every infra prop to be
318
+ passed by the consumer at every render site. After 0.3.0, all 52
319
+ components resolve from the provider as a fallback. Explicit props still
320
+ win — call sites that pass values keep their previous behaviour
321
+ unchanged.
322
+
323
+ ### Changed
324
+
325
+ - **52 components** now wrap their `props` through
326
+ `useInfraProps(props)` in a `computed`, matching the canonical
327
+ `CartBonusItems.vue` pattern. The full list:
328
+ `AccountIconAndMenu`, `ActionCode`, `AddToCart`, `AddToFavorite`,
329
+ `AddressSelector`, `Breadcrumbs`, `CartCarriers`, `CartIconAndSidebar`,
330
+ `CartItem`, `CartPaymethods`, `CartSummary`, `CategoryDescription`,
331
+ `CategoryShortDescription`, `ClusterCard`, `ClusterInfo`,
332
+ `ClusterOptions`, `CompanySwitcher`, `FavoriteListDetails`,
333
+ `FavoriteListItem`, `FavoriteLists`, `ForgotPassword`, `GridFilters`,
334
+ `GridToolbar`, `ItemsOverview`, `LoginForm`, `Menu`, `OrderActions`,
335
+ `OrderItemCard`, `OrderList`, `OrderSummary`, `OrderTotals`,
336
+ `ProductBulkPrices`, `ProductBundles`, `ProductCard`,
337
+ `ProductDescription`, `ProductDownloads`, `ProductGrid`, `ProductInfo`,
338
+ `ProductPrice`, `ProductShortDescription`, `ProductSlider`,
339
+ `ProductSpecifications`, `ProductTabs`, `ProductVideos`, `QuoteActions`,
340
+ `PurchaseAuthorizationConfigurator`, `PurchaseAuthorizationRequests`,
341
+ `RegisterForm`, `SearchBar`, `UserDetails`.
342
+ - Template forwards inside `ProductCard.vue` and `ProductGrid.vue` that
343
+ passed `:foo="props.X"` to child components now pass `:foo="infra.X"`
344
+ so the explicit-or-provider value flows uniformly down the tree.
345
+ - Three components grew a shadow `const X = computed(() => infra.value.X)`
346
+ binding (`AccountIconAndMenu`, `AddToFavorite`, `UserDetails`)
347
+ because their templates reference the infra value bare
348
+ (`v-if="user"`, `{{ user.email }}`) and Vue's setup-binding lookup
349
+ needs a setup-scope ref to read from.
350
+
351
+ ### Migration
352
+
353
+ Existing consumers that pass all infra props keep working unchanged —
354
+ the resolver's contract is "explicit wins, otherwise provider, otherwise
355
+ undefined." Consumers should now feel free to drop redundant prop passes
356
+ where `<PropellerProvider>` wraps the subtree.
357
+
358
+ A follow-up cleanup PR in `propeller-vue` will prune the ~245 redundant
359
+ prop-lines its views currently pass, starting with `ProductDetailView`,
360
+ `CategoryView`, and `CartView`.
361
+
362
+ ### Verification
363
+
364
+ - `vue-tsc --noEmit` clean.
365
+ - 22 / 22 vitest tests pass unchanged.
366
+ - `npm run build` emits identical dts shape (infra prop types were
367
+ already optional in 0.2.0; the change is purely internal wiring).
368
+
369
+ ## 0.2.3
370
+
371
+ ### Fixed
372
+
373
+ - `AccountIconAndMenu` no longer forwards its own `labels` (which contains menu-UI slugs like `accountLabel`, `logoutLabel`) to the embedded `<LoginForm>` — that previously caused LoginForm's `email`, `password`, `forgotPassword` strings to fail translation. Use the new `loginFormLabels?` prop instead.
374
+
375
+ ### Added
376
+
377
+ - `AccountIconAndMenu`: new `loginFormLabels?: Record<string, string>` prop, forwarded to the embedded `<LoginForm>`. Lets consumers pass the LoginForm namespace's translations through to the dropdown sign-in form.
378
+
379
+ ## 0.2.2
380
+
381
+ ### Added
382
+
383
+ - `ProductCard` / `ProductGrid` / `ProductSlider`: new `priceLabels?: Record<string, string>` prop, forwarded through to the embedded `<ProductPrice>` display inside each card. Lets consumers translate `inclTax` / `exclTax` / `loginToSeePrices` strings on grid/slider pages without per-card wiring. `ClusterCard` is intentionally unchanged — it builds its own price span and doesn't render `<ProductPrice>`.
384
+
385
+ ## 0.2.1
386
+
387
+ ### Added
388
+
389
+ - `ProductGrid` / `ProductSlider`: new props `productCardLabels?`, `clusterCardLabels?`, `addToCartLabels?` for forwarding translations to embedded `<ProductCard>` / `<ClusterCard>` / inner `<AddToCart>`. Mirrors the existing `stockLabels?` pattern.
390
+ - `PriceToggle`: new `labels?: Record<string, string>` prop with slugs `pricesLabel`, `inclVat`, `exclVat`. Previously these strings were hardcoded.
391
+ - `OrderList`: filter column field labels and sort-field dropdown options now route through the `labels` prop. Column labels use slug `col<Capitalized>` (e.g. `colTerm`, `colCreatedAt`); sort options use the enum value as the slug. All fallbacks preserve existing English behavior, so the change is non-breaking.
392
+
393
+ ### Fixed
394
+
395
+ - `ProductSlider` no longer forwards its own `labels` (slider-UI slugs) to embedded `ClusterCard` / `ProductCard` — that previously caused card-level strings to fail translation. Use the new `clusterCardLabels?` / `productCardLabels?` props instead.
396
+
397
+ ## [0.2.0] - 2026-06-01
398
+
399
+ Adds shop-mode-aware user gating. Mirrors the React UI change. Existing
400
+ public API is unchanged; new fields are optional and default to
401
+ backward-compatible behaviour.
402
+
403
+ ### Added
404
+
405
+ - **`shopMode?: ShopMode`** on `PropellerScope`. Declares whether the shop
406
+ is `'b2b'`, `'b2c'`, or `'hybrid'`. Defaults to `'hybrid'` when omitted
407
+ so existing call sites keep their current branching semantics (any
408
+ logged-in Contact treated as B2B).
409
+ - **Derived `userMode: UserMode`** on `PropellerInfra`. Computed via
410
+ `deriveUserMode(user, shopMode)` from `propeller-v2-core-ui`. Values:
411
+ `'anonymous' | 'b2b' | 'b2c'`. B2B-gated UI (company switcher, B2B
412
+ side-nav items, quote/authorization affordances) should read this
413
+ instead of re-deriving from `isContact(user)` ad hoc.
414
+ - **`useUserMode()` composable**. Direct read of `userMode` for components
415
+ that only need that one signal.
416
+
417
+ ### Why this matters
418
+
419
+ Hybrid shops need a single, consistent gate that says "is the current
420
+ viewer behaving as B2B or B2C?" Previously every B2B-gated component
421
+ re-derived this from `isContact(user)` ad hoc, which was correct but
422
+ duplicated and ignored the shop's `mode` (a B2C shop that somehow had a
423
+ Contact session would still light up the B2B surface). Centralising the
424
+ derivation eliminates the duplication and makes the shop mode authoritative.
425
+
426
+ ### Requires
427
+
428
+ - `propeller-v2-core-ui` ≥ 0.2.0 (for `deriveUserMode`, `ShopMode`,
429
+ `UserMode`).
430
+
431
+ ---
432
+
433
+ ## [0.1.0] — Unreleased
434
+
435
+ First version of the package. Extracted from the `propeller-vue`
436
+ storefront so the Propeller Commerce Vue surface can be consumed as a
437
+ standalone library. The Vue mirror of `propeller-v2-react-ui`. Not yet
438
+ published to a registry — consumed via a `file:` link or `github:` URL
439
+ during stabilization.
440
+
441
+ ### Added
442
+
443
+ - **Initial extraction.** 60 components, the 15 Vue composables, the
444
+ runtime-agnostic `composables/shared/` layer (utilities and domain
445
+ types), and the three reactive shared wrappers (`usePagination`,
446
+ `useServiceFetch`, `useUserIdentity`) moved into this package from
447
+ `propeller-vue`.
448
+ - **Build pipeline.** Vite library mode (`@vitejs/plugin-vue` +
449
+ `vite-plugin-dts`) produces dual ESM + CJS bundles with `.d.ts`
450
+ declarations. Unlike the React package there is no `"use client"`
451
+ banner — Vue has no such directive.
452
+ - **Three entry points.** `propeller-v2-vue-ui` (components, composables,
453
+ the provider, `createServices`, `toPlain`); `propeller-v2-vue-ui/shared`
454
+ (pure TS — `createServices`, `toPlain`, formatters, helpers, all domain
455
+ types — safe to import from a Nuxt server context or a build script);
456
+ and `propeller-v2-vue-ui/pure` (SSR-safe presentational components —
457
+ `ProductPrice`, `ItemStock`, `GridTitle`, `OrderTotals`, … — with no
458
+ composables and no browser APIs, cheap to render into an SSR shell).
459
+ Mirrors `propeller-v2-react-ui`'s `/pure` entry component-for-component.
460
+ - **Precompiled stylesheet** (`dist/styles.css`). The package's Tailwind
461
+ v4 classes are compiled to vanilla CSS at build time and shipped.
462
+ Consumers import it once and do **not** need Tailwind in their own
463
+ project. Token names and BEM hook class names are kept identical to
464
+ `propeller-v2-react-ui`.
465
+ - **Three styling override surfaces** — theme tokens (CSS variables), BEM
466
+ hooks, and per-instance `class`. Documented in [STYLING.md](./STYLING.md).
467
+ - **`providePropeller` / `usePropellerContext`** — the single integration
468
+ point, a `provide`/`inject` provider. `providePropeller(value)` installs
469
+ the `PropellerInfra` (carrying `graphqlClient`, `services`, `user`,
470
+ `companyId`, `language`, `includeTax`, `currency`, `configuration`,
471
+ `portalMode`). Imports zero host code.
472
+ - **`provideProductGridConfig` / `useProductGridConfig`** — Tier-2 grid
473
+ config provider used by `ProductGrid` to collapse ~20 cascaded props on
474
+ `ProductCard` / `ClusterCard`.
475
+ - **`createServices(client)`** — factory that builds the typed `Services`
476
+ bundle (`product`, `cart`, `user`, `order`, …) keyed to a
477
+ consumer-built `GraphQLClient`. Memoized per client via `WeakMap`.
478
+ Copied verbatim from `propeller-v2-react-ui` — pure, framework-agnostic.
479
+ - **`toPlain(value)`** — recursively strips the SDK's underscore-prefixed
480
+ backing fields from class instances.
481
+ - **`useServices()`** — reads the `Services` bundle from the provider;
482
+ throws a clear error when used outside `providePropeller()`.
483
+ - **`useInfraProps()` / `useResolvedProps()`** — resolve component props
484
+ against the provider (and the grid config) with explicit-prop-wins
485
+ precedence. New to the Vue surface (the React package had them; the Vue
486
+ composables did not).
487
+ - Public-grade documentation: [README.md](./README.md),
488
+ [STYLING.md](./STYLING.md), [TECH.md](./TECH.md),
489
+ [CONTRIBUTING.md](./CONTRIBUTING.md), [MIGRATION.md](./MIGRATION.md),
490
+ [SECURITY.md](./SECURITY.md), and an MIT `LICENSE`.
491
+ - **Unit tests.** Vitest suite covering the pure-logic surface — `src/lib/`
492
+ (`createServices`, `toPlain`) and the framework-free shared utilities.
493
+ 13 test files, 183 tests, ported from `propeller-v2-react-ui`.
494
+ - **CI pipeline** (`.gitlab-ci.yml`). A `verify` stage (typecheck, unit
495
+ tests + coverage, build), a `downstream` stage that builds the package
496
+ and runs `propeller-vue`'s Playwright e2e suite against it (the
497
+ component regression gate), and a `mirror` stage that mirrors to the
498
+ public GitHub repo.
499
+ - **Storybook** (`.storybook/`, Storybook 9 + `@storybook/vue3-vite`). A
500
+ story per component (60 total), rendering each in isolation against
501
+ fixture data and a mock provider. Mock foundation in `src/__mocks__/`
502
+ (`fixtures.ts`, `mockServices.ts`, `decorators.ts`).
503
+ - **Documentation site** (`docs/`). A self-contained Docusaurus 3 app —
504
+ hand-written MDX guides, a six-page **API integration** section
505
+ (`guides/api/`) explaining how the composables reach the GraphQL
506
+ backend domain by domain, and a **generated TypeDoc API reference**
507
+ (`content/api/`, rebuilt by `npm run gen:api` from the package's
508
+ pure-TS headless surface — composables, provider, SDK seam, utilities
509
+ and types). The `.vue` components' prop tables stay in Storybook, since
510
+ TypeDoc cannot parse Single-File Components. Not published, not in the
511
+ package build.
512
+
513
+ - **`Menu`: optional pre-fetched `tree` prop.** When the host supplies
514
+ `tree: MenuCategory[]`, `Menu` skips its internal `useMenu` fetch
515
+ entirely and renders the tree directly — mirroring the
516
+ `ProductGrid.products` opt-in. Lets host apps fetch the category tree
517
+ server-side (e.g. in `entry-server.ts`'s always-on prefetch) and have
518
+ the menu HTML land in the initial response. Omitting the prop preserves
519
+ the legacy client-side fetch behaviour — no breaking change.
520
+ - **`MenuCategory` type exported from `/shared`.** Type-only re-export so
521
+ server modules (e.g. a host's `lib/server.ts`) can build the tree without
522
+ pulling the Vue composable's runtime into the server bundle.
523
+
524
+ ### Changed
525
+
526
+ - **Decoupled the SDK seam from the host (vs the in-app original).** Every
527
+ composable previously did `new XxxService(graphqlClient)` inline (57
528
+ call sites). They now resolve services through the memoized
529
+ `createServices(graphqlClient)` factory. The package ships no
530
+ `graphqlClient` singleton, no hardcoded endpoint, and reads no
531
+ `import.meta.env`. The consumer constructs its own `GraphQLClient`,
532
+ calls `createServices(client)`, and installs both via
533
+ `providePropeller`.
534
+ - **Removed host coupling from components.** `ProductCard` no longer
535
+ imports `vue-router` (navigation via the `onProductClick` callback prop,
536
+ with a native location fallback). `SearchBar` and `CartIconAndSidebar`
537
+ no longer import `localizeHref` from the host config — URLs come from
538
+ the `configuration` prop's url builders. `AddToCart` and
539
+ `CartIconAndSidebar` use a plain `<a>` instead of `<router-link>`.
540
+
541
+ ### Fixed
542
+
543
+ - **~186 pre-existing type errors.** The original `propeller-vue` excluded
544
+ `components/propeller/` from its `vue-tsc` run, so the 60 components were
545
+ never type-checked. This package type-checks the whole surface;
546
+ `vue-tsc --noEmit` is clean. The bulk were inline event handlers using
547
+ `e.target.value` on the bare `EventTarget` type (fixed with an
548
+ `HTMLInputElement` cast) plus assorted SDK type-name and narrowing
549
+ corrections.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Propeller Commerce
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.