# @wix/headless-ecom

E-commerce headless components for building cart, checkout, and commerce functionality in Wix-powered applications.

## 💡 Motivation

Traditional Wix components are tightly coupled with Wix's editor and rendering engine. **Headless components** break free from this constraint, enabling developers to build **completely custom frontends** while still leveraging Wix's powerful backend services.

This package connects your standalone React application (Next.js, Astro, Remix, etc.) directly to Wix's e-commerce APIs through the **Wix SDK**.

In simple words - the developer brings the UI, Wix provides the e-commerce engine. The headless components are the bridge that connects them, giving the developer the best of both worlds—Wix's robust backend with his frontend creativity.

## 📦 Package Overview

This package provides unstyled, composable React components for e-commerce functionality, following a service-oriented architecture where business logic is separated from presentation.

For detailed API specifications, see [ECOM_INTERFACE.md](../../../docs/api/ECOM_INTERFACE.md).

## 🚀 Installation

```bash
npm install @wix/headless-ecom @wix/headless-components
# or
yarn add @wix/headless-ecom @wix/headless-components
```

## 📚 What's Included

### ✅ Current Components

- **[Cart](src/react/Cart.tsx)** - Main cart component with primitive layer and AsChild support
- **[LineItem](src/react/LineItem.tsx)** - Individual cart item component
- **[CartCoupon](src/react/CartCoupon.tsx)** - Coupon management functionality
- **[SelectedOption](src/react/SelectedOption.tsx)** - Product options displayed in cart
- **[CurrentCart](src/react/CurrentCart.tsx)** - Cart state wrapper component
- **[Commerce](src/react/Commerce.tsx)** - Commerce functionality wrapper

### 🔧 Services

- **[CurrentCartService](src/services/current-cart-service.ts)** - Cart state management
- **[CheckoutService](src/services/checkout-service.ts)** - Checkout flow logic
- **[SelectedOptionService](src/services/selected-option-service.ts)** - Product option handling

## 🎯 Usage

### Basic Cart Implementation

```tsx
import { Cart } from '@wix/headless-ecom/react';
import { LineItem } from '@wix/headless-ecom/react';

function ShoppingCart() {
  return (
    <Cart.Root>
      <Cart.LineItemsList>
        {({ lineItems, isLoading }) =>
          isLoading ? (
            <div>Loading cart...</div>
          ) : (
            lineItems.map((item) => (
              <LineItem.Root key={item.id} lineItem={item}>
                <LineItem.Image />
                <LineItem.Title />
                <LineItem.SelectedOptions>
                  <LineItem.SelectedOptionRepeater>
                    <SelectedOption.Text />
                    <SelectedOption.Color />
                  </LineItem.SelectedOptionRepeater>
                </LineItem.SelectedOptions>
              </LineItem.Root>
            ))
          )
        }
      </Cart.LineItemsList>

      <Cart.Summary>
        {({ subtotal, total, tax }) => (
          <div>
            <p>Subtotal: {subtotal}</p>
            <p>Tax: {tax}</p>
            <p>Total: {total}</p>
          </div>
        )}
      </Cart.Summary>

      <Cart.Checkout>
        {({ checkout, isLoading }) => (
          <button onClick={checkout} disabled={isLoading}>
            {isLoading ? 'Processing...' : 'Checkout'}
          </button>
        )}
      </Cart.Checkout>
    </Cart.Root>
  );
}
```

### Using Services Directly

```tsx
import {
  CurrentCartService,
  loadCurrentCartServiceConfig,
} from '@wix/headless-ecom/services';

// Load cart configuration
const config = await loadCurrentCartServiceConfig();

// Use in your service manager
const services = createServiceManager({
  services: [CurrentCartService],
  config: { currentCart: config },
});
```

## 🏗️ Architecture

This package follows a three-layer architecture:

### 1. Services Layer (`/services`)

Business logic, state management, and API integrations:

- `current-cart-service.ts` - Cart state and operations
- `checkout-service.ts` - Checkout flow management
- `selected-option-service.ts` - Product option handling
- `common-types.ts` - Shared TypeScript types

### 2. React Components (`/react`)

Headless UI primitives with render props:

- **Core Components** (`/react/core`) - Plain render functions connecting directly to the SDK. These use the old render-props pattern and provide the foundational logic for interacting with Wix services.
- **Public API Components** (`/react`) - Primitive components inspired by Radix UI. These wrap the core components to provide a more modern, composable API with `asChild` support and follow the documented patterns.

**Key Principle**: Headless components include **no styling** and preferably **minimal DOM elements**. They are designed to be building blocks for composing the UI of your e-commerce app, giving the developer complete control over the visual presentation while handling all the business logic, state management, and API interactions.

### 3. Mappers (`/mappers`)

Data transformation utilities:

- `line-item-to-selected-options.ts` - Convert line items to selected options

## 📋 File Structure

```
ecom/
├── package.json
├── README.md (this file)
├── tsconfig.*.json
├── vitest.config.ts
├── src/
│   ├── react/
│   │   ├── Cart.tsx                  (1,246 lines - main component)
│   │   ├── Cart.test.tsx
│   │   ├── LineItem.tsx
│   │   ├── LineItem.test.tsx
│   │   ├── SelectedOption.tsx
│   │   ├── SelectedOption.test.tsx
│   │   ├── CartCoupon.tsx
│   │   ├── CartCoupon.test.tsx
│   │   ├── CurrentCart.tsx
│   │   ├── Commerce.tsx
│   │   ├── Commerce.test.tsx
│   │   ├── index.tsx
│   │   └── core/
│   │       ├── CurrentCart.tsx       (old render-props)
│   │       └── Checkout.tsx
│   ├── services/
│   │   ├── current-cart-service.ts
│   │   ├── checkout-service.ts
│   │   ├── selected-option-service.ts
│   │   ├── common-types.ts
│   │   └── index.ts
│   ├── mappers/
│   │   └── line-item-to-selected-options.ts
│   └── data-component-tags.ts
├── dist/                             (built ESM output)
└── cjs/                              (built CommonJS output)
```

