@wix/agent-skills 1.13.0 → 1.15.0
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 +4 -1
- package/package.json +1 -1
- package/skills/README.md +23 -0
- package/skills/wix-app/SKILL.md +10 -2
- package/skills/wix-app/references/AUTO_PATTERNS_DASHBOARD.md +326 -0
- package/skills/wix-app/references/CODE_QUALITY.md +1 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +124 -115
- package/skills/wix-app/references/DASHBOARD_PAGE.md +3 -0
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +23 -9
- package/skills/wix-app/references/SITE_PLUGIN.md +1 -1
- package/skills/wix-app/references/auto-patterns-dashboard/action-cell.md +115 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-config-structure.md +264 -0
- package/skills/wix-app/references/auto-patterns-dashboard/app-context.md +37 -0
- package/skills/wix-app/references/auto-patterns-dashboard/bulk-actions.md +86 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page-actions.md +119 -0
- package/skills/wix-app/references/auto-patterns-dashboard/collection-page.md +103 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-actions-override.md +76 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-columns-override.md +82 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-components-override.md +89 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-header-override.md +124 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-sections-override.md +91 -0
- package/skills/wix-app/references/auto-patterns-dashboard/custom-slots-override.md +71 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-actions.md +70 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page-view-actions.md +73 -0
- package/skills/wix-app/references/auto-patterns-dashboard/entity-page.md +98 -0
- package/skills/wix-app/references/auto-patterns-dashboard/example-patterns.json +278 -0
- package/skills/wix-app/references/auto-patterns-dashboard/pages-configuration.md +94 -0
- package/skills/wix-app/references/auto-patterns-dashboard/resolved-action.md +43 -0
- package/skills/wix-app/references/auto-patterns-dashboard/sdk-utilities.md +66 -0
- package/skills/wix-app/references/auto-patterns-dashboard/views.md +76 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +1 -14
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +54 -29
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +2 -2
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +17 -105
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +127 -0
- package/skills/wix-app/references/editor-react-component/PARTS.md +2 -1
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +15 -15
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +25 -53
- package/skills/wix-app/scripts/generate-auto-patterns.js +510 -0
- package/skills/wix-auth/SKILL.md +12 -0
- package/skills/wix-auth/references/device-flow.md +140 -0
- package/skills/wix-docs/SKILL.md +188 -0
- package/skills/wix-docs/references/API_SPEC_SEARCH.md +213 -0
- package/skills/wix-docs/references/EXTRACTING.md +120 -0
- package/skills/wix-headless/SKILL.md +84 -130
- package/skills/wix-headless/entry/bootstrap.mjs +93 -0
- package/skills/wix-headless/entry/skill.md +78 -0
- package/skills/wix-headless/references/AI_FEATURES.md +178 -0
- package/skills/wix-headless/references/CAPABILITIES.md +84 -0
- package/skills/wix-headless/references/DISCOVERY.md +34 -56
- package/skills/wix-headless/references/DOC_DISCOVERY.md +37 -0
- package/skills/wix-headless/references/FEEDBACK.md +118 -0
- package/skills/wix-headless/references/IMAGE_GENERATION.md +69 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +97 -0
- package/skills/wix-headless/references/SEED.md +44 -188
- package/skills/wix-headless/references/SETUP.md +32 -103
- package/skills/wix-headless/references/astro.md +98 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +196 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +236 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-bookings.md +279 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-cms.md +163 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-events.md +203 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +222 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +160 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +118 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-portfolio.md +132 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +124 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +188 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-reservations.md +173 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurants.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-blog.md +175 -0
- package/skills/wix-headless/references/inline-recipes/setup-bookings.md +228 -0
- package/skills/wix-headless/references/inline-recipes/setup-cms.md +200 -0
- package/skills/wix-headless/references/inline-recipes/setup-events.md +196 -0
- package/skills/wix-headless/references/inline-recipes/setup-forms.md +174 -0
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +176 -0
- package/skills/wix-headless/references/inline-recipes/setup-portfolio.md +153 -0
- package/skills/wix-headless/references/inline-recipes/setup-pricing-plans.md +229 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-orders.md +161 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurant-reservations.md +117 -0
- package/skills/wix-headless/references/inline-recipes/setup-restaurants.md +152 -0
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +57 -0
- package/skills/wix-headless/references/managed/CONNECT.md +74 -0
- package/skills/wix-headless/references/managed/CREATE.md +130 -0
- package/skills/wix-headless/references/managed/DEPLOYMENT.md +57 -0
- package/skills/wix-headless/references/non-astro.md +59 -0
- package/skills/wix-headless/references/self-managed/AUTHENTICATION.md +22 -0
- package/skills/wix-headless/references/self-managed/DEPLOYMENT.md +7 -0
- package/skills/wix-headless/references/stripe/AUTHENTICATION.md +55 -0
- package/skills/wix-headless/references/stripe/DEPLOYMENT.md +63 -0
- package/skills/wix-manage/SKILL.md +24 -1
- package/skills/wix-manage/references/analytics/query-site-analytics.md +241 -0
- package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +1 -1
- package/skills/wix-manage/references/bookings/diagnose-availability-issues.md +265 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +436 -0
- package/skills/wix-manage/references/marketing/generate-and-publish-marketing-plan.md +209 -0
- package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +249 -0
- package/skills/wix-manage/references/stores/create-product-with-options-catalog-v3.md +51 -0
- package/skills/wix-vibe-headless/SKILL.md +136 -0
- package/skills/wix-vibe-headless/references/blog/INSTRUCTIONS.md +128 -0
- package/skills/wix-vibe-headless/references/blog/wix-blog.js +217 -0
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +153 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-checkout.js +147 -0
- package/skills/wix-vibe-headless/references/bookings/wix-bookings-services.js +215 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +154 -0
- package/skills/wix-vibe-headless/references/cms/wix-cms.js +186 -0
- package/skills/wix-vibe-headless/references/events/INSTRUCTIONS.md +142 -0
- package/skills/wix-vibe-headless/references/events/wix-events-browse.js +135 -0
- package/skills/wix-vibe-headless/references/events/wix-events-registration.js +187 -0
- package/skills/wix-vibe-headless/references/members/INSTRUCTIONS.md +211 -0
- package/skills/wix-vibe-headless/references/members/wix-members-auth.js +387 -0
- package/skills/wix-vibe-headless/references/portfolio/INSTRUCTIONS.md +111 -0
- package/skills/wix-vibe-headless/references/portfolio/wix-portfolio.js +194 -0
- package/skills/wix-vibe-headless/references/pricing-plans/INSTRUCTIONS.md +127 -0
- package/skills/wix-vibe-headless/references/pricing-plans/wix-pricing-plans.js +157 -0
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +138 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-menu.js +224 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-ordering.js +156 -0
- package/skills/wix-vibe-headless/references/restaurants/wix-restaurants-reservations.js +107 -0
- package/skills/wix-vibe-headless/references/shared/wix-client.js +186 -0
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +155 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-cart.js +147 -0
- package/skills/wix-vibe-headless/references/storefront/wix-store-catalog.js +142 -0
- package/skills/wix-headless/references/BUILD-astro.md +0 -244
- package/skills/wix-headless/references/BUILD-own-build.md +0 -167
- package/skills/wix-headless/references/BUILD.md +0 -105
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +0 -165
- package/skills/wix-headless/references/DISCOVERY-connect.md +0 -55
- package/skills/wix-headless/references/DISCOVERY-create.md +0 -238
- package/skills/wix-headless/references/PLAN-connect.md +0 -19
- package/skills/wix-headless/references/PLAN-create.md +0 -17
- package/skills/wix-headless/references/PLAN.md +0 -92
- package/skills/wix-headless/references/astro/blog/BLOG_PAGES.md +0 -300
- package/skills/wix-headless/references/astro/blog/BLOG_SETUP.md +0 -218
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +0 -45
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +0 -77
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +0 -214
- package/skills/wix-headless/references/astro/cms/FAQ_KNOWLEDGE_BASE.md +0 -231
- package/skills/wix-headless/references/astro/cms/PORTFOLIO.md +0 -453
- package/skills/wix-headless/references/astro/cms/RESOURCE_LIBRARY.md +0 -354
- package/skills/wix-headless/references/astro/cms/TEAM_DIRECTORY.md +0 -299
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +0 -351
- package/skills/wix-headless/references/astro/ecom/CART_PAGES.md +0 -119
- package/skills/wix-headless/references/astro/ecom/CART_WIRING.md +0 -103
- package/skills/wix-headless/references/astro/ecom/COMPONENTS_CSS.md +0 -132
- package/skills/wix-headless/references/astro/forms/CONTACT_FORM.md +0 -463
- package/skills/wix-headless/references/astro/gift-cards/COMPONENTS.md +0 -119
- package/skills/wix-headless/references/astro/gift-cards/PAGES.md +0 -129
- package/skills/wix-headless/references/astro/stores/BACK_IN_STOCK.md +0 -178
- package/skills/wix-headless/references/astro/stores/CATEGORY_PAGES.md +0 -85
- package/skills/wix-headless/references/astro/stores/COMPONENTS_CSS.md +0 -129
- package/skills/wix-headless/references/astro/stores/HOME_AND_NAV.md +0 -229
- package/skills/wix-headless/references/astro/stores/PRODUCT_PAGES.md +0 -215
- package/skills/wix-headless/references/astro/stores/SHARED_WIRING.md +0 -165
- package/skills/wix-headless/references/astro/templates/Footer.astro +0 -27
- package/skills/wix-headless/references/astro/templates/Layout.astro +0 -132
- package/skills/wix-headless/references/astro/templates/Navigation.astro +0 -38
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +0 -41
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +0 -374
- package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +0 -136
- package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +0 -25
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +0 -71
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +0 -54
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +0 -49
- package/skills/wix-headless/references/astro/templates/bookings/bookingDriver.ts +0 -245
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +0 -424
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +0 -176
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +0 -181
- package/skills/wix-headless/references/astro/templates/ecom/CartBadge.tsx +0 -84
- package/skills/wix-headless/references/astro/templates/ecom/CartView.tsx +0 -543
- package/skills/wix-headless/references/astro/templates/ecom/cart.astro +0 -13
- package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +0 -302
- package/skills/wix-headless/references/astro/templates/ecom/discounts.ts +0 -71
- package/skills/wix-headless/references/astro/templates/ecom/thank-you.astro +0 -24
- package/skills/wix-headless/references/astro/templates/gift-cards/GiftCardPurchase.tsx +0 -172
- package/skills/wix-headless/references/astro/templates/gift-cards/_home-teaser-snippet.astro +0 -42
- package/skills/wix-headless/references/astro/templates/gift-cards/_nav-snippet.astro +0 -11
- package/skills/wix-headless/references/astro/templates/gift-cards/components-gift-cards.css +0 -220
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.astro +0 -51
- package/skills/wix-headless/references/astro/templates/gift-cards/gift-cards.ts +0 -75
- package/skills/wix-headless/references/astro/templates/global.css +0 -288
- package/skills/wix-headless/references/astro/templates/index.astro +0 -56
- package/skills/wix-headless/references/astro/templates/stores/AddToCartButton.tsx +0 -77
- package/skills/wix-headless/references/astro/templates/stores/BackInStockForm.tsx +0 -176
- package/skills/wix-headless/references/astro/templates/stores/CategoryRail.astro +0 -69
- package/skills/wix-headless/references/astro/templates/stores/ProductCard.astro +0 -79
- package/skills/wix-headless/references/astro/templates/stores/ProductPurchase.tsx +0 -397
- package/skills/wix-headless/references/astro/templates/stores/SeoTags.astro +0 -21
- package/skills/wix-headless/references/astro/templates/stores/back-in-stock.ts +0 -67
- package/skills/wix-headless/references/astro/templates/stores/categories.ts +0 -155
- package/skills/wix-headless/references/astro/templates/stores/category/[slug].astro +0 -130
- package/skills/wix-headless/references/astro/templates/stores/components-stores.css +0 -400
- package/skills/wix-headless/references/astro/templates/stores/products/[slug].astro +0 -128
- package/skills/wix-headless/references/astro/templates/stores/products/index.astro +0 -101
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +0 -161
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +0 -32
- package/skills/wix-headless/references/bookings/FLOW.md +0 -246
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +0 -95
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +0 -355
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +0 -176
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +0 -71
- package/skills/wix-headless/references/commands/known-apps.json +0 -6
- package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +0 -142
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +0 -88
- package/skills/wix-headless/references/custom/blog/WIRING.md +0 -52
- package/skills/wix-headless/references/custom/bookings/WIRING.md +0 -197
- package/skills/wix-headless/references/custom/cms/WIRING.md +0 -97
- package/skills/wix-headless/references/custom/ecom/WIRING.md +0 -67
- package/skills/wix-headless/references/custom/forms/WIRING.md +0 -101
- package/skills/wix-headless/references/custom/stores/WIRING.md +0 -80
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +0 -59
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +0 -43
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +0 -51
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +0 -357
- package/skills/wix-headless/references/seed-recipes.md +0 -49
- package/skills/wix-headless/references/shared/AGENTS_MD.md +0 -47
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +0 -108
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +0 -8
- package/skills/wix-headless/references/shared/DESIGN_MD.md +0 -84
- package/skills/wix-headless/references/shared/DOCS_SEARCH.md +0 -41
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +0 -186
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +0 -206
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +0 -97
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +0 -143
- package/skills/wix-headless/references/shared/STYLING.md +0 -141
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +0 -126
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +0 -252
- package/skills/wix-headless/references/verticals/_schema.json +0 -74
- package/skills/wix-headless/references/verticals/_schema.md +0 -95
- package/skills/wix-headless/references/verticals/blog.md +0 -31
- package/skills/wix-headless/references/verticals/bookings.md +0 -41
- package/skills/wix-headless/references/verticals/cms.md +0 -30
- package/skills/wix-headless/references/verticals/ecom.md +0 -25
- package/skills/wix-headless/references/verticals/forms.md +0 -26
- package/skills/wix-headless/references/verticals/gift-cards.md +0 -24
- package/skills/wix-headless/references/verticals/stores.md +0 -33
- package/skills/wix-headless/scripts/check-manifest.mjs +0 -335
- package/skills/wix-headless/scripts/compose.mjs +0 -525
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +0 -157
- package/skills/wix-headless/scripts/flatten.sh +0 -61
- package/skills/wix-headless/scripts/generate-images.mjs +0 -242
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +0 -148
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +0 -190
- package/skills/wix-headless/scripts/scaffold.sh +0 -139
- package/skills/wix-headless/scripts/seed-utilities.sh +0 -93
- package/skills/wix-headless/scripts/write-decorative-json.mjs +0 -62
- package/skills/wix-headless/shared-utilities/analytics.ts +0 -40
- package/skills/wix-headless/shared-utilities/ricos.ts +0 -179
- package/skills/wix-headless/shared-utilities/wix-image.ts +0 -72
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
# Phase 3 Components-CSS — Ecom
|
|
2
|
-
|
|
3
|
-
**This stylesheet is pre-copied from the skill template by the orchestrator** (build-wave pre-batch, BUILD-astro.md § "Step 4.5") — there is no `components-css` subagent to dispatch. This file documents the CSS for reference so the ecom `components` scope (in the merged build agent) knows the class-name surface it targets.
|
|
4
|
-
|
|
5
|
-
## What this scope owns
|
|
6
|
-
|
|
7
|
-
Exactly one file:
|
|
8
|
-
|
|
9
|
-
- `src/styles/components-ecom.css` — scoped CSS for cart/checkout: cart-summary panel, cart-total row, checkout button (with `:disabled` and `:hover` states), empty state, cart-item line layout (image, name, qty controls, prices, modifiers, unavailable state, remove button), discount/applied-discount rows, and the cart-badge nav element. Imported by `Layout.astro` (the designer foundation sets up the import).
|
|
10
|
-
|
|
11
|
-
## What this scope does NOT own
|
|
12
|
-
|
|
13
|
-
- Any `.tsx` or `.astro` file. Those are the `components` sibling scope (`./CART_WIRING.md`).
|
|
14
|
-
- `src/styles/global.css` — owned by the designer foundation. **You read it (to audit for ecom-class leaks) but never write it.**
|
|
15
|
-
- `src/styles/components-stores.css`, `src/styles/components-gift-cards.css` — owned by other packs' `components-css` (or `components`) scopes.
|
|
16
|
-
- `src/utils/discounts.ts` — pre-copied by the orchestrator before this dispatch; not your concern.
|
|
17
|
-
|
|
18
|
-
## Reading set
|
|
19
|
-
|
|
20
|
-
You only need:
|
|
21
|
-
|
|
22
|
-
1. **`<SKILL_ROOT>/references/astro/templates/ecom/components-ecom.css`** — the canonical template. Read it once.
|
|
23
|
-
2. **`<SKILL_ROOT>/references/shared/STYLING.md`** — the styling-contract conventions (how to use `@apply`, the `@theme` token utilities, the no-default-Tailwind-colors rule, and the global-vs-scoped CSS ownership boundary).
|
|
24
|
-
3. **`<SKILL_ROOT>/references/shared/RETURN_CONTRACT.md`** — the return JSON shape.
|
|
25
|
-
4. **`src/styles/global.css`** in the project — read to audit for ecom-class leaks (see § "Global-CSS leak audit" below).
|
|
26
|
-
5. **Design tokens (on disk)** — read the design tokens (the DESIGN.md vocabulary — `colors`/`typography`/`rounded`/`containers`; spacing is Tailwind's numeric scale, not a token) from `.wix/design-tokens.css` (gate-verified present before the wave). They are NOT inlined in your prompt.
|
|
27
|
-
|
|
28
|
-
You do NOT need to read `INSTRUCTIONS.md`, `CART_WIRING.md`, the TSX templates, the `discounts.ts` util, or any other reference. Skipping those reads is the point of the split.
|
|
29
|
-
|
|
30
|
-
## Implementation
|
|
31
|
-
|
|
32
|
-
### 1. Read the template
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
<SKILL_ROOT>/references/astro/templates/ecom/components-ecom.css
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
This is the canonical scoped CSS for the ecom pack. Adapt sizing/spacing to the brand's aesthetic — use the design tokens from your prompt (`--color-bark`, `--color-cream`, `--radius-md`, `--font-display`, etc.); spacing uses Tailwind's numeric scale (`gap-4`, `py-24`), not a token. **Do not rename the class names or state modifiers** — they must match the contract keys the TSX components reference.
|
|
39
|
-
|
|
40
|
-
### 2. The two `@reference` directives are mandatory
|
|
41
|
-
|
|
42
|
-
The first two non-comment lines of `components-ecom.css` MUST be:
|
|
43
|
-
|
|
44
|
-
```css
|
|
45
|
-
@reference "tailwindcss";
|
|
46
|
-
@reference "./global.css";
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Without these, Tailwind v4 fails the build with `"Cannot apply unknown utility class"` on any `@apply` rule that uses a utility like `size-6` or `gap-4`. The template ships them; do not remove.
|
|
50
|
-
|
|
51
|
-
### 3. Class ownership
|
|
52
|
-
|
|
53
|
-
Classes defined in `components-ecom.css` (this is the **single source of truth** — the designer's `global.css` does NOT publish these):
|
|
54
|
-
|
|
55
|
-
- **`.cart-summary` / `.cart-total` / `.cart-empty`** — the `/cart` page summary panel (sticky on desktop), total row, and empty-state. The `.cart-empty .checkout-btn` rule scopes the empty-state CTA to inline-flex with a max-width so it doesn't render full-width.
|
|
56
|
-
- **`.checkout-btn`** — primary checkout button, with `:disabled` and `:hover:not(:disabled)` states. **Composes from `.btn-primary`** (which IS a designer-owned plain-CSS rule in `global.css`). Do **NOT** use `@apply btn-primary` here — Tailwind v4 only `@apply`s utilities declared with `@utility` (which `btn` is in `global.css`), not plain custom classes. The build fails with `Cannot apply unknown utility class 'btn-primary'` if you try. Use `composes` via flat property repetition or extend manually.
|
|
57
|
-
- **`.cart-item-*`** — full row primitives: `cart-item-qty`, `qty-btn`, `qty-value`, `cart-item-unavailable`, `cart-item-actions`, `cart-item-prices`, `cart-item-full-price`, `cart-item-unit-price`, `cart-item-line-total`, `cart-item-remove`, `cart-item-image-link`, `cart-item-name-link`, `cart-item-option`, `cart-item-modifiers`. CartView.tsx references these by name; renaming breaks the page.
|
|
58
|
-
- **`.cart-discount` / `.cart-discount-name` / `.cart-discount-amount`** — the discount row in the summary.
|
|
59
|
-
- **`.cart-applied-discounts` / `.cart-applied-discounts-name`** — the name-only applied-discounts row (line-item automatic discounts).
|
|
60
|
-
- **`.cart-badge` / `.cart-badge-count`** — the nav badge (mounted in `Navigation.astro` via the ecom `pages` scope's CartBadge).
|
|
61
|
-
|
|
62
|
-
Classes you do NOT own:
|
|
63
|
-
|
|
64
|
-
- `.btn`, `.btn-primary`, `.btn-secondary` — designer's `global.css` (`.btn` is a Tailwind v4 `@utility`).
|
|
65
|
-
- Anything in `components-stores.css` (option pills, product card, product grid, offer callout) — owned by stores pack.
|
|
66
|
-
- Anything in `components-gift-cards.css` — owned by gift-cards pack.
|
|
67
|
-
|
|
68
|
-
### 4. Global-CSS leak audit
|
|
69
|
-
|
|
70
|
-
Before writing your file, **read `src/styles/global.css`** and grep for any class your scope owns. Ecom-specific rules sometimes leak into the designer's foundation:
|
|
71
|
-
|
|
72
|
-
- Any `.cart-summary`, `.cart-total`, `.cart-empty`, `.checkout-btn` rule.
|
|
73
|
-
- Any `.cart-item-*` rule.
|
|
74
|
-
- Any `.cart-badge` rule.
|
|
75
|
-
- Any `.cart-discount` / `.cart-applied-discounts` rule.
|
|
76
|
-
|
|
77
|
-
If you find a leak, do NOT edit `global.css` (the designer owns it). Instead:
|
|
78
|
-
|
|
79
|
-
1. Override the rule with the complete declaration in `components-ecom.css` (later imports win in CSS cascade because Layout.astro imports `components-ecom.css` AFTER `global.css`).
|
|
80
|
-
2. Add `{code: "GLOBAL_CSS_LEAK", class: "<name>", file: "src/styles/global.css"}` to your return JSON's `errors` array — non-fatal but tracked.
|
|
81
|
-
|
|
82
|
-
### 5. Write the file
|
|
83
|
-
|
|
84
|
-
Write the adapted CSS to `src/styles/components-ecom.css`. The orchestrator's post-Phase-3 manifest check verifies the file exists.
|
|
85
|
-
|
|
86
|
-
## Coordination: design tokens
|
|
87
|
-
|
|
88
|
-
Read the design tokens from `.wix/design-tokens.css` (on disk, gate-verified present before the wave) — they are NOT inlined in your prompt.
|
|
89
|
-
|
|
90
|
-
## Return format
|
|
91
|
-
|
|
92
|
-
```json
|
|
93
|
-
{
|
|
94
|
-
"status": "complete",
|
|
95
|
-
"phase": "ecom-components-css",
|
|
96
|
-
"scope": "components-css",
|
|
97
|
-
"summary": "Wrote components-ecom.css from template, adapted to brand tokens",
|
|
98
|
-
"data": {
|
|
99
|
-
"scopedCssFile": "src/styles/components-ecom.css",
|
|
100
|
-
"scopedCssRules": 22,
|
|
101
|
-
"scopedContractClassesDefined": [
|
|
102
|
-
"cart-summary", "cart-total", "cart-empty", "checkout-btn",
|
|
103
|
-
"cart-item-qty", "qty-btn", "qty-value", "cart-item-unavailable",
|
|
104
|
-
"cart-item-actions", "cart-item-prices", "cart-item-full-price",
|
|
105
|
-
"cart-item-unit-price", "cart-item-line-total", "cart-item-remove",
|
|
106
|
-
"cart-item-image-link", "cart-item-name-link",
|
|
107
|
-
"cart-item-option", "cart-item-modifiers",
|
|
108
|
-
"cart-discount", "cart-discount-name", "cart-discount-amount",
|
|
109
|
-
"cart-applied-discounts", "cart-applied-discounts-name",
|
|
110
|
-
"cart-badge", "cart-badge-count"
|
|
111
|
-
]
|
|
112
|
-
},
|
|
113
|
-
"files": [
|
|
114
|
-
"src/styles/components-ecom.css"
|
|
115
|
-
],
|
|
116
|
-
"errors": []
|
|
117
|
-
}
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
If a leak was found and overridden, include `errors: [{code: "GLOBAL_CSS_LEAK", class: "<name>", file: "src/styles/global.css"}]`.
|
|
121
|
-
|
|
122
|
-
## Anti-patterns
|
|
123
|
-
|
|
124
|
-
| WRONG | CORRECT |
|
|
125
|
-
|-------|---------|
|
|
126
|
-
| Read `INSTRUCTIONS.md`, `CART_WIRING.md`, or any `.tsx` template | Not needed — this scope only writes CSS |
|
|
127
|
-
| Edit `src/styles/global.css` to fix a leak | Override in `components-ecom.css`; report the leak in `errors` |
|
|
128
|
-
| Use default Tailwind colors (`bg-green-50`, `text-red-600`) | Brand `@theme` utilities (`bg-bark`, `text-cream`) or `var(--color-...)` |
|
|
129
|
-
| `@apply btn-primary` on `.checkout-btn` | Tailwind v4 only `@apply`s `@utility` declarations, not plain CSS rules — build fails. Either repeat the properties manually or compose via `composes` |
|
|
130
|
-
| Rename a class because the brand is "more elegant" with kebab variants | Class names are contract keys; renaming breaks every TSX import that references them |
|
|
131
|
-
| Skip the leak audit | Skipping ships double-defined rules; the audit is < 5 s and prevents downstream visual regressions |
|
|
132
|
-
| Drop the `@reference` directives | Tailwind v4 needs both — without them, `@apply size-6` and similar fail at build |
|
|
@@ -1,463 +0,0 @@
|
|
|
1
|
-
# Recipe: Contact / Lead / Signup Form
|
|
2
|
-
|
|
3
|
-
Build a complete form feature using `@wix/forms` — server-side schema fetching + client-side submission.
|
|
4
|
-
|
|
5
|
-
> **Critical Rules — Read Before Starting**
|
|
6
|
-
> 1. **Style migration mandatory** — when replacing `.astro` placeholder with a React island, copy the `<style is:global>` block to the page file or all form styles vanish (invisible inputs on dark sites).
|
|
7
|
-
> 2. **Form creation is TWO steps** — POST to create, then PATCH to add `postSubmissionTriggers`. Skipping the PATCH means submissions are silently lost (no CRM Contact created).
|
|
8
|
-
> 3. **Namespace propagation** — if form creation fails with `UNSUPPORTED_FORM_NAMESPACE`, wait 10s and retry up to 3 times. Do NOT fall back to hardcoded fields — a form without a `formId` cannot submit to Wix.
|
|
9
|
-
> 4. **Discover forms via SDK** — use `forms.listForms("wix.form_app.form")` with `auth.elevate`. Never hardcode form field IDs or form ID.
|
|
10
|
-
|
|
11
|
-
> **⚠️ CRITICAL — Style Migration Required:** When you replace the designed `.astro` form placeholder with a React island, the placeholder's `<style is:global>` block is no longer rendered and ALL form styles vanish. You MUST copy the entire `<style is:global>` block from the designed component into the page file. Without this, form inputs are invisible on dark sites. See Step 1.4 below.
|
|
12
|
-
|
|
13
|
-
## Prerequisites
|
|
14
|
-
|
|
15
|
-
- Wix Forms app must be installed on the site (installed via the apps-installer REST endpoint after scaffolding, or manually in the Wix dashboard)
|
|
16
|
-
- `@wix/forms` package installed: `npm install @wix/forms`
|
|
17
|
-
|
|
18
|
-
> **Forms are auto-created during scaffolding.** When scaffolding with a forms template (e.g., the Registration template `e5d63bf1-cd06-48eb-ad77-0da9235adcf1`), a form is automatically created on the site with server-side privileges. Use `forms.listForms("wix.form_app.form")` with `auth.elevate` to discover it — no manual form ID needed. If no forms exist, use the REST API Form Setup below to create one (the Create Form API is not available to headless SDK calls, but the CLI-minted REST token can create forms).
|
|
19
|
-
|
|
20
|
-
## Form Setup (REST)
|
|
21
|
-
|
|
22
|
-
Before writing any form code, ensure a contact form exists on the site via the form-schema REST API:
|
|
23
|
-
|
|
24
|
-
1. **List forms** — `REST: GET https://www.wixapis.com/form-schema-service/v4/forms?namespace=wix.form_app.form`
|
|
25
|
-
2. **If the API returns a "missing installed app" error** → install the Wix Forms app:
|
|
26
|
-
```
|
|
27
|
-
REST: POST https://www.wixapis.com/apps-installer-service/v1/app-instance/install
|
|
28
|
-
body: {
|
|
29
|
-
"tenant": { "tenantType": "SITE", "id": "<siteId>" },
|
|
30
|
-
"appInstance": { "appDefId": "225dd912-7dea-4738-8688-4b8c6955ffc2", "enabled": true }
|
|
31
|
-
}
|
|
32
|
-
```
|
|
33
|
-
> Translate this prose-HTTP form into the full `curl` tool-call shape — pass `body` as JSON in `-d` (NOT a stringified JSON). See `../../shared/AUTHENTICATION.md` for the standard REST headers.
|
|
34
|
-
|
|
35
|
-
Then retry listing forms.
|
|
36
|
-
3. **If forms list is empty** → create a form. This is a two-step atomic operation (POST to create, then PATCH to add `postSubmissionTriggers`) — see step 4 for the full procedure and rationale.
|
|
37
|
-
|
|
38
|
-
> **Namespace propagation:** If form creation fails with `UNSUPPORTED_FORM_NAMESPACE` immediately after installing the Forms app, the namespace hasn't propagated yet. Wait 10 seconds and retry up to 3 times. Do NOT silently fall back to static field definitions — forms without a `formId` cannot submit to Wix.
|
|
39
|
-
|
|
40
|
-
Select only the fields needed for the form's purpose.
|
|
41
|
-
|
|
42
|
-
**Field building blocks** — assemble the `formFields` array from these individual definitions:
|
|
43
|
-
|
|
44
|
-
```jsonc
|
|
45
|
-
// EMAIL (required for all form types)
|
|
46
|
-
{
|
|
47
|
-
"id": "191b2fae-7313-467a-9d4f-fd85598b1bdb",
|
|
48
|
-
"hidden": false, "identifier": "CONTACTS_EMAIL", "fieldType": "INPUT",
|
|
49
|
-
"inputOptions": {
|
|
50
|
-
"target": "email", "pii": true, "required": true, "inputType": "STRING", "readOnly": false,
|
|
51
|
-
"stringOptions": { "validation": { "format": "EMAIL", "enum": [] }, "componentType": "TEXT_INPUT", "textInputOptions": { "label": "Email", "showLabel": true } }
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// FIRST_NAME
|
|
56
|
-
{
|
|
57
|
-
"id": "c16f3def-fc74-4950-3b72-46dbdc132a90",
|
|
58
|
-
"hidden": false, "identifier": "CONTACTS_FIRST_NAME", "fieldType": "INPUT",
|
|
59
|
-
"inputOptions": {
|
|
60
|
-
"target": "first_name", "pii": true, "required": false, "inputType": "STRING", "readOnly": false,
|
|
61
|
-
"stringOptions": { "validation": { "format": "UNKNOWN_FORMAT", "enum": [] }, "componentType": "TEXT_INPUT", "textInputOptions": { "label": "First name", "showLabel": true } }
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// LAST_NAME
|
|
66
|
-
{
|
|
67
|
-
"id": "84242617-c855-486f-4ec6-87443210fb4f",
|
|
68
|
-
"hidden": false, "identifier": "CONTACTS_LAST_NAME", "fieldType": "INPUT",
|
|
69
|
-
"inputOptions": {
|
|
70
|
-
"target": "last_name", "pii": true, "required": false, "inputType": "STRING", "readOnly": false,
|
|
71
|
-
"stringOptions": { "validation": { "format": "UNKNOWN_FORMAT", "enum": [] }, "componentType": "TEXT_INPUT", "textInputOptions": { "label": "Last name", "showLabel": true } }
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// PHONE
|
|
76
|
-
{
|
|
77
|
-
"id": "5f5995cc-2951-4ce9-ae89-82ff487b1619",
|
|
78
|
-
"hidden": false, "identifier": "CONTACTS_PHONE", "fieldType": "INPUT",
|
|
79
|
-
"inputOptions": {
|
|
80
|
-
"target": "phone", "pii": true, "required": false, "inputType": "STRING", "readOnly": false,
|
|
81
|
-
"stringOptions": { "validation": { "format": "PHONE", "enum": [] }, "componentType": "PHONE_INPUT", "phoneInputOptions": { "label": "Phone", "showLabel": true } }
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// MESSAGE
|
|
86
|
-
// ⚠️ **Naming trap:** The MESSAGE field uses `identifier: "TEXT_AREA"` but its
|
|
87
|
-
// `componentType` MUST be `"TEXT_INPUT"`. The API will reject `componentType: "TEXT_AREA"`
|
|
88
|
-
// — that enum value does not exist in the Forms API. The `identifier` controls how the
|
|
89
|
-
// Wix dashboard renders the field; `componentType` controls API schema validation.
|
|
90
|
-
// Do not confuse the two.
|
|
91
|
-
{
|
|
92
|
-
"id": "ce6fc634-bc35-48ef-6f01-c2cded75d836",
|
|
93
|
-
"hidden": false, "identifier": "TEXT_AREA", "fieldType": "INPUT",
|
|
94
|
-
"inputOptions": {
|
|
95
|
-
"target": "message", "pii": false, "required": false, "inputType": "STRING", "readOnly": false,
|
|
96
|
-
"stringOptions": { "validation": { "format": "UNKNOWN_FORMAT", "enum": [] }, "componentType": "TEXT_INPUT", "textInputOptions": { "label": "Message", "showLabel": true } }
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// SUBMIT BUTTON (always include as the last field)
|
|
101
|
-
{
|
|
102
|
-
"id": "fe946b52-9719-4c57-57e8-a0791c29344f",
|
|
103
|
-
"hidden": false, "identifier": "SUBMIT_BUTTON", "fieldType": "DISPLAY",
|
|
104
|
-
"displayOptions": { "displayFieldType": "PAGE_NAVIGATION", "pageNavigationOptions": { "nextPageText": "Next", "previousPageText": "Back", "submitText": "Submit" } }
|
|
105
|
-
}
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
**Assembly by purpose:**
|
|
109
|
-
|
|
110
|
-
| Purpose | Fields to include | Layout rows |
|
|
111
|
-
|---------|------------------|-------------|
|
|
112
|
-
| Waitlist / newsletter | EMAIL + SUBMIT | email row 0, submit row 1 |
|
|
113
|
-
| Lead capture | FIRST_NAME + EMAIL + SUBMIT | first_name row 0, email row 1, submit row 2 |
|
|
114
|
-
| Contact (full) | FIRST_NAME + LAST_NAME + EMAIL + PHONE + MESSAGE + SUBMIT | first+last row 0 (6+6 cols), email row 1, phone row 2, message row 3, submit row 4 |
|
|
115
|
-
|
|
116
|
-
Build the `steps[0].layout.large.items` array to match — each field gets a `{ fieldId, row, column, width: 12, height: 1 }` entry. For side-by-side fields (first + last name), use `width: 6` with `column: 0` and `column: 6`.
|
|
117
|
-
|
|
118
|
-
The `postSubmissionTriggers.upsertContact.fieldsMapping` must only include mappings for fields that exist on the form. For a waitlist form with email only:
|
|
119
|
-
```json
|
|
120
|
-
"fieldsMapping": {
|
|
121
|
-
"email": { "contactField": "EMAIL", "emailInfo": { "tag": "UNTAGGED" } }
|
|
122
|
-
}
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
Full REST call structure:
|
|
126
|
-
```
|
|
127
|
-
REST: POST https://www.wixapis.com/form-schema-service/v4/forms
|
|
128
|
-
body: {
|
|
129
|
-
"form": {
|
|
130
|
-
"formFields": [ <selected fields from above> ],
|
|
131
|
-
"steps": [{ "id": "cfa7a3ed-ef11-4ae7-3a5b-7d450c86d217", "name": "Page 1", "hidden": false,
|
|
132
|
-
"layout": { "large": { "items": [ <layout entries matching selected fields> ] }}
|
|
133
|
-
}],
|
|
134
|
-
"name": "<Form Name matching purpose>",
|
|
135
|
-
"namespace": "wix.form_app.form",
|
|
136
|
-
"spamFilterProtectionLevel": "ADVANCED",
|
|
137
|
-
"enabled": true,
|
|
138
|
-
"postSubmissionTriggers": {
|
|
139
|
-
"upsertContact": {
|
|
140
|
-
"fieldsMapping": { <only mappings for included contact fields> },
|
|
141
|
-
"labels": []
|
|
142
|
-
}
|
|
143
|
-
},
|
|
144
|
-
"submitSettings": {
|
|
145
|
-
"submitSuccessAction": "THANK_YOU_MESSAGE",
|
|
146
|
-
"thankYouMessageOptions": {
|
|
147
|
-
"durationInSeconds": 8,
|
|
148
|
-
"richContent": { "nodes": [{ "type": "PARAGRAPH", "id": "krhc065", "nodes": [{ "type": "TEXT", "id": "", "nodes": [], "textData": { "text": "Thanks, we received your submission.", "decorations": [] } }], "paragraphData": { "textStyle": { "textAlignment": "CENTER" } } }] }
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
```
|
|
154
|
-
4. **Always PATCH `postSubmissionTriggers` after creation** — The creation API silently drops this field. Treat form creation as a two-step atomic operation:
|
|
155
|
-
- Step A: `POST /forms` to create the form
|
|
156
|
-
- Step B: `PATCH /forms/<formId>` to add `postSubmissionTriggers`
|
|
157
|
-
Never skip Step B, even if you included triggers in the creation payload. The cost of a redundant PATCH is zero; the cost of missing triggers is silent data loss (submissions recorded but no CRM contact created).
|
|
158
|
-
- GET the form: `GET https://www.wixapis.com/form-schema-service/v4/forms?namespace=wix.form_app.form`
|
|
159
|
-
- PATCH using the procedure in step 5 below
|
|
160
|
-
5. **If forms already exist** → verify the form has `postSubmissionTriggers.upsertContact`. This field is **critical** — without it, submissions are recorded but no Contact is created in the CRM. If missing, patch the form to add it:
|
|
161
|
-
```
|
|
162
|
-
REST: PATCH https://www.wixapis.com/form-schema-service/v4/forms/<formId>
|
|
163
|
-
body: {
|
|
164
|
-
"form": {
|
|
165
|
-
"revision": "<current revision from GET>",
|
|
166
|
-
"postSubmissionTriggers": {
|
|
167
|
-
"upsertContact": {
|
|
168
|
-
"fieldsMapping": {
|
|
169
|
-
<map each contact field target in the form, e.g.:>
|
|
170
|
-
"email": { "contactField": "EMAIL", "emailInfo": { "tag": "UNTAGGED" } },
|
|
171
|
-
"first_name": { "contactField": "FIRST_NAME" },
|
|
172
|
-
"last_name": { "contactField": "LAST_NAME" },
|
|
173
|
-
"phone": { "contactField": "PHONE", "phoneInfo": { "tag": "UNTAGGED" } }
|
|
174
|
-
},
|
|
175
|
-
"labels": []
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
```
|
|
181
|
-
Only include mappings for fields that exist on the form. The `fieldsMapping` keys must match the `inputOptions.target` values of the form's fields.
|
|
182
|
-
|
|
183
|
-
## Files to Modify / Create
|
|
184
|
-
|
|
185
|
-
| File | Action |
|
|
186
|
-
|------|--------|
|
|
187
|
-
| Existing designed page (e.g., `src/pages/contact.astro`) | **Modify in place** — add SDK imports and replace placeholder form with React island |
|
|
188
|
-
| `src/components/ContactForm.tsx` | **Create** — React island for client-side submission |
|
|
189
|
-
|
|
190
|
-
## Implementation
|
|
191
|
-
|
|
192
|
-
### 1. Modify the Existing Designed Page
|
|
193
|
-
|
|
194
|
-
**Do NOT create a new page from scratch.** The merged `contact-page` scope writes this page once — branded styling, layout, and `<style>` block alongside the form wiring (per `references/astro/designer/INSTRUCTIONS.md` → `contact-page`). When wiring an existing designed page, modify it in place:
|
|
195
|
-
|
|
196
|
-
1. **Add SDK imports** to the frontmatter:
|
|
197
|
-
```astro
|
|
198
|
-
import { forms } from "@wix/forms";
|
|
199
|
-
import { auth } from "@wix/essentials";
|
|
200
|
-
import ContactForm from "../components/ContactForm.tsx";
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
2. **Add the form discovery query** to the frontmatter:
|
|
204
|
-
```astro
|
|
205
|
-
const elevatedListForms = auth.elevate(forms.listForms);
|
|
206
|
-
const listResult = await elevatedListForms("wix.form_app.form");
|
|
207
|
-
const wixForm = listResult.forms?.[0];
|
|
208
|
-
const formId = wixForm?._id ?? "";
|
|
209
|
-
|
|
210
|
-
const formFields = wixForm?.formFields
|
|
211
|
-
?.filter((field) => field.fieldType === "INPUT" && !field.hidden)
|
|
212
|
-
.map((field) => {
|
|
213
|
-
const opts = field.inputOptions;
|
|
214
|
-
const str = opts?.stringOptions;
|
|
215
|
-
const label =
|
|
216
|
-
str?.textInputOptions?.label ??
|
|
217
|
-
str?.dropdownOptions?.label ??
|
|
218
|
-
str?.phoneInputOptions?.label ??
|
|
219
|
-
"";
|
|
220
|
-
return {
|
|
221
|
-
label,
|
|
222
|
-
target: opts?.target ?? "",
|
|
223
|
-
required: opts?.required ?? false,
|
|
224
|
-
componentType: str?.componentType ?? "TEXT_INPUT",
|
|
225
|
-
identifier: field.identifier ?? "",
|
|
226
|
-
options: str?.dropdownOptions?.options?.map((o) => ({
|
|
227
|
-
value: o.value ?? o.label ?? "",
|
|
228
|
-
label: o.label ?? o.value ?? "",
|
|
229
|
-
})),
|
|
230
|
-
};
|
|
231
|
-
}) ?? [];
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
3. **Replace the placeholder form HTML** with the React island:
|
|
235
|
-
```astro
|
|
236
|
-
{formId ? (
|
|
237
|
-
<ContactForm client:load formId={formId} fields={formFields} />
|
|
238
|
-
) : (
|
|
239
|
-
<p>No form found. Create one in the Wix dashboard.</p>
|
|
240
|
-
)}
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
4. **Migrate the form's `<style is:global>` block into the page.**
|
|
244
|
-
|
|
245
|
-
The designed Astro placeholder component (e.g., `ContactForm.astro`) contains a `<style is:global>` block with all form CSS. Once you replace the Astro import with the React island, that component is no longer rendered and its styles vanish.
|
|
246
|
-
|
|
247
|
-
- Open the designed Astro placeholder component and copy its entire `<style is:global>...</style>` block
|
|
248
|
-
- Paste it into the page file, below any existing `<style>` block
|
|
249
|
-
- Keep both `<style>` blocks — the page's scoped styles handle layout, the `is:global` block handles form elements inside the React island
|
|
250
|
-
- Do NOT remove or modify the page's existing `<style>` block
|
|
251
|
-
|
|
252
|
-
**Why `is:global` is required:** Astro scoped styles use `data-astro-cid-*` attributes that don't transfer to React-rendered DOM. The form styles must be global to reach elements inside the React island.
|
|
253
|
-
|
|
254
|
-
### 2. Contact Form Component (`src/components/ContactForm.tsx`)
|
|
255
|
-
|
|
256
|
-
The React island must match the designed component's class names and use CSS variables for all visual properties. Two approaches:
|
|
257
|
-
|
|
258
|
-
**Approach A (preferred): Page provides styles via `<style>` block.** The component reuses the class names from the designed placeholder. The page's existing `<style>` block handles all visual styling. The component only needs minimal inline styles for dynamic states.
|
|
259
|
-
|
|
260
|
-
**Approach B: Component owns its styles using CSS variables.** If the page doesn't have a `<style>` block for the form, the component includes a `<style>` JSX element using only CSS custom properties.
|
|
261
|
-
|
|
262
|
-
> **Styling note:** The React island uses the styling contract class names (`.form-container`, `.form-field`, `.form-label`, `.form-input`, `.form-textarea`, `.form-button`, `.form-success`, `.form-error`, `.form-field-error`, `.form-input-error`) from the designed ContactForm component's `<style is:global>` block. See `references/shared/STYLING.md` (Contact Form).
|
|
263
|
-
|
|
264
|
-
```tsx
|
|
265
|
-
import { useState } from "react";
|
|
266
|
-
import { submissions } from "@wix/forms";
|
|
267
|
-
|
|
268
|
-
interface FormField {
|
|
269
|
-
label: string;
|
|
270
|
-
target: string;
|
|
271
|
-
required: boolean;
|
|
272
|
-
componentType: string;
|
|
273
|
-
identifier?: string;
|
|
274
|
-
options?: { value: string; label: string }[];
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
interface ContactFormProps {
|
|
278
|
-
formId: string;
|
|
279
|
-
fields: FormField[];
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export default function ContactForm({ formId, fields }: ContactFormProps) {
|
|
283
|
-
const [formData, setFormData] = useState<Record<string, string>>({});
|
|
284
|
-
const [status, setStatus] = useState<"idle" | "submitting" | "success" | "error">("idle");
|
|
285
|
-
const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});
|
|
286
|
-
|
|
287
|
-
const handleSubmit = async (e: React.FormEvent) => {
|
|
288
|
-
e.preventDefault();
|
|
289
|
-
setStatus("submitting");
|
|
290
|
-
setFieldErrors({});
|
|
291
|
-
|
|
292
|
-
try {
|
|
293
|
-
const result = await submissions.createSubmission({
|
|
294
|
-
formId,
|
|
295
|
-
submissions: formData,
|
|
296
|
-
});
|
|
297
|
-
|
|
298
|
-
if (result.status === "PENDING" || result.status === "CONFIRMED") {
|
|
299
|
-
setStatus("success");
|
|
300
|
-
setFormData({});
|
|
301
|
-
} else {
|
|
302
|
-
setStatus("error");
|
|
303
|
-
}
|
|
304
|
-
} catch (err: unknown) {
|
|
305
|
-
const violations =
|
|
306
|
-
(err as any)?.details?.validationError?.fieldViolations ?? [];
|
|
307
|
-
const errorMap: Record<string, string> = {};
|
|
308
|
-
|
|
309
|
-
for (const v of violations) {
|
|
310
|
-
const fieldErrs: { errorPath?: string; errorMessage?: string }[] =
|
|
311
|
-
v?.data?.errors ?? [];
|
|
312
|
-
for (const fe of fieldErrs) {
|
|
313
|
-
if (fe.errorPath && !errorMap[fe.errorPath]) {
|
|
314
|
-
errorMap[fe.errorPath] = fe.errorMessage ?? "Invalid value";
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
if (Object.keys(errorMap).length > 0) {
|
|
320
|
-
setFieldErrors(errorMap);
|
|
321
|
-
setStatus("idle");
|
|
322
|
-
} else {
|
|
323
|
-
setStatus("error");
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
if (status === "success") {
|
|
329
|
-
return (
|
|
330
|
-
<div className="form-success">
|
|
331
|
-
Thank you! We'll be in touch soon.
|
|
332
|
-
</div>
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return (
|
|
337
|
-
<form onSubmit={handleSubmit} className="form-container">
|
|
338
|
-
{/* Styles come from the designed component's <style is:global> block.
|
|
339
|
-
Uses styling contract classes: .form-container, .form-field, .form-label,
|
|
340
|
-
.form-input, .form-select, .form-textarea, .form-button, .form-error,
|
|
341
|
-
.form-field-error, .form-input-error.
|
|
342
|
-
See references/shared/STYLING.md (Contact Form). */}
|
|
343
|
-
|
|
344
|
-
{fields.map((field) => (
|
|
345
|
-
<div key={field.target} className="form-field">
|
|
346
|
-
<label className="form-label">
|
|
347
|
-
{field.label}
|
|
348
|
-
{field.required && <span className="required">*</span>}
|
|
349
|
-
</label>
|
|
350
|
-
{field.componentType === "DROPDOWN" && field.options ? (
|
|
351
|
-
<select
|
|
352
|
-
required={field.required}
|
|
353
|
-
value={formData[field.target] ?? ""}
|
|
354
|
-
onChange={(e) =>
|
|
355
|
-
setFormData((prev) => ({ ...prev, [field.target]: e.target.value }))
|
|
356
|
-
}
|
|
357
|
-
className={`form-select${fieldErrors[field.target] ? " form-input-error" : ""}`}
|
|
358
|
-
>
|
|
359
|
-
<option value="">Select an option</option>
|
|
360
|
-
{field.options.map((opt) => (
|
|
361
|
-
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
|
362
|
-
))}
|
|
363
|
-
</select>
|
|
364
|
-
) : field.identifier === "TEXT_AREA" || field.target === "message" ? (
|
|
365
|
-
<textarea
|
|
366
|
-
required={field.required}
|
|
367
|
-
value={formData[field.target] ?? ""}
|
|
368
|
-
onChange={(e) =>
|
|
369
|
-
setFormData((prev) => ({ ...prev, [field.target]: e.target.value }))
|
|
370
|
-
}
|
|
371
|
-
rows={4}
|
|
372
|
-
className={`form-textarea${fieldErrors[field.target] ? " form-input-error" : ""}`}
|
|
373
|
-
/>
|
|
374
|
-
) : (
|
|
375
|
-
<input
|
|
376
|
-
type={
|
|
377
|
-
field.target === "email" ? "email" :
|
|
378
|
-
field.componentType === "PHONE_INPUT" ? "tel" : "text"
|
|
379
|
-
}
|
|
380
|
-
required={field.required}
|
|
381
|
-
value={formData[field.target] ?? ""}
|
|
382
|
-
onChange={(e) =>
|
|
383
|
-
setFormData((prev) => ({ ...prev, [field.target]: e.target.value }))
|
|
384
|
-
}
|
|
385
|
-
className={`form-input${fieldErrors[field.target] ? " form-input-error" : ""}`}
|
|
386
|
-
{...(field.componentType === "PHONE_INPUT" ? { placeholder: "+1234567890" } : {})}
|
|
387
|
-
/>
|
|
388
|
-
)}
|
|
389
|
-
{fieldErrors[field.target] && (
|
|
390
|
-
<p className="form-field-error">{fieldErrors[field.target]}</p>
|
|
391
|
-
)}
|
|
392
|
-
</div>
|
|
393
|
-
))}
|
|
394
|
-
|
|
395
|
-
<button
|
|
396
|
-
type="submit"
|
|
397
|
-
disabled={status === "submitting"}
|
|
398
|
-
className="form-button"
|
|
399
|
-
>
|
|
400
|
-
{status === "submitting" ? "Sending..." : "Send Message"}
|
|
401
|
-
</button>
|
|
402
|
-
|
|
403
|
-
{status === "error" && (
|
|
404
|
-
<p className="form-error">Something went wrong. Please try again.</p>
|
|
405
|
-
)}
|
|
406
|
-
</form>
|
|
407
|
-
);
|
|
408
|
-
}
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
> **Adapting class names:** The class names above (`form-container`, `form-field`, `form-label`, `form-input`, `form-button`, `form-success`, `form-error`, `form-field-error`, `form-input-error`) are defaults. If the designed component uses different class names, use those instead — the styling contract from the page's own design takes precedence.
|
|
412
|
-
|
|
413
|
-
## Discovering Forms
|
|
414
|
-
|
|
415
|
-
Forms are auto-created when scaffolding with a forms template. Use `auth.elevate(forms.listForms)` with the `"wix.form_app.form"` namespace to discover them — no hardcoded ID needed:
|
|
416
|
-
|
|
417
|
-
```typescript
|
|
418
|
-
import { forms } from "@wix/forms";
|
|
419
|
-
import { auth } from "@wix/essentials";
|
|
420
|
-
|
|
421
|
-
const elevatedListForms = auth.elevate(forms.listForms);
|
|
422
|
-
const listResult = await elevatedListForms("wix.form_app.form");
|
|
423
|
-
const wixForm = listResult.forms?.[0];
|
|
424
|
-
const formId = wixForm?._id;
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
If no forms exist, use the REST API Form Setup section above to create one via `curl`. If curl auth is not available, create one in the Wix dashboard (Forms section → Add New Form).
|
|
428
|
-
|
|
429
|
-
## Form Field Schema (SDK Types)
|
|
430
|
-
|
|
431
|
-
Each field in `formFields` has this structure when `fieldType === "INPUT"`:
|
|
432
|
-
|
|
433
|
-
```typescript
|
|
434
|
-
field.identifier // "CONTACTS_EMAIL", "TEXT_AREA", "SUBMIT_BUTTON", etc.
|
|
435
|
-
field.inputOptions.target // "email", "first_name", "message", custom UUIDs
|
|
436
|
-
field.inputOptions.required // boolean
|
|
437
|
-
field.inputOptions.stringOptions.componentType // "TEXT_INPUT" | "DROPDOWN" | "PHONE_INPUT"
|
|
438
|
-
field.inputOptions.stringOptions.textInputOptions?.label // label for text inputs
|
|
439
|
-
field.inputOptions.stringOptions.dropdownOptions?.label // label for dropdowns
|
|
440
|
-
field.inputOptions.stringOptions.dropdownOptions?.options // [{value, label}] for dropdowns
|
|
441
|
-
field.inputOptions.stringOptions.phoneInputOptions?.label // label for phone inputs
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
> **⚠️ Textarea detection:** The message field's `componentType` is always `"TEXT_INPUT"` (the API rejects `"TEXT_AREA"` as a componentType value). To render a `<textarea>`, check `field.identifier === "TEXT_AREA"` or `field.target === "message"` — NOT `field.componentType`.
|
|
445
|
-
|
|
446
|
-
## Built-In Field Targets
|
|
447
|
-
|
|
448
|
-
| Target | Type | HTML Input |
|
|
449
|
-
|--------|------|-----------|
|
|
450
|
-
| `email` | Email | `type="email"` |
|
|
451
|
-
| `first_name` | Text | `type="text"` |
|
|
452
|
-
| `last_name` | Text | `type="text"` |
|
|
453
|
-
| `phone` | Phone | `type="tel"` |
|
|
454
|
-
| `company` | Text | `type="text"` |
|
|
455
|
-
|
|
456
|
-
Custom fields use UUID-based targets from the form schema.
|
|
457
|
-
|
|
458
|
-
## Testing
|
|
459
|
-
|
|
460
|
-
1. Run `npx @wix/cli@latest dev`
|
|
461
|
-
2. Navigate to `/contact`
|
|
462
|
-
3. Fill in the form and submit
|
|
463
|
-
4. Check the Wix dashboard → Forms → Submissions to verify the data arrived
|