@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/MIGRATION.md ADDED
@@ -0,0 +1,178 @@
1
+ # Migration guide
2
+
3
+ ## `Menu`: optional pre-fetched `tree` prop (additive)
4
+
5
+ **When:** during `0.1.0` stabilization (pre-publish).
6
+
7
+ `Menu` now accepts an optional `tree?: MenuCategory[]` prop. When supplied,
8
+ the component skips its internal `useMenu` fetch and renders the tree
9
+ directly — mirroring the long-standing `ProductGrid.products` opt-in.
10
+
11
+ **No migration required.** Omitting the prop preserves the legacy
12
+ client-side fetch behaviour. This is purely opt-in for hosts that want to
13
+ move the category tree fetch into the SSR layer (e.g. propeller-vue's
14
+ `entry-server.ts` always-on prefetch) so the menu HTML lands in the initial
15
+ response and the host can attach cache tags via the SDK's `headers` config.
16
+
17
+ ### Recommended pattern for Vue SSR consumers
18
+
19
+ ```ts
20
+ // entry-server.ts — Vue 3 + Vite SSR (or any Node-side render hook)
21
+ import { fetchMenu, getAnonymousInfra } from '@/lib/server'
22
+ import { useMenuStore } from '@/stores/menu'
23
+
24
+ // Inside the render flow, before renderToString:
25
+ const tree = await fetchMenu(getAnonymousInfra(), BASE_CATEGORY_ID)
26
+ useMenuStore().setTree(tree)
27
+ ```
28
+
29
+ ```vue
30
+ <!-- AppHeader.vue or wherever the menu lives -->
31
+ <script setup lang="ts">
32
+ import { computed } from 'vue'
33
+ import { Menu as PropellerMenu } from 'propeller-v2-vue-ui'
34
+ import { useMenuStore } from '@/stores/menu'
35
+
36
+ const menuStore = useMenuStore()
37
+ const menuTreeProp = computed(() => menuStore.tree ?? undefined)
38
+ </script>
39
+
40
+ <template>
41
+ <PropellerMenu
42
+ :graphqlClient="graphqlClient"
43
+ :categoryId="BASE_CATEGORY_ID"
44
+ :language="lang"
45
+ :tree="menuTreeProp"
46
+ :onMenuItemClick="handleClick"
47
+ />
48
+ </template>
49
+ ```
50
+
51
+ `MenuCategory` is exported from `/shared` (type-only) so the server-side
52
+ fetch helper can build the tree without pulling the Vue composable's
53
+ runtime into the server bundle.
54
+
55
+ See [TECH.md §7 "Pre-fetched data prop pattern"](./TECH.md) for the broader
56
+ context and the same pattern as it applies to `ProductGrid`.
57
+
58
+ ---
59
+
60
+ ## From in-app components → the `propeller-v2-vue-ui` package
61
+
62
+ Before this package existed, the Propeller Commerce Vue components and
63
+ composables lived directly inside the `propeller-vue` storefront under
64
+ `src/components/propeller/` and `src/composables/`. They are now a
65
+ standalone package. This guide is for moving a consumer onto it.
66
+
67
+ ### 1. Install the package
68
+
69
+ ```bash
70
+ npm install propeller-v2-vue-ui propeller-sdk-v2 --install-links
71
+ ```
72
+
73
+ `propeller-sdk-v2` is a **peer dependency** — install it yourself so the
74
+ package and your app share one SDK instance. `--install-links` is needed
75
+ on Windows for `file:` / `github:` installs (a symlinked install breaks the
76
+ nested `propeller-sdk-v2` resolution).
77
+
78
+ ### 2. Import the stylesheet
79
+
80
+ ```ts
81
+ // main.ts
82
+ import 'propeller-v2-vue-ui/styles.css';
83
+ ```
84
+
85
+ Import it once, at your app entry. You no longer compile the components'
86
+ Tailwind classes yourself — the package ships a precompiled stylesheet.
87
+
88
+ ### 3. Build the SDK seam and install the provider
89
+
90
+ The biggest change: the package ships **no `graphqlClient` singleton**.
91
+ Previously composables imported a shared client from `src/lib/api.ts` and
92
+ did `new XxxService(graphqlClient)` internally. Now:
93
+
94
+ ```ts
95
+ // src/lib/api.ts — YOUR app keeps this file; it just changes shape
96
+ import { GraphQLClient } from 'propeller-sdk-v2';
97
+ import { createServices } from 'propeller-v2-vue-ui';
98
+
99
+ export const graphqlClient = new GraphQLClient({
100
+ endpoint: import.meta.env.VITE_GRAPHQL_ENDPOINT || '/api/graphql',
101
+ apiKey: import.meta.env.VITE_API_KEY || '',
102
+ timeout: 30_000,
103
+ });
104
+
105
+ export const services = createServices(graphqlClient);
106
+ ```
107
+
108
+ Then install the provider once, high in the tree (root `App.vue`):
109
+
110
+ ```vue
111
+ <script setup lang="ts">
112
+ import { providePropeller } from 'propeller-v2-vue-ui';
113
+ import { graphqlClient, services } from '@/lib/api';
114
+ import { useAuthStore } from '@/stores/auth';
115
+ import { useLanguageStore } from '@/stores/language';
116
+ // …
117
+
118
+ const auth = useAuthStore();
119
+ const lang = useLanguageStore();
120
+
121
+ providePropeller({
122
+ graphqlClient,
123
+ services,
124
+ user: auth.user,
125
+ companyId: undefined,
126
+ language: lang.language,
127
+ includeTax: false,
128
+ currency: '€',
129
+ configuration: config,
130
+ portalMode: 'open',
131
+ });
132
+ </script>
133
+ ```
134
+
135
+ ### 4. Update component imports
136
+
137
+ ```diff
138
+ - import ProductCard from '@/components/propeller/ProductCard.vue';
139
+ + import { ProductCard } from 'propeller-v2-vue-ui';
140
+ ```
141
+
142
+ The 60 component names are unchanged.
143
+
144
+ ### 5. Composables
145
+
146
+ Composable signatures are unchanged — they still accept a `graphqlClient`
147
+ option. Internally they now route through `createServices`. Update imports:
148
+
149
+ ```diff
150
+ - import { useCart } from '@/composables/useCart';
151
+ + import { useCart } from 'propeller-v2-vue-ui';
152
+ ```
153
+
154
+ The three framework-agnostic cart helpers (`initCart`, `fetchActiveCart`,
155
+ `mergeAnonymousCart`) take a `services` bundle in their config rather than
156
+ a raw `graphqlClient`.
157
+
158
+ ### 6. URL builders and routing
159
+
160
+ `ProductCard` no longer depends on `vue-router`. Pass an `onProductClick`
161
+ callback for SPA navigation:
162
+
163
+ ```vue
164
+ <ProductCard :product="p" :onProductClick="(prod) => router.push(productUrl(prod))" />
165
+ ```
166
+
167
+ `SearchBar` and `CartIconAndSidebar` build result URLs from the
168
+ `configuration.urls` builders you pass in — supply
169
+ `configuration.urls.getProductUrl` / `getClusterUrl` if you need
170
+ language-prefixed or custom paths.
171
+
172
+ ### What you keep in your own app
173
+
174
+ - `src/lib/api.ts` — the `GraphQLClient` construction and `createServices`
175
+ call. Endpoint, env-var names, timeout — all consumer-specific.
176
+ - Any server-side (Nuxt) data fetching — the package has no `/server`
177
+ entry.
178
+ - Routing, Pinia stores, the app shell.
package/README.md ADDED
@@ -0,0 +1,282 @@
1
+ # propeller-v2-vue-ui
2
+
3
+ A Vue 3 component library for **Propeller Commerce** storefronts. It ships
4
+ ready-made e-commerce UI — product cards, grids, carts, checkout, account
5
+ pages — together with headless composables that talk to the Propeller
6
+ GraphQL API, plus the shared utilities and types those parts build on.
7
+
8
+ It is the Vue mirror of [`propeller-v2-react-ui`](https://github.com/propeller-commerce/propeller-v2-react-ui):
9
+ same component set, same SDK seam, same styling contract.
10
+
11
+ The package is framework-flexible within the Vue ecosystem: it runs in any
12
+ Vue 3.4+ app — a Vite SPA, a Nuxt 3 app — and ships its own precompiled
13
+ stylesheet, so you do **not** need Tailwind in your project to use it.
14
+
15
+ ## Table of contents
16
+
17
+ - [Installation](#installation)
18
+ - [Peer dependencies](#peer-dependencies)
19
+ - [Entry points](#entry-points)
20
+ - [Core concept: the SDK seam](#core-concept-the-sdk-seam)
21
+ - [Quick start](#quick-start)
22
+ - [The Propeller provider](#the-propeller-provider)
23
+ - [Using components](#using-components)
24
+ - [Using composables](#using-composables)
25
+ - [Styling](#styling)
26
+ - [API reference](#api-reference)
27
+ - [Building from source](#building-from-source)
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install propeller-v2-vue-ui propeller-sdk-v2 --install-links
33
+ ```
34
+
35
+ `propeller-sdk-v2` is a **peer dependency** — install it yourself so the
36
+ package and your application share a single SDK instance. `--install-links`
37
+ is needed on Windows for `file:` / `github:` installs.
38
+
39
+ ## Peer dependencies
40
+
41
+ | Package | Version | Required |
42
+ | ------------------ | -------- | -------- |
43
+ | `vue` | `>=3.4` | Yes |
44
+ | `propeller-sdk-v2` | `*` | Yes |
45
+
46
+ There is no dependency on Nuxt or `vue-router` — nothing in the package
47
+ imports them. A plain Vite + Vue app works out of the box.
48
+
49
+ ## Entry points
50
+
51
+ | Import path | Contents |
52
+ | ----------------------------- | ----------------------------------------------------- |
53
+ | `propeller-v2-vue-ui` | Components, composables, the provider, `createServices`, `toPlain` |
54
+ | `propeller-v2-vue-ui/shared` | `createServices`, `toPlain`, formatters, helpers, types — pure TS |
55
+ | `propeller-v2-vue-ui/pure` | SSR-safe presentational components — no composables, no browser APIs |
56
+ | `propeller-v2-vue-ui/styles.css` | The precompiled stylesheet |
57
+
58
+ The `/shared` entry is plain TypeScript with no Vue dependency — import the
59
+ pure helpers and `createServices` from there when you want them outside a
60
+ component (a Nuxt server route, a build script, a test).
61
+
62
+ The `/pure` entry re-exports a curated subset of components that are
63
+ guaranteed SSR-safe: no composable calls, no `window`/`localStorage`/`document`
64
+ access, no `onMounted` fetching. Render them directly into the static shell
65
+ of a server-rendered page with no hydration mismatch. Mirrors the React
66
+ package's `/pure` entry component-for-component.
67
+
68
+ ## Core concept: the SDK seam
69
+
70
+ This is the one architectural idea to understand before using the package.
71
+
72
+ **The package ships no GraphQL client** and **no hardcoded API endpoint.**
73
+ GraphQL transport is application-specific — a Vite SPA hits the API through
74
+ its dev proxy; a Nuxt app may use a server route; another app uses a custom
75
+ rewrite. Baking a URL into a component library would lock it to one app
76
+ shape.
77
+
78
+ The contract is three steps:
79
+
80
+ 1. **You construct the `GraphQLClient`** from `propeller-sdk-v2`, with your
81
+ endpoint, headers and auth resolver.
82
+ 2. **You call `createServices(client)`** once — it returns a typed
83
+ `Services` bundle (`product`, `cart`, `user`, `order`, …) keyed to that
84
+ client.
85
+ 3. **You install both** via `providePropeller({ graphqlClient, services, … })`.
86
+
87
+ Inside the provider, every component and composable reads the services via
88
+ `useServices()` — they never instantiate the SDK themselves.
89
+
90
+ `createServices` is a pure factory, memoized per client via a `WeakMap`, so
91
+ calling it again with the same client returns the same bundle. `toPlain`
92
+ recursively strips the SDK's underscore-prefixed backing fields so
93
+ downstream code sees the clean public shape.
94
+
95
+ ## Quick start
96
+
97
+ ### 1. Build the client and services
98
+
99
+ ```ts
100
+ // src/lib/api.ts — your app owns this file
101
+ import { GraphQLClient } from 'propeller-sdk-v2';
102
+ import { createServices } from 'propeller-v2-vue-ui';
103
+
104
+ export const graphqlClient = new GraphQLClient({
105
+ endpoint: import.meta.env.VITE_GRAPHQL_ENDPOINT || '/api/graphql',
106
+ apiKey: import.meta.env.VITE_API_KEY || '',
107
+ timeout: 30_000,
108
+ });
109
+
110
+ export const services = createServices(graphqlClient);
111
+ ```
112
+
113
+ ### 2. Install the provider and the stylesheet
114
+
115
+ ```ts
116
+ // src/main.ts
117
+ import { createApp } from 'vue';
118
+ import App from './App.vue';
119
+ import 'propeller-v2-vue-ui/styles.css';
120
+
121
+ createApp(App).mount('#app');
122
+ ```
123
+
124
+ ```vue
125
+ <!-- src/App.vue -->
126
+ <script setup lang="ts">
127
+ import { providePropeller } from 'propeller-v2-vue-ui';
128
+ import { graphqlClient, services } from '@/lib/api';
129
+
130
+ providePropeller({
131
+ graphqlClient,
132
+ services,
133
+ user: null, // your auth state (a Contact / Customer or null)
134
+ companyId: undefined,
135
+ language: 'NL',
136
+ includeTax: false,
137
+ currency: '€',
138
+ configuration: {}, // free-form config bag (url builders, image filters)
139
+ portalMode: 'open',
140
+ });
141
+ </script>
142
+
143
+ <template>
144
+ <RouterView />
145
+ </template>
146
+ ```
147
+
148
+ `providePropeller` must be called in a component's `setup()` (typically the
149
+ root `App.vue`) so the `provide` reaches the whole tree.
150
+
151
+ ### 3. Use components and composables anywhere below the provider
152
+
153
+ ```vue
154
+ <script setup lang="ts">
155
+ import { ProductCard } from 'propeller-v2-vue-ui';
156
+ </script>
157
+
158
+ <template>
159
+ <ProductCard :product="product" />
160
+ </template>
161
+ ```
162
+
163
+ ## The Propeller provider
164
+
165
+ `providePropeller(value)` installs a `PropellerInfra` object for the
166
+ component subtree. `usePropellerContext()` reads it (non-throwing — returns
167
+ `null` outside a provider).
168
+
169
+ ### `PropellerInfra` fields
170
+
171
+ | Field | Type | Notes |
172
+ | --------------- | -------------------------- | ----- |
173
+ | `graphqlClient` | `GraphQLClient` | The client you constructed. |
174
+ | `services` | `Services` | The bundle from `createServices(client)`. |
175
+ | `user` | `Contact \| Customer \| null` | Your auth state. |
176
+ | `companyId` | `number \| undefined` | Active company for B2B pricing. |
177
+ | `language` | `string` | e.g. `'NL'`, `'EN'`. |
178
+ | `includeTax` | `boolean` | Leading price is net (incl. VAT) when true. |
179
+ | `currency` | `string` | Currency symbol for price formatting. |
180
+ | `configuration` | `unknown` | Free-form bag (url builders, image filters). |
181
+ | `portalMode` | `string` | e.g. `'open'`, `'semi-closed'`. |
182
+
183
+ A component reads infra via `useInfraProps(props)` — an explicit prop always
184
+ wins, otherwise the value comes from the provider, otherwise a default. This
185
+ means components also work standalone (no provider) for tests and
186
+ Storybook.
187
+
188
+ ## Using components
189
+
190
+ The package exports 60 components. They are prop-driven. Components that
191
+ need infrastructure resolve it from the provider, so most usages are short:
192
+
193
+ ```vue
194
+ <ProductGrid :categoryId="17" />
195
+ <CartIconAndSidebar />
196
+ <Breadcrumbs :categoryPath="category.categoryPath" />
197
+ ```
198
+
199
+ `ProductGrid` installs a Tier-2 grid config (`provideProductGridConfig`)
200
+ that `ProductCard` / `ClusterCard` and their subtree consume — so you do not
201
+ thread display flags and callbacks through by hand.
202
+
203
+ See [STYLING.md](./STYLING.md) for restyling, and the docs site for the full
204
+ component catalogue.
205
+
206
+ ## Partner extension API
207
+
208
+ Customise nested components (price, stock, add-to-cart, whole card) without
209
+ forking. See [docs/extension-api.md](docs/extension-api.md) for the full
210
+ guide covering injection slots, cascade rules, before/after iteration slots,
211
+ whole-card swap, ProductInfo expanded shell, and contract types.
212
+
213
+ ## Using composables
214
+
215
+ The 15 composables are headless — reactive state + actions, no markup.
216
+
217
+ ```ts
218
+ import { useCart } from 'propeller-v2-vue-ui';
219
+ import { computed } from 'vue';
220
+ import { graphqlClient } from '@/lib/api';
221
+
222
+ const { cart, addItem, loading } = useCart({
223
+ graphqlClient,
224
+ user: computed(() => authStore.user),
225
+ language: computed(() => languageStore.language),
226
+ configuration: { imageSearchFiltersGrid: {}, imageVariantFiltersSmall: {} },
227
+ });
228
+ ```
229
+
230
+ Composables that take `user` / `companyId` / `language` expect **refs** —
231
+ wrap props or store values with `computed()` before passing them in, so the
232
+ composable tracks changes.
233
+
234
+ The framework-agnostic cart helpers (`initCart`, `fetchActiveCart`,
235
+ `mergeAnonymousCart`) take a `services` bundle rather than a raw client.
236
+
237
+ ## Styling
238
+
239
+ The package ships a precompiled stylesheet — import it once:
240
+
241
+ ```ts
242
+ import 'propeller-v2-vue-ui/styles.css';
243
+ ```
244
+
245
+ Three override surfaces — theme tokens (CSS variables), BEM hook classes,
246
+ and a per-instance `class` attribute. Full detail in [STYLING.md](./STYLING.md).
247
+
248
+ ## API reference
249
+
250
+ ### From `propeller-v2-vue-ui`
251
+
252
+ - **SDK seam:** `createServices`, `toPlain`, `Services` (type)
253
+ - **Provider:** `providePropeller`, `usePropellerContext`,
254
+ `provideProductGridConfig`, `useProductGridConfig`, `PropellerInfra` /
255
+ `ProductGridConfig` (types)
256
+ - **Composables:** `useAddress`, `useAuth`, `useCart`, `useCheckout`,
257
+ `useClusterConfigurator`, `useCompany`, `useFavorites`, `useInfraProps`,
258
+ `useMenu`, `useOrders`, `useProductBundles`, `useProductInfo`,
259
+ `useProductSearch`, `useProductSlider`, `useProductSpecs`,
260
+ `usePurchaseAuthorizationConfigurator`,
261
+ `usePurchaseAuthorizationRequests`, `useResolvedProps`, `useServices`
262
+ - **Utilities:** `formatPrice`, `formatDate`, `getLanguageString`,
263
+ `getProductImageUrl`, `getStockStatus`, `getLabel`, `isContact`,
264
+ `isCustomer`, … (see `src/index.ts` for the full list)
265
+ - **60 components** — `AccountIconAndMenu` … `UserDetails`
266
+
267
+ ### From `propeller-v2-vue-ui/shared`
268
+
269
+ The runtime-agnostic subset: `createServices`, `toPlain`, the framework-free
270
+ utilities, and all domain types. No Vue, safe in a server context.
271
+
272
+ ## Building from source
273
+
274
+ ```bash
275
+ npm install # runs `prepare` → build
276
+ npm run build # vite build + Tailwind CSS compile
277
+ npm run typecheck # vue-tsc --noEmit
278
+ npm test # Vitest unit suite
279
+ ```
280
+
281
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for the full workflow and
282
+ [TECH.md](./TECH.md) for the architecture.
package/STYLING.md ADDED
@@ -0,0 +1,119 @@
1
+ # Styling propeller-v2-vue-ui
2
+
3
+ The package ships a precompiled stylesheet (`dist/styles.css`) that bundles
4
+ every Tailwind utility class its components reference plus the theme tokens
5
+ those utilities resolve against. Consumers import it once:
6
+
7
+ ```ts
8
+ // main.ts (or your app entry)
9
+ import 'propeller-v2-vue-ui/styles.css';
10
+ ```
11
+
12
+ If you don't want default styling at all, skip the import — every component
13
+ will render unstyled (Tailwind classes resolve to nothing) and you'll be on
14
+ your own.
15
+
16
+ The token names and BEM hook class names are **identical** to
17
+ `propeller-v2-react-ui`. A project running both frameworks can share a
18
+ single stylesheet of overrides.
19
+
20
+ ## Three override surfaces
21
+
22
+ Pick the one that matches the scope of your change.
23
+
24
+ ### 1. Theme tokens (most cases)
25
+
26
+ The package's `:root` block declares CSS variables like `--card`,
27
+ `--primary`, `--border`, `--radius-container`, etc. at low specificity. A
28
+ consumer that re-declares the same variable anywhere with equal or higher
29
+ specificity wins, and every utility that resolved against it updates
30
+ instantly.
31
+
32
+ ```css
33
+ /* your global stylesheet — re-skin the whole package without touching components */
34
+ :root {
35
+ --primary: #ff7043; /* changes bg-primary, text-primary, … */
36
+ --primary-foreground: #ffffff;
37
+ --card: #fafafa;
38
+ --border: #e1e1e1;
39
+ --radius-container: 12px;
40
+ }
41
+ ```
42
+
43
+ Scope-limited overrides work too:
44
+
45
+ ```css
46
+ .brand-x { --primary: #1e88e5; }
47
+ .brand-y { --primary: #43a047; }
48
+ ```
49
+
50
+ `<div class="brand-x"><ProductCard ... /></div>` and the embedded
51
+ `bg-primary` / `text-primary` calls inside the card resolve to blue. Same
52
+ component, different scope.
53
+
54
+ Full token list (declared in `src/styles.css`): background, foreground,
55
+ foreground-subtle, card, card-foreground, popover, popover-foreground,
56
+ surface-hover, primary (+fg), secondary (+fg), muted (+fg), accent (+fg),
57
+ destructive (+fg), success (+fg), warning (+fg), border, border-subtle,
58
+ input, ring, radius, radius-control, radius-container.
59
+
60
+ ### 2. BEM hooks (component-specific overrides)
61
+
62
+ Every styled element in every component carries a BEM class alongside its
63
+ Tailwind utilities — `.propeller-product-card`,
64
+ `.propeller-product-card__price`, `.propeller-breadcrumbs`, etc. The package
65
+ emits its utilities inside `@layer utilities`, so any unlayered consumer
66
+ rule that targets a BEM class wins by cascade order regardless of where it
67
+ appears in the stylesheet.
68
+
69
+ ```css
70
+ .propeller-product-card {
71
+ background: #fff8e1;
72
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
73
+ }
74
+
75
+ .propeller-product-card__price {
76
+ font-weight: 700;
77
+ color: #b45309;
78
+ }
79
+
80
+ .propeller-breadcrumbs__separator { display: none; }
81
+ ```
82
+
83
+ The `@layer utilities` vs plain-rule cascade rule is part of the CSS spec —
84
+ no `!important` required.
85
+
86
+ ### 3. Per-instance `class`
87
+
88
+ Vue merges a `class` attribute passed to a component onto that component's
89
+ root element automatically (standard fallthrough-attribute behaviour), so a
90
+ one-off override is a regular attribute:
91
+
92
+ ```vue
93
+ <ProductCard :product="p" class="bg-yellow-100 ring-2 ring-yellow-400" />
94
+ <Breadcrumbs :categoryPath="[]" currentLabel="Home" class="text-sm text-muted-foreground" />
95
+ ```
96
+
97
+ The consumer's class is merged with the component's base classes — it adds
98
+ to them, it does not replace them. To *strip* a default, use the BEM hook
99
+ approach.
100
+
101
+ ## What does NOT work
102
+
103
+ - **No replacing internal markup.** Use slots where a component exposes
104
+ them; otherwise the component's structure is fixed. Re-skin via tokens or
105
+ BEM hooks.
106
+ - **No global `@apply` directives that target package classes from the
107
+ host's Tailwind config.** The package's `bg-card` etc. are not registered
108
+ in your `@apply` resolver — they only exist in `dist/styles.css`. Write a
109
+ host-side override as plain CSS targeting the BEM hook.
110
+ - **No theme tokens you didn't declare.** Tailwind v4 utility classes that
111
+ reference tokens absent from the cascade resolve to nothing. Declare any
112
+ custom token in your own `@theme` block.
113
+
114
+ ## Tailwind dependency
115
+
116
+ The package's styles compile to vanilla CSS at build time. **Consumers do
117
+ NOT need Tailwind** to use the package — `dist/styles.css` works in any Vue
118
+ project. If you also use Tailwind, importing the package's CSS doesn't
119
+ conflict; your own Tailwind output is a separate stylesheet.