@wix/agent-skills 1.15.0 → 1.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -0
- package/package.json +1 -1
- package/skills/wix-app/references/DATA_COLLECTION.md +5 -3
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +2 -0
- package/skills/wix-app/references/STORES_VERSIONING.md +9 -211
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +5 -0
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +151 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +57 -0
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +6 -0
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +3 -1
- package/skills/wix-app/references/stores/CATEGORIES.md +22 -0
- package/skills/wix-app/references/stores/GET_PRODUCT.md +99 -0
- package/skills/wix-app/references/stores/INVENTORY.md +37 -0
- package/skills/wix-app/references/stores/QUERY.md +87 -0
- package/skills/wix-app/references/stores/WRITE.md +55 -0
- package/skills/wix-headless/SKILL.md +6 -1
- package/skills/wix-headless/entry/bootstrap.mjs +2 -2
- package/skills/wix-headless/entry/skill.md +0 -2
- package/skills/wix-headless/references/CAPABILITIES.md +6 -4
- package/skills/wix-headless/references/DISCOVERY.md +1 -1
- package/skills/wix-headless/references/FEEDBACK.md +16 -5
- package/skills/wix-headless/references/SDK_HANDOFF.md +2 -0
- package/skills/wix-headless/references/SEED.md +3 -1
- package/skills/wix-headless/references/SETUP.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +42 -2
- package/skills/wix-headless/references/inline-recipes/setup-bookings.md +5 -1
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +1 -1
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +21 -5
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +3 -1
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-experiences.md +73 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +38 -2
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +20 -1
- package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +1 -1
- package/skills/wix-headless/references/managed/CONNECT.md +1 -1
- package/skills/wix-headless/references/managed/CREATE.md +1 -1
- package/skills/wix-headless/references/managed/DEPLOYMENT.md +22 -0
- package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +8 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +8 -0
- package/skills/wix-manage/SKILL.md +8 -5
- package/skills/wix-manage/references/analytics/query-site-analytics.md +66 -9
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +3 -0
- package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +6 -5
- package/skills/wix-manage/references/bookings/create-course-service.md +30 -5
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +76 -42
- package/skills/wix-manage/references/cms/cms-schema-management.md +6 -0
- package/skills/wix-manage/references/get-paid/how-to-setup-wix-payments.md +30 -7
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +225 -144
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +19 -10
- package/skills/wix-manage/references/sites/site-import.md +270 -0
- package/skills/wix-manage/references/stores/create-product-from-image.md +8 -6
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +16 -10
- package/skills/wix-vibe-headless/SKILL.md +6 -0
- package/skills/wix-vibe-headless/platforms/README.md +22 -0
- package/skills/wix-vibe-headless/platforms/base44.md +142 -0
- package/skills/wix-vibe-headless/platforms/generic.md +87 -0
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +5 -1
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +3 -1
- package/skills/wix-vibe-headless/references/events/wix-events-browse.js +2 -1
- package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +84 -55
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +11 -2
- package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +5 -1
package/README.md
CHANGED
|
@@ -91,6 +91,14 @@ When a major bump is required (a breaking change in the underlying `wix-cli`), t
|
|
|
91
91
|
|
|
92
92
|
Run the [`release-bump`](.github/workflows/release-bump.yml) workflow from the **Actions** tab and pick a `version_strategy`. The rest is automatic — the bump PR auto-merges once checks pass and [`release.yml`](.github/workflows/release.yml) publishes to npm via Trusted Publishing.
|
|
93
93
|
|
|
94
|
+
## Serving & caching (`www.wix.com/skills`)
|
|
95
|
+
|
|
96
|
+
Besides the npm package, skills are served as raw markdown / `.tgz` at `https://www.wix.com/skills/<name>` (also `dev.wix.com/skills`). That registry is **not** in this repo — it's an Express service in [`wix-private/docs`](https://github.com/wix-private/docs) (`docs-web-app`) that serves this repo's `main` branch directly, with no build step.
|
|
97
|
+
|
|
98
|
+
Responses are cached at the Wix edge (Pepyaka, tag `skills`) plus a ~5-min per-pod tarball cache. A push to `main` touching `skills/**` **auto-invalidates** the edge tag (via `md-resolver`'s GitHub-push consumer), so a merge reflects within a few minutes. To force it immediately, hit the manual flush (`POST /api/v1/invalidate-ssr-cache/skills`, BO staff) or the Fire Console `invalidateCache` call.
|
|
99
|
+
|
|
100
|
+
Full details — endpoints, `wix-` prefix stripping, host-relative links, invalidation — are in the [docs-web-app skills README](https://github.com/wix-private/docs/blob/main/packages/docs-web-app/express/skills/README.md).
|
|
101
|
+
|
|
94
102
|
## Contributing
|
|
95
103
|
|
|
96
104
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on adding new skills.
|
package/package.json
CHANGED
|
@@ -80,18 +80,20 @@ export default {
|
|
|
80
80
|
| `ARRAY_DOCUMENT` | Array of documents | File collections |
|
|
81
81
|
| `ANY` | Any type | Most flexible |
|
|
82
82
|
|
|
83
|
-
**CRITICAL: OBJECT fields require `objectOptions
|
|
83
|
+
**CRITICAL: OBJECT fields require `objectOptions` with a `fields` array.** When using `type: "OBJECT"`, you MUST include `objectOptions: { fields: [] }` — the API will reject OBJECT fields without it. Use an empty `fields` array if you don't need a fixed schema (the object will still accept arbitrary JSON):
|
|
84
84
|
|
|
85
85
|
```json
|
|
86
86
|
{
|
|
87
87
|
"key": "settings",
|
|
88
88
|
"displayName": "Settings",
|
|
89
89
|
"type": "OBJECT",
|
|
90
|
-
"objectOptions": {}
|
|
90
|
+
"objectOptions": { "fields": [] }
|
|
91
91
|
}
|
|
92
92
|
```
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
> ⚠️ `objectOptions: {}` (without the `fields` key) is **not valid** and will cause a runtime error. Always include `fields`, even as an empty array.
|
|
95
|
+
|
|
96
|
+
For structured objects with a defined schema, list the nested fields inside `objectOptions.fields`:
|
|
95
97
|
|
|
96
98
|
```json
|
|
97
99
|
{
|
|
@@ -87,6 +87,8 @@ Topic-focused references (rules + patterns + common mistakes in one place):
|
|
|
87
87
|
- [`editor-react-component/PROPS-VS-CSS.md`](editor-react-component/PROPS-VS-CSS.md) — What should be a React prop vs CSS
|
|
88
88
|
- [`editor-react-component/COMPONENT-API.md`](editor-react-component/COMPONENT-API.md) — Props structure, elementProps, data types, file splitting, containers, array props
|
|
89
89
|
- [`editor-react-component/REACT-PATTERNS.md`](editor-react-component/REACT-PATTERNS.md) — SSR-safe patterns, CSS rules, remaining common mistakes
|
|
90
|
+
- [`editor-react-component/ANIMATED-COMPONENTS.md`](editor-react-component/ANIMATED-COMPONENTS.md) — Play/pause controls for animated components (Lottie, GIF, autoPlay props)
|
|
91
|
+
- [`editor-react-component/COMPONENT-PREVIEW.md`](editor-react-component/COMPONENT-PREVIEW.md) — `component.preview.tsx` patterns and `useIsEditMode()` usage
|
|
90
92
|
|
|
91
93
|
## CSS guidelines
|
|
92
94
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
# Wix Stores Catalog Versioning (V1 / V3)
|
|
3
2
|
|
|
4
3
|
Wix Stores has two catalog versions that are **NOT backwards compatible**. Apps **must support both** — single-version apps cannot list in the App Market and break on new sites.
|
|
@@ -82,214 +81,6 @@ Handle `STORES_NOT_INSTALLED` gracefully — return empty results, do not throw.
|
|
|
82
81
|
|
|
83
82
|
---
|
|
84
83
|
|
|
85
|
-
## Copy-Paste Recipes
|
|
86
|
-
|
|
87
|
-
Each recipe handles both versions. `V3Product` and V1 `Product` types are **not** re-exported from `@wix/stores` top-level — let TS infer or use structural types.
|
|
88
|
-
|
|
89
|
-
### List products with pagination
|
|
90
|
-
|
|
91
|
-
Both versions expose a fluent query builder, but the paging method differs:
|
|
92
|
-
|
|
93
|
-
| Aspect | V1 (`products.queryProducts()`) | V3 (`productsV3.queryProducts()`) |
|
|
94
|
-
|--------|--------------------------------|----------------------------------|
|
|
95
|
-
| API style | Fluent builder: `.skip().limit().find()` | Fluent builder: `.skipTo(cursor).limit().find()` |
|
|
96
|
-
| Pagination | Offset (`.skip(n)`) | Cursor (`.skipTo(cursor)`) |
|
|
97
|
-
| Result `items` | `res.items` (V1 `Product[]`) | `res.items` (V3 `Product[]`) |
|
|
98
|
-
| Total count | `res.totalCount` | **None** — V3 only has `cursors.next` + `hasNext()` |
|
|
99
|
-
| `hasNext` | `res.hasNext()` (method) | `res.hasNext()` (method) |
|
|
100
|
-
| Next cursor | n/a | `res.cursors.next` (string) |
|
|
101
|
-
|
|
102
|
-
```typescript
|
|
103
|
-
import { catalogVersioning, products, productsV3 } from '@wix/stores';
|
|
104
|
-
|
|
105
|
-
export interface ProductsPage {
|
|
106
|
-
products: unknown[]; // narrow at call site
|
|
107
|
-
nextCursor: string | null; // V3 only
|
|
108
|
-
hasNext: boolean;
|
|
109
|
-
totalCount: number | null; // V1 only
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export async function listProductsPage(
|
|
113
|
-
limit: number,
|
|
114
|
-
cursorOrSkip: string | number | undefined,
|
|
115
|
-
): Promise<ProductsPage> {
|
|
116
|
-
const v = await getVersion();
|
|
117
|
-
if (v === 'STORES_NOT_INSTALLED') {
|
|
118
|
-
return { products: [], nextCursor: null, hasNext: false, totalCount: 0 };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (v === 'V3_CATALOG') {
|
|
122
|
-
let builder = productsV3.queryProducts().limit(limit);
|
|
123
|
-
if (typeof cursorOrSkip === 'string') builder = builder.skipTo(cursorOrSkip);
|
|
124
|
-
// Do NOT chain a sort — see gotcha #10.
|
|
125
|
-
const res = await builder.find();
|
|
126
|
-
return {
|
|
127
|
-
products: res.items,
|
|
128
|
-
nextCursor: res.cursors.next ?? null,
|
|
129
|
-
hasNext: res.hasNext(),
|
|
130
|
-
totalCount: null,
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const skip = typeof cursorOrSkip === 'number' ? cursorOrSkip : 0;
|
|
135
|
-
const res = await products.queryProducts().skip(skip).limit(limit).find();
|
|
136
|
-
return {
|
|
137
|
-
products: res.items,
|
|
138
|
-
nextCursor: null,
|
|
139
|
-
hasNext: res.hasNext(),
|
|
140
|
-
totalCount: res.totalCount ?? null,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
> **Two ways to call V3 `queryProducts`:** the canonical builder shown above, and a direct-call form `productsV3.queryProducts({ cursorPaging: { limit, cursor } })` returning a `Promise<{ products, pagingMetadata }>`. Both compile and run, but the builder is more idiomatic and matches V1's shape.
|
|
146
|
-
|
|
147
|
-
### Display price/stock without fetching variants
|
|
148
|
-
|
|
149
|
-
V3 `queryProducts` does not return variants. Read product-level rollup fields instead:
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
function displayPrice(p: { actualPriceRange?: { minValue?: { amount?: string }; maxValue?: { amount?: string } } }): string {
|
|
153
|
-
const min = p.actualPriceRange?.minValue?.amount;
|
|
154
|
-
const max = p.actualPriceRange?.maxValue?.amount;
|
|
155
|
-
if (!min) return '—';
|
|
156
|
-
return max && max !== min ? `${min} – ${max}` : min;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function stockLabel(status: string | undefined): string {
|
|
160
|
-
switch (status) {
|
|
161
|
-
case 'IN_STOCK': return 'In Stock';
|
|
162
|
-
case 'OUT_OF_STOCK': return 'Out of Stock';
|
|
163
|
-
case 'PARTIALLY_OUT_OF_STOCK': return 'Limited';
|
|
164
|
-
case 'PREORDER': return 'Pre-order';
|
|
165
|
-
default: return '—';
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
// V1 path: product.stock.inventoryStatus (same UPPER_SNAKE_CASE values)
|
|
169
|
-
// V3 path: product.inventory.availabilityStatus (adds PREORDER)
|
|
170
|
-
// SKU lives on the variant — show "—" in lists, or use Read-Only Variants API.
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Get a single product
|
|
174
|
-
|
|
175
|
-
```typescript
|
|
176
|
-
if (v === 'V3_CATALOG') {
|
|
177
|
-
const product = await productsV3.getProduct(id); // returns Product directly
|
|
178
|
-
return product;
|
|
179
|
-
}
|
|
180
|
-
const { product } = await products.getProduct(id); // V1 wraps in { product }
|
|
181
|
-
return product;
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### Create a product (single-variant, with price)
|
|
185
|
-
|
|
186
|
-
```typescript
|
|
187
|
-
if (v === 'V3_CATALOG') {
|
|
188
|
-
const product = await productsV3.createProduct({
|
|
189
|
-
name: 'My Product',
|
|
190
|
-
productType: 'PHYSICAL', // UPPER_CASE
|
|
191
|
-
variantsInfo: {
|
|
192
|
-
variants: [{
|
|
193
|
-
price: { actualPrice: { amount: '19.99' } }, // string, on the variant
|
|
194
|
-
sku: 'SKU-001',
|
|
195
|
-
}],
|
|
196
|
-
},
|
|
197
|
-
});
|
|
198
|
-
return product;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
const { product } = await products.createProduct({
|
|
202
|
-
name: 'My Product',
|
|
203
|
-
productType: 'physical', // lower-case
|
|
204
|
-
priceData: { price: 19.99 }, // number, on the product
|
|
205
|
-
sku: 'SKU-001',
|
|
206
|
-
});
|
|
207
|
-
return product;
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Update a product (V3 needs `revision`)
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
if (v === 'V3_CATALOG') {
|
|
214
|
-
// Signature: updateProduct(_id, productFields). Returns Product directly.
|
|
215
|
-
const current = await productsV3.getProduct(id);
|
|
216
|
-
if (current.revision == null) throw new Error(`Product ${id} has no revision`);
|
|
217
|
-
return await productsV3.updateProduct(id, {
|
|
218
|
-
revision: current.revision, // narrowed — required under exactOptionalPropertyTypes
|
|
219
|
-
name: 'New name',
|
|
220
|
-
});
|
|
221
|
-
}
|
|
222
|
-
// V1: updateProduct(id, productFields). Returns { product }.
|
|
223
|
-
const { product } = await products.updateProduct(id, { name: 'New name' });
|
|
224
|
-
return product;
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
### Delete a product
|
|
228
|
-
|
|
229
|
-
```typescript
|
|
230
|
-
if (v === 'V3_CATALOG') await productsV3.deleteProduct(id);
|
|
231
|
-
else await products.deleteProduct(id);
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
### Inventory: increment stock
|
|
235
|
-
|
|
236
|
-
```typescript
|
|
237
|
-
import { inventory, inventoryItemsV3 } from '@wix/stores';
|
|
238
|
-
|
|
239
|
-
if (v === 'V3_CATALOG') {
|
|
240
|
-
// Per-variant; flat shape.
|
|
241
|
-
await inventoryItemsV3.bulkIncrementInventoryItems([
|
|
242
|
-
{ inventoryItemId, incrementBy: 5 },
|
|
243
|
-
]);
|
|
244
|
-
} else {
|
|
245
|
-
// Per-product (variant optional).
|
|
246
|
-
await inventory.incrementInventory([
|
|
247
|
-
{ productId, variantId, incrementBy: 5 },
|
|
248
|
-
]);
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
To find a V3 inventory item ID, use `inventoryItemsV3.searchInventoryItems` filtered by `productId` / `variantId`.
|
|
253
|
-
|
|
254
|
-
### Query inventory
|
|
255
|
-
|
|
256
|
-
```typescript
|
|
257
|
-
if (v === 'V3_CATALOG') {
|
|
258
|
-
const res = await inventoryItemsV3.queryInventoryItems().eq('productId', productId).find();
|
|
259
|
-
return res.items;
|
|
260
|
-
}
|
|
261
|
-
// V1: filter is a JSON-stringified expression.
|
|
262
|
-
const res = await inventory.queryInventory({
|
|
263
|
-
query: { filter: JSON.stringify({ productId }) },
|
|
264
|
-
});
|
|
265
|
-
return res.inventoryItems;
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Collections (V1) ↔ Categories (V3)
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
// V1 write ops (createCollection, updateCollection, addProductsToCollection, …)
|
|
272
|
-
// live on the `products` namespace, NOT `collections`. The `collections` namespace is read-only.
|
|
273
|
-
import { products } from '@wix/stores';
|
|
274
|
-
import { categories } from '@wix/categories';
|
|
275
|
-
|
|
276
|
-
if (v === 'V3_CATALOG') {
|
|
277
|
-
// V3 createCategory(category, options). treeReference is REQUIRED and goes in `options`.
|
|
278
|
-
// For Wix Stores categories: appNamespace MUST be the literal "@wix/stores", treeKey is null.
|
|
279
|
-
const category = await categories.createCategory(
|
|
280
|
-
{ name: 'Sale' },
|
|
281
|
-
{ treeReference: { appNamespace: '@wix/stores', treeKey: null } },
|
|
282
|
-
);
|
|
283
|
-
return category;
|
|
284
|
-
}
|
|
285
|
-
const { collection } = await products.createCollection({ name: 'Sale' }); // V1 returns { collection }
|
|
286
|
-
return collection;
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
V3 categories are tree-structured. Reference them on a product via `directCategories[]`, not `collectionIds[]`. **All Stores category API calls must pass `treeReference: { appNamespace: '@wix/stores', treeKey: null }` in `options`** — applies to `createCategory`, `updateCategory`, `queryCategories`, etc.
|
|
290
|
-
|
|
291
|
-
---
|
|
292
|
-
|
|
293
84
|
## V1 → V3 Field Mapping (most common)
|
|
294
85
|
|
|
295
86
|
For the full table see the [Catalog V1 to V3 Migration Guide](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/catalog-v1-to-v3-migration-guide?apiView=SDK).
|
|
@@ -311,6 +102,7 @@ For the full table see the [Catalog V1 to V3 Migration Guide](https://dev.wix.co
|
|
|
311
102
|
| `collectionIds[i]` | `directCategories[i].id` |
|
|
312
103
|
| `ribbon`, `brand` (string) | `ribbon.name`, `brand.name` (managed via `ribbonsV3` / `brandsV3`) |
|
|
313
104
|
| `media.mainMedia.image.url` (main image URL) | `media.main.image ?? media.main.url` — in V3, `ProductMedia.image` is a `string` (Wix-hosted URL), `url` is a `string` (external URL); check both |
|
|
105
|
+
| `lastUpdated` | `updatedDate` |
|
|
314
106
|
|
|
315
107
|
**Pricing model** — V1 had a `discount` object; V3 removed it. Discounts are now expressed by the relationship between two fields on the variant: `actualPrice` (required, what the customer pays) vs `compareAtPrice` (optional, original price shown struck through). With discount: V1 `price`/`discountedPrice` → V3 `compareAtPrice`/`actualPrice`. Without discount: V1 `price` → V3 `actualPrice`, leave `compareAtPrice` empty.
|
|
316
108
|
|
|
@@ -330,6 +122,12 @@ Payload changes: V1 `changedFields` → V3 `modifiedFields`. Top-level `entityId
|
|
|
330
122
|
|
|
331
123
|
---
|
|
332
124
|
|
|
333
|
-
##
|
|
125
|
+
## Detailed references
|
|
126
|
+
|
|
127
|
+
- [stores/QUERY.md](stores/QUERY.md) — list/query products, pagination, price and stock display
|
|
128
|
+
- [stores/GET_PRODUCT.md](stores/GET_PRODUCT.md) — getProduct, options/choices, modifiers, variant choices
|
|
129
|
+
- [stores/WRITE.md](stores/WRITE.md) — create, update, delete products
|
|
130
|
+
- [stores/INVENTORY.md](stores/INVENTORY.md) — inventory read and write operations
|
|
131
|
+
- [stores/CATEGORIES.md](stores/CATEGORIES.md) — collections (V1) ↔ categories (V3)
|
|
334
132
|
|
|
335
|
-
|
|
133
|
+
For methods not listed here, use `SearchWixSDKDocumentation` then `ReadFullDocsArticle`. Always return the required permission scopes to the user.
|
|
@@ -12,10 +12,15 @@ This reference lists common event types, SDK imports, permissions, and links. Fo
|
|
|
12
12
|
|
|
13
13
|
## eCommerce Events
|
|
14
14
|
|
|
15
|
+
Order events use **`@wix/ecom`** (namespace `orders`). Order **refund** events are the exception: they live in **`@wix/payments`** (namespace `refunds`), not `@wix/ecom`.
|
|
16
|
+
|
|
15
17
|
| Event | Import | Handler Call | Permission | API Reference |
|
|
16
18
|
| --- | --- | --- | --- | --- |
|
|
17
19
|
| Order created | `import { orders } from "@wix/ecom"` | `orders.onOrderCreated(handler)` | `SCOPE.DC-STORES.READ-ORDERS` | [onOrderCreated](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/orders/orders/order-created?apiView=SDK) |
|
|
18
20
|
| Order approved | `import { orders } from "@wix/ecom"` | `orders.onOrderApproved(handler)` | `SCOPE.DC-STORES.READ-ORDERS` | [onOrderApproved](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/orders/orders/order-approved?apiView=SDK) |
|
|
21
|
+
| Order canceled | `import { orders } from "@wix/ecom"` | `orders.onOrderCanceled(handler)` | `SCOPE.DC-STORES.READ-ORDERS` | [onOrderCanceled](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/orders/orders/order-canceled?apiView=SDK) |
|
|
22
|
+
| Refund created | `import { refunds } from "@wix/payments"` | `refunds.onRefundCreated(handler)` | `SCOPE.DC-PAYMENTS.READ-REFUNDS` | [onRefundCreated](https://dev.wix.com/docs/api-reference/business-management/payments/refunds/refund-created?apiView=SDK) |
|
|
23
|
+
| Refund updated | `import { refunds } from "@wix/payments"` | `refunds.onRefundUpdated(handler)` | `SCOPE.DC-PAYMENTS.READ-REFUNDS` | [onRefundUpdated](https://dev.wix.com/docs/api-reference/business-management/payments/refunds/refund-updated?apiView=SDK) |
|
|
19
24
|
| Cart created | `import { cart } from "@wix/ecom"` | `cart.onCartCreated(handler)` | `SCOPE.DC-STORES.READ-ORDERS` | [onCartCreated](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart/cart/cart-created?apiView=SDK) |
|
|
20
25
|
| Cart updated | `import { cart } from "@wix/ecom"` | `cart.onCartUpdated(handler)` | `SCOPE.DC-STORES.READ-ORDERS` | [onCartUpdated](https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart/cart/cart-updated?apiView=SDK) |
|
|
21
26
|
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# Animated Components (Play/Pause Control)
|
|
2
|
+
|
|
3
|
+
Rules and patterns for components whose primary content is a **playable
|
|
4
|
+
animation** — a Lottie/JSON animation, an animated GIF/SVG, a canvas/WebGL
|
|
5
|
+
loop, or a video-like surface.
|
|
6
|
+
|
|
7
|
+
Every such component MUST ship an on-stage **play/pause button**.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## When this applies
|
|
12
|
+
|
|
13
|
+
Apply automatically — without being asked — whenever the component has an
|
|
14
|
+
`autoPlay` prop **or** its primary content is a **startable / loopable**
|
|
15
|
+
animation a visitor would reasonably want to start or stop:
|
|
16
|
+
|
|
17
|
+
- Any component with an `autoPlay` prop (gallery, slider, carousel, etc.)
|
|
18
|
+
- Lottie / JSON vector animations
|
|
19
|
+
- Animated GIFs or animated SVGs
|
|
20
|
+
- Canvas / WebGL animation loops
|
|
21
|
+
- Any video-like playing surface
|
|
22
|
+
|
|
23
|
+
**Key rule:** If the component accepts an `autoPlay` prop — even if the
|
|
24
|
+
underlying mechanism is a `setInterval` advancing an index rather than a media
|
|
25
|
+
player — it MUST expose a play/pause button so visitors can stop the
|
|
26
|
+
auto-advancing behavior. "Autoplay" is a behavior contract, not an
|
|
27
|
+
implementation detail.
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## What to add (checklist)
|
|
32
|
+
|
|
33
|
+
1. **Props** — `autoPlay`, `loop`, `pauseButtonVisibility`
|
|
34
|
+
2. **Playback state** — `isPlaying` + `handlePause` / `handleResume`
|
|
35
|
+
3. **Play/pause button** — overlay `<button>` with inline SVG icon + CSS positioning and optional hover-only visibility
|
|
36
|
+
4. **Modify `component.preview.tsx`** — suppress autoplay in editor design mode
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 1. Props
|
|
41
|
+
|
|
42
|
+
Playback controls are **behavior** props (see [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md)):
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import type { A11y, Direction } from '@wix/editor-react-types';
|
|
46
|
+
|
|
47
|
+
export interface MyAnimationProps {
|
|
48
|
+
id?: string;
|
|
49
|
+
className?: string;
|
|
50
|
+
direction?: Direction;
|
|
51
|
+
a11y?: A11y;
|
|
52
|
+
|
|
53
|
+
/** Start playing on load. Default `true`. */
|
|
54
|
+
autoPlay?: boolean;
|
|
55
|
+
|
|
56
|
+
/** Repeat when finished. Default `true`. */
|
|
57
|
+
loop?: boolean;
|
|
58
|
+
|
|
59
|
+
/** Show play/pause button. Default `'showOnHover'`. */
|
|
60
|
+
pauseButtonVisibility?: 'showAlways' | 'showOnHover';
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 2. Playback state
|
|
67
|
+
|
|
68
|
+
Track play/pause state with `useState`, initialized from the `autoPlay` prop:
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
const [isPlaying, setIsPlaying] = React.useState(autoPlay ?? true);
|
|
72
|
+
|
|
73
|
+
const handlePause = () => setIsPlaying(false);
|
|
74
|
+
const handleResume = () => setIsPlaying(true);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Pass `isPlaying` to the animation renderer and toggle between `handlePause` / `handleResume` on button click.
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 3. Play/pause button
|
|
82
|
+
|
|
83
|
+
Create play/pause icons that visually match the component's style. Use simple recognizable shapes — a triangle for play, two rectangles for pause — implemented as inline SVG so there is no external icon dependency. Size, stroke, and fill should feel native to the component's design.
|
|
84
|
+
|
|
85
|
+
Position the button absolutely so it overlays the content without pushing other elements out of place:
|
|
86
|
+
|
|
87
|
+
```css
|
|
88
|
+
.animationContainer {
|
|
89
|
+
position: relative;
|
|
90
|
+
block-size: 100%;
|
|
91
|
+
inline-size: 100%;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.playButton {
|
|
95
|
+
position: absolute;
|
|
96
|
+
inset-inline-end: 5px;
|
|
97
|
+
inset-block-start: 5px;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
```css
|
|
102
|
+
/* pauseButtonVisibility variants — structural CSS, not named-part rules */
|
|
103
|
+
|
|
104
|
+
/* showOnHover (default) */
|
|
105
|
+
.root[data-pause-button-visibility="showOnHover"] .playButton {
|
|
106
|
+
opacity: 0;
|
|
107
|
+
pointer-events: none;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.root[data-pause-button-visibility="showOnHover"]:hover .playButton {
|
|
111
|
+
opacity: 1;
|
|
112
|
+
pointer-events: auto;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* showAlways — no extra CSS needed; button is visible by default */
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 4. Modify `component.preview.tsx` for autoplay suppression
|
|
121
|
+
|
|
122
|
+
For animated components, modify the generated `component.preview.tsx` to suppress autoplay in editor design mode. See [`COMPONENT-PREVIEW.md`](COMPONENT-PREVIEW.md) for how the preview file works.
|
|
123
|
+
|
|
124
|
+
### Target state of `component.preview.tsx`
|
|
125
|
+
|
|
126
|
+
Replace the generated passthrough with the following. Replace `MyComponent` with the real component name.
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
import React from 'react';
|
|
130
|
+
import MyComponent from './component';
|
|
131
|
+
import { useIsEditMode } from '@wix/react-component-utils';
|
|
132
|
+
|
|
133
|
+
export default function MyComponentPreview(
|
|
134
|
+
props: React.ComponentProps<typeof MyComponent>,
|
|
135
|
+
) {
|
|
136
|
+
const isEditMode = useIsEditMode();
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<MyComponent
|
|
140
|
+
{...props}
|
|
141
|
+
autoPlay={isEditMode ? false : props.autoPlay}
|
|
142
|
+
pauseButtonVisibility={isEditMode ? 'showAlways' : props.pauseButtonVisibility}
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
In editor design mode (`isEditMode` is `true`) → `autoPlay` is forced to `false` and `pauseButtonVisibility` is forced to `'showAlways'` so the site owner can always see and interact with the button.
|
|
149
|
+
In preview mode (`isEditMode` is `false`) → both use the user's configured values.
|
|
150
|
+
|
|
151
|
+
---
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Component Preview (`component.preview.tsx`)
|
|
2
|
+
|
|
3
|
+
Rules and patterns for the editor-specific entry point that every Editor React
|
|
4
|
+
component ships alongside its main `component.tsx`.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What it is
|
|
9
|
+
|
|
10
|
+
`component.preview.tsx` is the editor-specific entry point for a component. The
|
|
11
|
+
Wix CLI loads it **instead of** `component.tsx` when rendering the component
|
|
12
|
+
inside the Harmony Editor. It is generated automatically by the scaffold as a
|
|
13
|
+
passthrough that forwards all props unchanged:
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
const MyComponentPreview = (props: React.ComponentProps<typeof MyComponent>) => (
|
|
17
|
+
<MyComponent {...props} />
|
|
18
|
+
);
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The extension file is also pre-wired to load it — no manual wiring is needed:
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import componentPreviewUrl from './component.preview.tsx?url';
|
|
25
|
+
|
|
26
|
+
resources: {
|
|
27
|
+
client: { componentUrl },
|
|
28
|
+
editor: { componentUrl: componentPreviewUrl },
|
|
29
|
+
},
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## `useIsEditMode()`
|
|
35
|
+
|
|
36
|
+
When you need to distinguish **editor design mode** from **editor preview mode**,
|
|
37
|
+
use `useIsEditMode()` from `@wix/react-component-utils`:
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { useIsEditMode } from '@wix/react-component-utils';
|
|
41
|
+
|
|
42
|
+
const isEditMode = useIsEditMode();
|
|
43
|
+
// true → editor is in design mode
|
|
44
|
+
// false → editor is in preview mode
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`@wix/react-component-utils` is already a base dependency — no additional install needed.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## When to modify it
|
|
52
|
+
|
|
53
|
+
Modify `component.preview.tsx` whenever the component needs to behave differently
|
|
54
|
+
inside the editor than it does on the live site. The most common case is
|
|
55
|
+
suppressing autoplay so animations don't run while the site owner is designing.
|
|
56
|
+
|
|
57
|
+
→ See [`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md) §4 for the autoplay suppression pattern.
|
|
@@ -465,6 +465,12 @@ slide instead.
|
|
|
465
465
|
}
|
|
466
466
|
```
|
|
467
467
|
|
|
468
|
+
**Media playback is functional, not decorative.** When the component's content
|
|
469
|
+
*is* a playing animation (Lottie/JSON, animated GIF/SVG, canvas/WebGL, video),
|
|
470
|
+
letting it play is allowed — the motion is the content. Such components get a
|
|
471
|
+
play/pause control positioned in CSS. See
|
|
472
|
+
[`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md).
|
|
473
|
+
|
|
468
474
|
### Set `pointer-events: auto` on the root and every interactive element
|
|
469
475
|
|
|
470
476
|
The root selector and every nested class that the user can click,
|
|
@@ -9,6 +9,8 @@ This guide defines rules and guidance on **how to implement** production-quality
|
|
|
9
9
|
- [`DIRECTIONALITY.md`](DIRECTIONALITY.md) — RTL/LTR rules and patterns
|
|
10
10
|
- [`PROPS-VS-CSS.md`](PROPS-VS-CSS.md) — What should be a React prop vs CSS
|
|
11
11
|
- [`COMPONENT-API.md`](COMPONENT-API.md) — Props structure, elementProps, data types, file splitting, containers, array props
|
|
12
|
+
- [`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md) — Play/pause control and autoplay for animated/playable components
|
|
13
|
+
- [`COMPONENT-PREVIEW.md`](COMPONENT-PREVIEW.md) — `component.preview.tsx` patterns and `useIsEditMode()` usage
|
|
12
14
|
- [`REACT-PATTERNS.md`](REACT-PATTERNS.md) — SSR-safe patterns, CSS rules, common mistakes
|
|
13
15
|
|
|
14
16
|
## React 18 features are not supported
|
|
@@ -23,7 +25,7 @@ Understand the component and infer its behavior. Extract what is provided; use r
|
|
|
23
25
|
|
|
24
26
|
1. **Identity** — Component name.
|
|
25
27
|
2. **Structure** — Identify named parts by applying the mandatory filter in [`PARTS.md`](PARTS.md) to every candidate element before accepting it as a part. Include content/data props (labels, items, types, required vs optional) and configuration (toggles, choices, ranges, modes).
|
|
26
|
-
3. **Interactions** — Clicks, hover/focus; what is exposed as event props vs handled internally.
|
|
28
|
+
3. **Interactions** — Clicks, hover/focus; what is exposed as event props vs handled internally. If the component's primary content is a **playable animation** (Lottie/JSON, animated GIF/SVG, canvas/WebGL loop, video-like surface), it gets a play/pause control — follow [`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md).
|
|
27
29
|
4. **States** — For every part, decide which design states it supports (native: `hover`/`focus`/`disabled`/`invalid`; custom: `selected`/`active`/`open`/… ) by applying the heuristic in [`DESIGN-STATES.md`](DESIGN-STATES.md), and record them in the plan. These become the editor's per-element state styling controls.
|
|
28
30
|
|
|
29
31
|
**Understanding → implementation (checklist):** For every part, decide `elementProps` vs CSS-only and which design states it supports ([`DESIGN-STATES.md`](DESIGN-STATES.md)); build the props interface (data + behavior); wire interaction in React (`useState`, `useEffect`, refs, native event handlers); give every named inner element an `elementProps` entry and spread it + merge its `className` ([`COMPONENT-API.md`](COMPONENT-API.md)); generate TS + CSS. Infer reasonable defaults where anything is unspecified.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Stores — Collections (V1) ↔ Categories (V3)
|
|
2
|
+
|
|
3
|
+
```typescript
|
|
4
|
+
// V1 write ops (createCollection, updateCollection, addProductsToCollection, …)
|
|
5
|
+
// live on the `products` namespace, NOT `collections`. The `collections` namespace is read-only.
|
|
6
|
+
import { products } from '@wix/stores';
|
|
7
|
+
import { categories } from '@wix/categories';
|
|
8
|
+
|
|
9
|
+
if (v === 'V3_CATALOG') {
|
|
10
|
+
// V3 createCategory(category, options). treeReference is REQUIRED and goes in `options`.
|
|
11
|
+
// For Wix Stores categories: appNamespace MUST be the literal "@wix/stores", treeKey is null.
|
|
12
|
+
const category = await categories.createCategory(
|
|
13
|
+
{ name: 'Sale' },
|
|
14
|
+
{ treeReference: { appNamespace: '@wix/stores', treeKey: null } },
|
|
15
|
+
);
|
|
16
|
+
return category;
|
|
17
|
+
}
|
|
18
|
+
const { collection } = await products.createCollection({ name: 'Sale' }); // V1 returns { collection }
|
|
19
|
+
return collection;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
V3 categories are tree-structured. Reference them on a product via `directCategories[]`, not `collectionIds[]`. **All Stores category API calls must pass `treeReference: { appNamespace: '@wix/stores', treeKey: null }` in `options`** — applies to `createCategory`, `updateCategory`, `queryCategories`, etc.
|