## 🛠️ Development

### Setup

```bash
# Install dependencies (from monorepo root)
yarn install

# Build this package
cd packages/headless-components/ecom
yarn build
```

### Testing

⚠️ **Important**: Always use `--run` flag to avoid interactive watch mode.

```bash
# Run tests (non-interactive)
yarn test --run

# Run tests with verbose output
yarn test --run --reporter=verbose

# Run tests with coverage
yarn test --run --coverage
```

### Build

```bash
# Build both ESM and CommonJS
yarn build

# Build ESM only
yarn build:esm

# Build CommonJS only
yarn build:cjs
```

### Linting

```bash
# Lint and fix
yarn lint:fix

# Lint check (no changes)
yarn lint:check
```

## 📐 Design Patterns

### List, Options, and Repeater Pattern

This package follows the standard three-level architecture for list-based components:

```tsx
// Level 1: Container - provides context, conditional rendering
<Cart.LineItems>
  // Level 2: List container - handles empty state
  <Cart.LineItemsList emptyState={<div>Your cart is empty</div>}>
    // Level 3: Repeater - maps to LineItem.Root
    <Cart.LineItemRepeater>
      <LineItem.Title />
      <LineItem.Image />
    </Cart.LineItemRepeater>
  </Cart.LineItemsList>
</Cart.LineItems>
```

### AsChild Pattern

Components support the `asChild` prop for custom DOM structure:

```tsx
// Default rendering
<LineItem.Title>Product Name</LineItem.Title>
// Renders: <div>Product Name</div>

// With asChild - merges with child element
<LineItem.Title asChild>
  <h3 className="text-2xl font-bold">Product Name</h3>
</LineItem.Title>
// Renders: <h3 className="text-2xl font-bold">Product Name</h3>
```

### TestIds Pattern

All components use centralized TestIds enums:

```tsx
enum TestIds {
  cartRoot = 'cart-root',
  cartLineItems = 'cart-line-items',
  cartItem = 'cart-item',
  cartSummary = 'cart-summary',
}

// Usage in tests
screen.getByTestId('cart-root');
```

## 🚀 Deployment

This section describes how to roll out changes from the headless components package into the full Wix ecosystem (stores extension, kitchensink, Vibe plugins, and production extensions).

> **ℹ️ Note:** These steps are internal to Wix and assume access to the relevant private repositories and Falcon publishing.

---

### **1. Publish the package via Falcon**

1. Add your code changes to the headless components monorepo:  
   `@wix/headless-ecom` / `@wix/stores` in  
   **https://github.com/wix-private/headless-components/tree/master/packages/headless-components/stores**
2. Open a PR, get it reviewed, and merge into `master`.
3. Wait for Falcon to build and publish the new package version to the internal registry.

---

### **2. Update the Stores extension to re-export the new version**

Update the Stores extension to re-export the newly published version of `@wix/stores`:

- Bump the consumed version to the newly published one.

---

### **3. Update Kitchensink**

Update the kitchensink demo app to use the new version of `@wix/stores`:

1. In **https://github.com/wix-incubator/kitchensink**, bump the `@wix/stores` version.
2. Modify wrapper components or examples if API changes affect them.
3. Open a PR and merge it into `master` once tests pass.

---

### **4. Update `vibe-stores-plugin` via kitchen-sync**

1. In `vibe-stores-plugin-files`, run the **kitchen-sync** script to pull the updated files from kitchensink.
2. Open a PR containing the generated updates.
3. In the same PR, bump the plugin version in:  
   **https://github.com/wix-private/vibe-plugins/blob/master/plugins/stores/vibe-stores-plugin/package.json#L3**

---

### **5. Update the Dynamic Extension**

When the updated `@wix/vibe-stores-plugin` version is published:

1. Go to the extension in your app in dev center:  
2. Update the Store plugin version in the extension to the newly published one.
3. Publish the extension.

---



## 🔗 Dependencies

### Core Dependencies

```json
{
  "@wix/auto_sdk_ecom_checkout": "^1.0.61",
  "@wix/auto_sdk_ecom_current-cart": "^1.0.56",
  "@wix/headless-media": "workspace:*",
  "@wix/sdk": "^1.15.24",
  "@wix/services-manager-react": "^0.1.26",
  "@radix-ui/react-slot": "^1.1.0"
}
```

### Peer Dependencies

```json
{
  "@wix/headless-components": "^0.0.0"
}
```

## 📊 Package Exports

This package exports both ESM and CommonJS formats:

```json
{
  "exports": {
    "./react": {
      "types": "./dist/react/index.d.ts",
      "import": "./dist/react/index.js",
      "require": "./cjs/dist/react/index.js"
    },
    "./services": {
      "types": "./dist/services/index.d.ts",
      "import": "./dist/services/index.js",
      "require": "./cjs/dist/services/index.js"
    }
  }
}
```

## 📖 Related Documentation

- **Main README**: `/packages/headless-components/README.md` - Architecture guidelines
- **Implementation Status**: `/docs/IMPLEMENTATION_STATUS.md` - Complete component checklist
- **API Documentation**: `/docs/api/ECOM_INTERFACE.md` - E-commerce API specifications
- **Contributing**: `/CONTRIBUTING.md` - Contribution guidelines

## 🔍 Examples

Check out these example projects using this package:

- `examples/astro-stores-demo/` - Complete store implementation
- `examples/astro-restaurants-olo-demo/` - Online ordering with cart
