@kraftwerkdesign/c7-components
v0.1.8
Published
Lit-based Commerce7 web components.
Readme
@kraftwerkdesign/c7-components
Lit-based Commerce7 web components for Kraftwerk Design projects.
Install
npm install @kraftwerkdesign/c7-componentsUsage
import { setC7Config } from '@kraftwerkdesign/c7-components'
import '@kraftwerkdesign/c7-components'
setC7Config({
tenant: 'your-tenant',
tenantId: 'your-tenant',
apiBase: 'https://api.commerce7.com',
})<c7-add-to-cart product-slug="sample-product" quantity="1"></c7-add-to-cart>Components
<c7-add-to-cart>
Attributes:
product-slug(required): Commerce7 product slug.quantity(optional): Quantity to add, defaults to1.
CSS parts:
wrapper: The outermostdivwrapping the entire component.button-wrapper: The clickable wrapper container around the button slot.button: The default button element (when not using a slot).status: The status message element.price-wrapper: The wrapperdivaround the default price display.price: The primary (actual) pricespan.compare-price: The struck-through list pricespan, rendered only whenaddToCartPricediffers fromprice.
CSS custom properties:
--c7wc-btn-bg--c7wc-btn-bg-hover--c7wc-btn-text--c7wc-btn-border--c7wc-btn-disabled-bg--c7wc-btn-disabled-text--c7wc-status-text--c7wc-price-text: Color of the primary price. Defaults toinherit.--c7wc-compare-price-text: Color of the compare (strikethrough) price. Defaults to#9c8d82.
Slots
The component supports three named slots for full customization:
priceslot: Custom price display. Rendered before the button. To populate it with the API price, adddata-c7-price/data-c7-add-to-cart-priceto elements inside the slot — see Custom Price Markup.buttonslot: Custom button HTML. The entire slot content is clickable.statusslot: Custom status message display.
<!-- Default (shows price + button automatically) -->
<c7-add-to-cart product-slug="sample-product"></c7-add-to-cart>
<!-- Custom price display -->
<c7-add-to-cart product-slug="sample-product">
<div slot="price" class="my-price"><!-- rendered by your own logic --></div>
</c7-add-to-cart>
<!-- Default button (baseline) -->
<c7-add-to-cart product-slug="sample-product"></c7-add-to-cart>
<!-- Custom button with Tailwind-style classes -->
<c7-add-to-cart product-slug="sample-product">
<button slot="button" class="bg-blue-600 text-white px-6 py-3 rounded-lg">Add to Cart</button>
</c7-add-to-cart>
<!-- Button with icon -->
<c7-add-to-cart product-slug="sample-product">
<span slot="button" class="flex items-center gap-2 bg-green-600 text-white px-4 py-2 rounded">
<svg><!-- cart icon --></svg>
<span>Add to Cart</span>
</span>
</c7-add-to-cart>
<!-- Custom status message -->
<c7-add-to-cart product-slug="sample-product">
<span slot="status" class="text-green-600 text-sm font-medium">✓ Successfully added!</span>
</c7-add-to-cart>
<!-- Fully customized -->
<c7-add-to-cart product-slug="sample-product">
<button slot="button" class="custom-btn">🛒 Buy Now - $29.99</button>
<div slot="status" class="custom-status">✅ Added to your cart!</div>
</c7-add-to-cart>Custom Price Markup
Place data-c7-price, data-c7-add-to-cart-price, or data-c7-compare-price on any element inside <c7-add-to-cart> to have it automatically filled with the formatted price from the API response. This works anywhere in the component's light DOM — inside a slot or alongside one.
<c7-add-to-cart product-slug="champagne-glasses">
<div slot="price" class="my-price">
<strong data-c7-add-to-cart-price></strong>
<del data-c7-price></del>
</div>
</c7-add-to-cart>| Attribute | Populated with |
| --------------------------- | ------------------------------------------------- |
| data-c7-price | Formatted retail price (e.g. "$65.00") |
| data-c7-compare-price | Formatted API compare price, or "" if none |
| data-c7-add-to-cart-price | Formatted add-to-cart/club price, or "" if none |
- Values are re-written whenever
product-slugchanges. - Multiple elements with the same attribute are all populated.
- Elements are left empty (
"") when the corresponding price isnull.
State-Based Styling
The component exposes state as data attributes on the host element for CSS targeting:
/* Default state */
c7-add-to-cart {
/* idle/ready */
}
/* Loading or adding state */
c7-add-to-cart[data-state='loading'],
c7-add-to-cart[data-state='adding'] {
/* loading styles */
}
/* Disabled states (sold out, retired, etc.) */
c7-add-to-cart[data-disabled='true'] {
/* disabled styles */
}
/* When product is available for purchase */
c7-add-to-cart[data-available='true'] {
/* available styles */
}
/* Example: Style custom slotted button based on state */
c7-add-to-cart[data-disabled='true'] [slot='button'] {
opacity: 0.6;
cursor: not-allowed;
}
c7-add-to-cart[data-state='adding'] [slot='button'] {
animation: pulse 1s infinite;
}
/* Example: Custom sold-out styling */
c7-add-to-cart[data-state='sold-out'] [slot='button'] {
background: #fee2e2;
color: #dc2626;
}JavaScript Access
Access component state and methods programmatically:
const cart = document.querySelector('c7-add-to-cart')
// Get current state
console.log(cart.state) // 'idle', 'loading', 'ready', 'adding', 'success', 'error', etc.
// Get current status message
console.log(cart.statusMessage) // 'Added', 'Sold Out', etc.
// Manually trigger add to cart
cart._productTask.run()Notes:
- Requires global configuration via
setC7ConfigfortenantandtenantId. - Optional
apiBasecan be set to point to a different Commerce7 API host. - If
window.c7action.showSideCartandwindow.c7action.reloadCartare defined, they will be called after a successful add. - When using slots, the click handler is automatically attached to the slot wrapper.
- The component is keyboard accessible - Enter and Space keys trigger the add-to-cart action.
Development
npm run devTests
npm testEnvironment Variables
Configure tests with these env variables (must use VITE_ prefix):
VITE_C7_TEST_TENANT=my-tenant VITE_C7_TEST_TENANT_ID=my-id VITE_C7_TEST_API_BASE=https://api.example.com npm testVITE_C7_TEST_TENANT- Tenant name (default: test-tenant)VITE_C7_TEST_TENANT_ID- Tenant ID (default: test-tenant-id)VITE_C7_TEST_API_BASE- API base URL (default: https://api.commerce7.com)
Stubbing Network Requests
Use the fetch mock utility to mock API calls in tests:
import { createFetchMock } from './test/fetch-mock'
const stubs = {
'my-product': { webStatus: 'Available', variants: [{ sku: 'SKU-001', hasInventory: true }] },
}
const { mock, restore } = createFetchMock(stubs)
window.fetch = mock
// run tests...
restore()Generate stubs from real API responses:
# Show available product slugs from Storybook stories
npm run generate-stubs --
# Generate stubs for all products in Storybook stories
npm run generate-stubs -- --from-stories
# Generate specific stubs
npm run generate-stubs -- product-1 product-2
# Override API base URL
VITE_C7_TEST_API_BASE=https://api.example.com npm run generate-stubs -- my-productThis extracts product slugs from src/stories/c7-add-to-cart.stories.ts and saves API responses to test/stubs/products/.
