@wix/agent-skills 1.16.3 → 1.18.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/package.json +1 -1
- package/skills/wix-app/SKILL.md +115 -12
- package/skills/wix-app/references/APP_MARKET_REVIEW.md +1 -1
- package/skills/wix-app/references/BACKEND_API.md +18 -0
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +6 -0
- package/skills/wix-app/references/DASHBOARD_MODAL.md +10 -2
- package/skills/wix-app/references/DASHBOARD_PAGE.md +32 -70
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +145 -127
- package/skills/wix-app/references/SITE_PLUGIN.md +14 -2
- package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +74 -68
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
- package/skills/wix-app/references/dashboard-page/COLLECTION_TOOLKIT.md +79 -0
- package/skills/wix-app/references/dashboard-page/ENTITY_PAGE_TOOLKIT.md +73 -0
- package/skills/wix-app/references/dashboard-page/PATTERNS_BUNDLE_READING.md +52 -0
- package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +184 -0
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +94 -49
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +16 -6
- package/skills/wix-app/references/editor-react-component/BROWSER-SUPPORT.md +56 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +35 -40
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +167 -445
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +56 -29
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
- package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
- package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
- package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +11 -3
- package/skills/wix-app/references/editor-react-component/PARTS.md +46 -24
- package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
- package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
- package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
- package/skills/wix-base44-connector/SKILL.md +156 -50
- package/skills/wix-base44-connector/references/CAPABILITY_MAP.md +78 -0
- package/skills/wix-base44-connector/scripts/utils.js +239 -45
- package/skills/wix-headless/entry/bootstrap.mjs +9 -2
- package/skills/wix-headless/entry/skill.md +1 -1
- package/skills/wix-headless/references/CAPABILITIES.md +9 -1
- package/skills/wix-headless/references/DESIGN.md +1 -0
- package/skills/wix-headless/references/DISCOVERY.md +2 -1
- package/skills/wix-headless/references/IMAGE_GENERATION.md +1 -0
- package/skills/wix-headless/references/SDK_HANDOFF.md +5 -2
- package/skills/wix-headless/references/SEED.md +2 -1
- package/skills/wix-headless/references/SETUP.md +1 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-blog.md +2 -2
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +68 -31
- package/skills/wix-headless/references/inline-recipes/how-to-code-forms.md +26 -10
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-astro.md +8 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-custom-login.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-members-non-astro.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-rentals.md +254 -0
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
- package/skills/wix-headless/references/inline-recipes/setup-online-store.md +13 -0
- package/skills/wix-headless/references/inline-recipes/setup-rentals.md +254 -0
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
- package/skills/wix-headless/references/non-astro.md +1 -1
- package/skills/wix-headless-fast/SKILL.md +166 -0
- package/skills/wix-headless-fast/entry/skill.md +99 -0
- package/skills/wix-headless-fast/install/deploy.mjs +433 -0
- package/skills/wix-headless-fast/install/fast-path.mjs +141 -0
- package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +137 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +137 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +113 -0
- package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +42 -0
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +123 -0
- package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +70 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +99 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +76 -0
- package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +62 -0
- package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +99 -0
- package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +24 -0
- package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +16156 -0
- package/skills/wix-headless-fast/references/blog/seed/SEED.md +72 -0
- package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +287 -0
- package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +129 -0
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +143 -0
- package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +119 -0
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +138 -0
- package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +54 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +206 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +96 -0
- package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +70 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +76 -0
- package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +22 -0
- package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +11962 -0
- package/skills/wix-headless-fast/references/bookings/seed/SEED.md +61 -0
- package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +302 -0
- package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +179 -0
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +83 -0
- package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +57 -0
- package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +151 -0
- package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +75 -0
- package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +41 -0
- package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +11262 -0
- package/skills/wix-headless-fast/references/cms/seed/SEED.md +103 -0
- package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +324 -0
- package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +149 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +66 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +176 -0
- package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +118 -0
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +117 -0
- package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +59 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +136 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +128 -0
- package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +61 -0
- package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +12 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +80 -0
- package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +21 -0
- package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +11884 -0
- package/skills/wix-headless-fast/references/events/seed/SEED.md +86 -0
- package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +276 -0
- package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +150 -0
- package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +317 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +269 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +231 -0
- package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +135 -0
- package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +10593 -0
- package/skills/wix-headless-fast/references/forms/seed/SEED.md +108 -0
- package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +320 -0
- package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +63 -0
- package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +60 -0
- package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +155 -0
- package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +78 -0
- package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +47 -0
- package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +66 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +88 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +53 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +122 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +50 -0
- package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +21 -0
- package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +42 -0
- package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +10 -0
- package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +11 -0
- package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +10329 -0
- package/skills/wix-headless-fast/references/members/seed/SEED.md +39 -0
- package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +94 -0
- package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +134 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +110 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +90 -0
- package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +115 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +59 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +39 -0
- package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +58 -0
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +165 -0
- package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +55 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +40 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +30 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +21 -0
- package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +29 -0
- package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +10197 -0
- package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +78 -0
- package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +258 -0
- package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +133 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +58 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +126 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +37 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +39 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +75 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +45 -0
- package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +30 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +41 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +40 -0
- package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +21 -0
- package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +11226 -0
- package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +71 -0
- package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +279 -0
- package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +165 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +142 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +26 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +121 -0
- package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +155 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +55 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +43 -0
- package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +177 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +165 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +103 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +254 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +146 -0
- package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +168 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +47 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +22 -0
- package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +12 -0
- package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +12560 -0
- package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +81 -0
- package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +479 -0
- package/skills/wix-headless-fast/references/shared/CONTENT.md +22 -0
- package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +73 -0
- package/skills/wix-headless-fast/references/shared/DESIGN.md +26 -0
- package/skills/wix-headless-fast/references/shared/app/styles/global.css +52 -0
- package/skills/wix-headless-fast/references/shared/app/wix/config.ts +15 -0
- package/skills/wix-headless-fast/references/shared/app/wix/media.ts +27 -0
- package/skills/wix-headless-fast/references/shared/app/wix/money.ts +24 -0
- package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +76 -0
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +46 -0
- package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +46 -0
- package/skills/wix-headless-fast/references/shared/seed/images.mjs +145 -0
- package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +149 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +26 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +121 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductCard.tsx +100 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductDetailView.tsx +130 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ProductGrid.tsx +48 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/ShopView.tsx +66 -0
- package/skills/wix-headless-fast/references/storefront/app/components/storefront/VariantPicker.tsx +103 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +48 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +140 -0
- package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +80 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +101 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +221 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +215 -0
- package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +109 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +46 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/products/[slug].astro +56 -0
- package/skills/wix-headless-fast/references/storefront/app-astro/pages/shop.astro +23 -0
- package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +12247 -0
- package/skills/wix-headless-fast/references/storefront/seed/SEED.md +85 -0
- package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +415 -0
- package/skills/wix-manage/SKILL.md +28 -2
- package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
- package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
- package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
- package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +141 -0
- package/skills/wix-manage/references/google-business-profile/connect-google-business-profile.md +134 -0
- package/skills/wix-manage/references/google-business-profile/manage-google-business-profile-locations.md +182 -0
- package/skills/wix-manage/references/marketing/create-and-publish-social-post.md +3 -0
- package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
- package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
- package/skills/wix-manage/references/sites/query-sites.md +72 -161
- package/skills/wix-manage/references/stores/create-product-catalog-v3.md +21 -6
- package/skills/wix-manage/references/stores/update-product-with-options.md +83 -0
- package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
- package/skills/wix-vibe-headless/SKILL.md +18 -4
- package/skills/wix-vibe-headless/install/deploy.cjs +12 -4
- package/skills/wix-vibe-headless/install/pin-agents-md.cjs +2 -1
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +16 -10
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +13 -8
- package/skills/wix-vibe-headless/platforms/base44.md +27 -62
- package/skills/wix-vibe-headless/platforms/generic.md +6 -3
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +45 -0
- package/skills/wix-vibe-headless/references/bookings/app/components/RentalDurationPicker.jsx +67 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useRentalDuration.js +128 -0
- package/skills/wix-vibe-headless/references/bookings/app/hooks/useServiceDetail.js +5 -3
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-rentals.js +250 -0
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-services.js +12 -5
- package/skills/wix-vibe-headless/references/bookings/seed/SEED.md +41 -0
- package/skills/wix-vibe-headless/references/bookings/seed/seed-rentals.js +267 -0
- package/skills/wix-vibe-headless/references/cms/INSTRUCTIONS.md +6 -3
- package/skills/wix-vibe-headless/references/forms/INSTRUCTIONS.md +470 -0
- package/skills/wix-vibe-headless/references/forms/app/hooks/useWixForm.js +425 -0
- package/skills/wix-vibe-headless/references/forms/app/lib/wix-form-schema-utils.js +187 -0
- package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms-submissions.js +238 -0
- package/skills/wix-vibe-headless/references/forms/app/rest/wix-forms.js +108 -0
- package/skills/wix-vibe-headless/references/forms/seed/SEED.md +1762 -0
- package/skills/wix-vibe-headless/references/rentals/INSTRUCTIONS.md +13 -0
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
- package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
- package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
- package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +152 -92
- package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
- package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
- package/skills/wix-vibe-headless/references/storefront/app/hooks/useProductDetail.js +15 -8
- package/skills/wix-vibe-headless/references/storefront/app/lib/storeImage.js +37 -0
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-catalog.js +18 -6
- package/skills/wix-vibe-headless/references/storefront/seed/SEED.md +30 -7
- package/skills/wix-vibe-headless/references/storefront/seed/seed-store.js +46 -10
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -516
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
- package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductCard.jsx +0 -110
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGallery.jsx +0 -51
- package/skills/wix-vibe-headless/references/storefront/app/components/ProductGrid.jsx +0 -49
- package/skills/wix-vibe-headless/references/storefront/app/components/VariantPicker.jsx +0 -92
- package/skills/wix-vibe-headless/references/storefront/app/pages/ProductDetail.jsx +0 -139
|
@@ -10,6 +10,43 @@ export function storeImage(value) {
|
|
|
10
10
|
return url;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
// A Wix media id (e.g. "abc123~mv2.jpg") is NOT a URL — build the static CDN url for it.
|
|
14
|
+
export function wixMediaUrl(mediaId) {
|
|
15
|
+
if (!mediaId || typeof mediaId !== "string") return null;
|
|
16
|
+
if (mediaId.startsWith("http") || mediaId.startsWith("//")) return storeImage(mediaId);
|
|
17
|
+
return `https://static.wixstatic.com/media/${mediaId}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// The media id inside a Wix image url (…/media/<id>/v1/… or a bare …/media/<id>). Compare two urls of
|
|
21
|
+
// the SAME image that differ only in sizing/format params by their id, not full-string equality.
|
|
22
|
+
export function wixMediaId(url) {
|
|
23
|
+
const m = typeof url === "string" && url.match(/\/media\/([^/?]+)/);
|
|
24
|
+
return m ? m[1] : url;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// The image assigned to a product OPTION CHOICE (e.g. a colour swatch). The storefront fetches with the
|
|
28
|
+
// PRODUCT_CHOICES_MEDIA_REFERENCES field, so Wix returns the choice image at choice.media.items[].mediaId
|
|
29
|
+
// and returns choice.linkedMedia EMPTY. Read media.items — do NOT switch this to choice.linkedMedia even
|
|
30
|
+
// if a direct admin/API probe shows linkedMedia populated: a probe made WITHOUT that field mask returns
|
|
31
|
+
// linkedMedia, but the storefront requests the mask, which blanks linkedMedia and returns media.items.
|
|
32
|
+
export function choiceImage(choice) {
|
|
33
|
+
const mediaId = choice?.media?.items?.[0]?.mediaId;
|
|
34
|
+
return mediaId ? wixMediaUrl(mediaId) : null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// The image for a resolved VARIANT (a full choice combination). Wix computes variant.media from the
|
|
38
|
+
// picked choices' media, so this is the exact image for the current selection — prefer it over a
|
|
39
|
+
// single choice's image once all options are chosen.
|
|
40
|
+
// ⚠️ Read `media.image.url` (the URL the API already returns), or build from `media.id` — the
|
|
41
|
+
// `~mv2` file id. NOT `media.uploadId`: that's a dashed GUID (the id the file was uploaded with),
|
|
42
|
+
// and https://static.wixstatic.com/media/<uploadId> is a 403. Variants without media (a fresh
|
|
43
|
+
// template's demo products) return null, and the caller falls back to the choice's own image.
|
|
44
|
+
export function variantImage(variant) {
|
|
45
|
+
const m = variant?.media;
|
|
46
|
+
if (!m) return null;
|
|
47
|
+
return storeImage(m.image?.url) || wixMediaUrl(m.id) || storeImage(m.thumbnail?.url);
|
|
48
|
+
}
|
|
49
|
+
|
|
13
50
|
// The main catalog image for a product (grid tiles, cart fallbacks).
|
|
14
51
|
export function productImage(product) {
|
|
15
52
|
return storeImage(product?.media?.main?.image?.url);
|
|
@@ -7,20 +7,22 @@ import { wixApiRequest } from "./wix-client.js";
|
|
|
7
7
|
const STORES_APP_ID = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Wix eCom Cart — key fields for building a cart UI.
|
|
10
|
+
* Wix eCom Cart V2 — key fields for building a cart UI.
|
|
11
11
|
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/get-current-cart.md
|
|
12
12
|
*
|
|
13
|
-
* id {string}
|
|
13
|
+
* id {string} — the cart id IS the checkout id (currency lives under businessInfo.currencyCode / customerInfo.currencyCode, not at the cart root),
|
|
14
14
|
* lineItems[].id {string} — lineItemId for update/remove (NOT catalogItemId),
|
|
15
|
-
* lineItems[].
|
|
16
|
-
* lineItems[].catalogReference.catalogItemId {string},
|
|
17
|
-
* lineItems[].
|
|
18
|
-
* lineItems[].
|
|
19
|
-
* lineItems[].
|
|
20
|
-
*
|
|
15
|
+
* lineItems[].quantityInfo.confirmedQuantity {number},
|
|
16
|
+
* lineItems[].source.catalogReference.catalogItemId {string} — NOT top-level in V2,
|
|
17
|
+
* lineItems[].name.original {string},
|
|
18
|
+
* lineItems[].pricing.unitPrice {ConvertedMoney} — per-unit price after discounts,
|
|
19
|
+
* lineItems[].pricing.totalPrice {ConvertedMoney} — line total after discounts,
|
|
20
|
+
* ConvertedMoney is { amount, convertedAmount } with NO formatted string — `amount` is in the
|
|
21
|
+
* site currency, `convertedAmount` in the display currency; format the number client-side.
|
|
22
|
+
* lineItems[].attributes.descriptionLines {array} — human-readable option/modifier labels:
|
|
21
23
|
* [{ name: { original }, plainText: { original } OR colorInfo: { original, code } }],
|
|
22
|
-
* lineItems[].image
|
|
23
|
-
* lineItems[].
|
|
24
|
+
* lineItems[].attributes.image {object} — { id, url, height, width, altText } (use .url),
|
|
25
|
+
* lineItems[].status {string} — "IN_STOCK"|"PARTIALLY_IN_STOCK"|"OUT_OF_STOCK"|"REMOVED_FROM_CATALOG"
|
|
24
26
|
*/
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -52,20 +54,22 @@ export async function addToCart(catalogItemId, variantId, quantity = 1, { modifi
|
|
|
52
54
|
|
|
53
55
|
const catalogReference = { appId: STORES_APP_ID, catalogItemId };
|
|
54
56
|
if (Object.keys(catalogReferenceOptions).length) catalogReference.options = catalogReferenceOptions;
|
|
55
|
-
const res = await wixApiRequest("/ecom/
|
|
57
|
+
const res = await wixApiRequest("/ecom/v2/carts/current/add-line-items", {
|
|
56
58
|
method: "POST",
|
|
57
|
-
body: {
|
|
59
|
+
body: { catalogItems: [{ catalogReference, quantity }] },
|
|
58
60
|
});
|
|
61
|
+
// V2 nests the reference under `source` — a top-level lineItem.catalogReference no longer exists.
|
|
59
62
|
const line = (res?.cart?.lineItems ?? []).find(
|
|
60
|
-
(l) => l.catalogReference?.catalogItemId === catalogItemId && (!variantId || l.catalogReference?.options?.variantId === variantId),
|
|
63
|
+
(l) => l.source?.catalogReference?.catalogItemId === catalogItemId && (!variantId || l.source?.catalogReference?.options?.variantId === variantId),
|
|
61
64
|
);
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
// Cart V2 rejects an unbuyable line with an explicit error rather than silently dropping it, but
|
|
66
|
+
// guard both signals defensively:
|
|
67
|
+
// 1. status set to something other than IN_STOCK
|
|
68
|
+
// 2. no matching line at all (confirmed quantity 0 / line absent)
|
|
69
|
+
if (line?.status && line.status !== "IN_STOCK") {
|
|
70
|
+
throw new Error(`Item not available for sale (status: ${line.status}). Is it in stock?`);
|
|
67
71
|
}
|
|
68
|
-
if (!line || line.
|
|
72
|
+
if (!line || line.quantityInfo?.confirmedQuantity === 0) {
|
|
69
73
|
// A missing line usually means a required selection wasn't sent — a mandatory modifier
|
|
70
74
|
// (pass modifierChoices/customTextFields) or the variantId for a product with options —
|
|
71
75
|
// not necessarily out of stock. Verify every required choice is included in this call.
|
|
@@ -81,7 +85,7 @@ export async function addToCart(catalogItemId, variantId, quantity = 1, { modifi
|
|
|
81
85
|
/** Read the visitor's current cart. Returns null if no cart exists yet. */
|
|
82
86
|
export async function getCurrentCart() {
|
|
83
87
|
try {
|
|
84
|
-
const res = await wixApiRequest("/ecom/
|
|
88
|
+
const res = await wixApiRequest("/ecom/v2/carts/current", { method: "GET" });
|
|
85
89
|
return res?.cart ?? null;
|
|
86
90
|
} catch {
|
|
87
91
|
return null;
|
|
@@ -89,7 +93,9 @@ export async function getCurrentCart() {
|
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
/**
|
|
92
|
-
*
|
|
96
|
+
* Start the hosted checkout for the current cart and return its URL.
|
|
97
|
+
* In Cart V2 the cart id IS the checkout id — there is no separate checkout-creation call; the
|
|
98
|
+
* redirect session is created straight from the current cart's id.
|
|
93
99
|
* Throws on empty cart, unavailable lines, or a missing redirect URL.
|
|
94
100
|
* Usage: window.location.href = await checkout()
|
|
95
101
|
* @returns {Promise<string>}
|
|
@@ -98,22 +104,16 @@ export async function checkout() {
|
|
|
98
104
|
const cart = await getCurrentCart();
|
|
99
105
|
const lines = cart?.lineItems ?? [];
|
|
100
106
|
if (!lines.length) throw new Error("Cannot check out: the cart is empty.");
|
|
101
|
-
const unavailable = lines.filter((l) => l.
|
|
107
|
+
const unavailable = lines.filter((l) => l.status && l.status !== "IN_STOCK");
|
|
102
108
|
if (unavailable.length) {
|
|
103
|
-
const names = unavailable.map((l) => l.
|
|
109
|
+
const names = unavailable.map((l) => l.name?.original ?? l.source?.catalogReference?.catalogItemId).join(", ");
|
|
104
110
|
throw new Error(`Cannot check out: ${unavailable.length} item(s) not available — ${names}.`);
|
|
105
111
|
}
|
|
106
|
-
|
|
107
|
-
const checkoutRes = await wixApiRequest("/ecom/v1/carts/current/create-checkout", {
|
|
108
|
-
method: "POST",
|
|
109
|
-
body: { channelType: "WEB" },
|
|
110
|
-
});
|
|
111
|
-
const checkoutId = checkoutRes?.checkoutId;
|
|
112
|
-
if (!checkoutId) throw new Error("Failed to create checkout from the current cart.");
|
|
112
|
+
if (!cart.id) throw new Error("Failed to check out: the current cart has no id.");
|
|
113
113
|
|
|
114
114
|
const redirect = await wixApiRequest("/headless/v1/redirect-session", {
|
|
115
115
|
method: "POST",
|
|
116
|
-
body: { ecomCheckout: { checkoutId }, callbacks: { postFlowUrl: window.location.href } },
|
|
116
|
+
body: { ecomCheckout: { checkoutId: cart.id }, callbacks: { postFlowUrl: window.location.href } },
|
|
117
117
|
});
|
|
118
118
|
const url = redirect?.redirectSession?.fullUrl;
|
|
119
119
|
if (!url) throw new Error("Failed to create the checkout redirect session.");
|
|
@@ -122,13 +122,13 @@ export async function checkout() {
|
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* Update the quantity of a cart line. lineItemId is cart.lineItems[].id, not catalogItemId.
|
|
125
|
-
*
|
|
125
|
+
* Cart V2 rejects an over-stock quantity with an explicit error rather than clamping it.
|
|
126
126
|
* @returns {Promise<object>} Updated cart.
|
|
127
127
|
*/
|
|
128
128
|
export async function updateCartItemQuantity(lineItemId, quantity) {
|
|
129
|
-
const res = await wixApiRequest("/ecom/
|
|
129
|
+
const res = await wixApiRequest("/ecom/v2/carts/current/update-line-items", {
|
|
130
130
|
method: "POST",
|
|
131
|
-
body: { lineItems: [{
|
|
131
|
+
body: { lineItems: [{ lineItemId, quantity: { newQuantity: quantity } }] },
|
|
132
132
|
});
|
|
133
133
|
return res?.cart;
|
|
134
134
|
}
|
|
@@ -139,7 +139,7 @@ export async function updateCartItemQuantity(lineItemId, quantity) {
|
|
|
139
139
|
* @returns {Promise<object>} Updated cart.
|
|
140
140
|
*/
|
|
141
141
|
export async function removeFromCart(lineItemId) {
|
|
142
|
-
const res = await wixApiRequest("/ecom/
|
|
142
|
+
const res = await wixApiRequest("/ecom/v2/carts/current/remove-line-items", {
|
|
143
143
|
method: "POST",
|
|
144
144
|
body: { lineItemIds: [lineItemId] },
|
|
145
145
|
});
|
|
@@ -30,12 +30,13 @@ import { wixApiRequest } from "./wix-client.js";
|
|
|
30
30
|
* options {array} — product options e.g. Size, Color:
|
|
31
31
|
* [{ id, name, optionRenderType "TEXT_CHOICES"|"COLOR_CHOICES"|"SWATCH_CHOICES",
|
|
32
32
|
* choicesSettings.choices [{ choiceId, key, name, inStock, visible, choiceType, colorCode,
|
|
33
|
-
*
|
|
33
|
+
* media }] }],
|
|
34
34
|
* A COLOR/SWATCH option's choices carry choiceType "ONE_COLOR" and colorCode "#395E55" — render
|
|
35
|
-
* those as real colour swatches, not text pills.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* those as real colour swatches, not text pills. A choice's photo is at media.items[].mediaId (a
|
|
36
|
+
* bare Wix media id — build https://static.wixstatic.com/media/<id>); use choiceImage() from
|
|
37
|
+
* lib/storeImage to resolve it. Needs the PRODUCT_CHOICES_MEDIA_REFERENCES field (requested by
|
|
38
|
+
* getProductBySlug below). visible false is a retired choice the merchant no longer sells: filter
|
|
39
|
+
* it out. (TEXT_CHOICES choices are choiceType "CHOICE_TEXT" with no colorCode.)
|
|
39
40
|
* modifiers {array} — non-variant customizations (engraving, gift wrap):
|
|
40
41
|
* [{ id, name, mandatory, modifierRenderType "TEXT_CHOICES"|"FREE_TEXT",
|
|
41
42
|
* key, choicesSettings.choices, freeTextSettings.key }],
|
|
@@ -85,7 +86,18 @@ export async function queryProducts({ limit = 100, cursor } = {}) {
|
|
|
85
86
|
export async function getProductBySlug(slug) {
|
|
86
87
|
const res = await wixApiRequest(`/stores/v3/products/slug/${encodeURIComponent(slug)}`, {
|
|
87
88
|
method: "GET",
|
|
88
|
-
|
|
89
|
+
// PRODUCT_CHOICES_MEDIA_REFERENCES → choice.media.items[].mediaId (the per-colour photos, needed
|
|
90
|
+
// for the swatch→gallery swap); VARIANT_OPTION_CHOICE_NAMES → variant choice names. Without these
|
|
91
|
+
// the choice media / variant data come back null.
|
|
92
|
+
query: {
|
|
93
|
+
fields: [
|
|
94
|
+
"CURRENCY",
|
|
95
|
+
"PLAIN_DESCRIPTION",
|
|
96
|
+
"MEDIA_ITEMS_INFO",
|
|
97
|
+
"PRODUCT_CHOICES_MEDIA_REFERENCES",
|
|
98
|
+
"VARIANT_OPTION_CHOICE_NAMES",
|
|
99
|
+
],
|
|
100
|
+
},
|
|
89
101
|
});
|
|
90
102
|
return res?.product ?? null;
|
|
91
103
|
}
|
|
@@ -4,6 +4,10 @@ Seed a Wix Stores catalog by **calling `seed-store.js`** — don't hand-write th
|
|
|
4
4
|
a build-time module (run via `exec_tool`, not shipped in the app) that abstracts every Wix Stores
|
|
5
5
|
seed operation. Load it and call **`setupStore` — the one-call path** — with plain data.
|
|
6
6
|
|
|
7
|
+
**Match each product's type to what the buyer receives** (the example shows both). *Access* — a
|
|
8
|
+
membership, or an online course/program the buyer enrolls in — isn't a store product at all; that's
|
|
9
|
+
the `pricing-plans` vertical, not here.
|
|
10
|
+
|
|
7
11
|
```js
|
|
8
12
|
// build-time exec_tool
|
|
9
13
|
const { accessToken } = await base44.asServiceRole.connectors.getConnection("wix");
|
|
@@ -22,12 +26,15 @@ const ctx = { token: accessToken, siteId: WIX_METASITE_ID };
|
|
|
22
26
|
// generate_image runs in the background while you build, so the urls are ready by seed time.
|
|
23
27
|
const result = await seed.setupStore(ctx, {
|
|
24
28
|
products: [
|
|
29
|
+
// physical — a shipped item: carries `quantity` (the default type)
|
|
25
30
|
{ name: "The Glam Rocker", description: "Sequin-studded velvet legend…", price: 49.99, quantity: 12, imageUrl: imageUrls[0] },
|
|
26
31
|
// a product with buyer choices — see "Options, variants and sale prices" below
|
|
27
32
|
{ name: "The Understudy", description: "…", price: 245, quantity: 8, imageUrl: imageUrls[1],
|
|
28
33
|
options: [{ name: "Color", type: "color", choices: [{ name: "Ink", colorCode: "#1B1B2F" }, { name: "Bone", colorCode: "#EDE6D6" }] }] },
|
|
29
34
|
// a product on sale — compareAtPrice drives the strikethrough + the tile's percent-off badge
|
|
30
35
|
{ name: "Encore Jacket", description: "…", price: 68, compareAtPrice: 129, quantity: 5, imageUrl: imageUrls[2] },
|
|
36
|
+
// digital — a file the buyer downloads & keeps (ebook, PDF, video): `digitalFileUrl`, NO `quantity`
|
|
37
|
+
{ name: "Backstage Guide", description: "…", price: 12, digitalFileUrl: "https://…/guide.pdf" },
|
|
31
38
|
],
|
|
32
39
|
categories: { "Legends": ["The Glam Rocker"], "Rising Stars": [] }, // omit if the brief names none
|
|
33
40
|
});
|
|
@@ -37,13 +44,15 @@ const result = await seed.setupStore(ctx, {
|
|
|
37
44
|
**Seeding is additive — never delete or overwrite existing content.** Don't clean up, don't remove
|
|
38
45
|
"sample" data, don't reset. Just add.
|
|
39
46
|
|
|
40
|
-
##
|
|
47
|
+
## How many, and exercising the UI
|
|
48
|
+
|
|
49
|
+
**Default to 3 products** unless the brief asks for a specific catalog — the seed shows the shape,
|
|
50
|
+
not a full inventory; the owner adds the rest later, from the Wix dashboard or by asking you for more.
|
|
41
51
|
|
|
42
52
|
The shipped storefront renders colour options as real swatches, shows a size/colour summary on each
|
|
43
53
|
tile, and puts a percent-off badge on a discounted product. A catalog of plain single-price products
|
|
44
|
-
leaves all of that invisible, so **
|
|
45
|
-
|
|
46
|
-
to the business — a ceramics studio has glaze colours, a bakery does not.
|
|
54
|
+
leaves all of that invisible, so **make those 3 exercise it**: unless the brief says otherwise, give
|
|
55
|
+
at least one product a colour option and put one product on sale. Keep it truthful to the business.
|
|
47
56
|
|
|
48
57
|
```js
|
|
49
58
|
options: [
|
|
@@ -60,13 +69,27 @@ options: [
|
|
|
60
69
|
- `compareAtPrice` (> `price`) is the "was" price: strikethrough on the PDP and a `−N%` badge on the
|
|
61
70
|
tile, computed from the two amounts. It works with or without options.
|
|
62
71
|
|
|
72
|
+
## Digital downloads
|
|
73
|
+
|
|
74
|
+
**Pick the product type from what the buyer receives.** A shipped physical item is the default. A
|
|
75
|
+
**downloadable file the buyer keeps** — ebook, PDF guide, template, preset pack, printable, music
|
|
76
|
+
track, downloadable video — is a **digital** product: pass its file as `digitalFileUrl`. Selling
|
|
77
|
+
*access* rather than a file — a membership, subscription, or an online course/program the buyer
|
|
78
|
+
enrolls in — is **Pricing Plans**, not a Stores product, so it isn't seeded here.
|
|
79
|
+
|
|
80
|
+
`digitalFileUrl` (plus `digitalFileName` when the url carries no filename) makes a product a digital
|
|
81
|
+
download — uploaded and created with both the file and stock, which is what the cart requires
|
|
82
|
+
(`quantity` is ignored). It's also the only way in: a file-less digital product is created
|
|
83
|
+
successfully, reads back healthy, and is then rejected at add-to-cart as `ITEM_NOT_FOUND_IN_CATALOG`.
|
|
84
|
+
|
|
63
85
|
Two things this module does **not** seed, so don't try:
|
|
64
86
|
|
|
65
87
|
- **Ribbons** ("New", "Best Seller"). The tile renders `product.ribbon` when it's there, but ribbons
|
|
66
88
|
are set in the Wix dashboard — tell the merchant that's where to add them.
|
|
67
|
-
- **Per-choice
|
|
68
|
-
|
|
69
|
-
the
|
|
89
|
+
- **Per-choice media** — the photo that makes picking a choice swap the gallery image. Seeded swatches
|
|
90
|
+
select and price correctly; the gallery follows a choice once photos are linked to it (Wix dashboard,
|
|
91
|
+
or the wix-manage "Update Product with Options" recipe → Choice & variant fields). The shipped PDP then
|
|
92
|
+
follows automatically — `choiceImage()` reads it back at `media.items[].mediaId`.
|
|
70
93
|
|
|
71
94
|
## Escape hatch — individual functions
|
|
72
95
|
Reach for the functions below only when the one-call `setupStore` doesn't fit (partial re-seed, custom
|
|
@@ -149,15 +149,16 @@ function buildOptions(options = []) {
|
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
// full Cartesian product of variants, each priced/stocked from the product; visible:true baked in
|
|
152
|
-
function expandVariants(options = [], { price, compareAtPrice, quantity }) {
|
|
152
|
+
function expandVariants(options = [], { price, compareAtPrice, quantity }, digitalFileId) {
|
|
153
153
|
const base = {
|
|
154
154
|
price: {
|
|
155
155
|
actualPrice: { amount: String(price) },
|
|
156
156
|
...(compareAtPrice ? { compareAtPrice: { amount: String(compareAtPrice) } } : {}),
|
|
157
157
|
},
|
|
158
158
|
visible: true,
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
...(digitalFileId
|
|
160
|
+
? { digitalProperties: { digitalFile: { id: digitalFileId } }, inventoryItem: { inStock: true } }
|
|
161
|
+
: { physicalProperties: {}, inventoryItem: { quantity: quantity ?? 0, preorderInfo: { enabled: false } } }),
|
|
161
162
|
};
|
|
162
163
|
if (!options.length) return [base];
|
|
163
164
|
let combos = [[]];
|
|
@@ -170,6 +171,33 @@ function expandVariants(options = [], { price, compareAtPrice, quantity }) {
|
|
|
170
171
|
return combos.map((choices) => ({ ...base, choices }));
|
|
171
172
|
}
|
|
172
173
|
|
|
174
|
+
// A digital variant is SELLABLE only with BOTH a file and stock: without the file the cart rejects
|
|
175
|
+
// it as ITEM_NOT_FOUND_IN_CATALOG, without stock as "exceeds available inventory" — and either way
|
|
176
|
+
// the product reads back visible and in the catalog, so nothing surfaces until a buyer tries to buy.
|
|
177
|
+
// `digitalFileUrl` is the only way into DIGITAL here, which makes the file-less product unbuildable.
|
|
178
|
+
// The bytes are PUT, not imported by url: an uploaded file is READY at once, while an imported one
|
|
179
|
+
// stays PENDING and the cart rejects the product until it settles.
|
|
180
|
+
const FILE_MIME = { pdf: "application/pdf", zip: "application/zip", epub: "application/epub+zip",
|
|
181
|
+
mp3: "audio/mpeg", wav: "audio/wav", mp4: "video/mp4", png: "image/png", jpg: "image/jpeg" };
|
|
182
|
+
|
|
183
|
+
async function uploadDigitalFile(ctx, url, fileName) {
|
|
184
|
+
const mimeType = FILE_MIME[(fileName.split(".").pop() || "").toLowerCase()];
|
|
185
|
+
if (!mimeType) throw new Error(`digitalFileName needs one of these extensions (${Object.keys(FILE_MIME).join(", ")}): ${fileName}`);
|
|
186
|
+
const { uploadUrl } = await req(ctx, "/site-media/v1/files/generate-upload-url", { body: { mimeType, fileName } });
|
|
187
|
+
const src = await fetch(url);
|
|
188
|
+
if (!src.ok) throw new Error(`digitalFileUrl ${url} -> ${src.status}`);
|
|
189
|
+
const res = await fetch(uploadUrl, {
|
|
190
|
+
method: "PUT", headers: { "Content-Type": mimeType }, body: Buffer.from(await src.arrayBuffer()),
|
|
191
|
+
});
|
|
192
|
+
const json = await res.json().catch(() => ({}));
|
|
193
|
+
const id = (json.file || json)?.id;
|
|
194
|
+
if (!res.ok || !id) throw new Error(`digital file upload failed (${res.status}): ${JSON.stringify(json).slice(0, 200)}`);
|
|
195
|
+
return id;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const digitalFileName = (p) =>
|
|
199
|
+
p.digitalFileName || decodeURIComponent(new URL(p.digitalFileUrl).pathname.split("/").pop() || "");
|
|
200
|
+
|
|
173
201
|
// ---- exported operations ----
|
|
174
202
|
|
|
175
203
|
async function installStoresApp(ctx) {
|
|
@@ -193,7 +221,10 @@ async function listProducts(ctx) {
|
|
|
193
221
|
/**
|
|
194
222
|
* Bulk-create products.
|
|
195
223
|
* @param products [{ name, description, price, compareAtPrice?, quantity,
|
|
196
|
-
* options?: [{ name, type?:"text"|"color", choices:["8","9"] | [{name,colorCode}] }]
|
|
224
|
+
* options?: [{ name, type?:"text"|"color", choices:["8","9"] | [{name,colorCode}] }],
|
|
225
|
+
* digitalFileUrl?, digitalFileName? }]
|
|
226
|
+
* digitalFileUrl: makes the product a DIGITAL download — the file is uploaded and the variant
|
|
227
|
+
* created with both the file and stock (see uploadDigitalFile). `quantity` is ignored.
|
|
197
228
|
* description: plain text, or simple HTML (`<p>`, `<br/>`, `<strong>`, `<em>`) — converted to
|
|
198
229
|
* Wix rich text here, so the storefront renders paragraphs and bold rather than tag text.
|
|
199
230
|
* options = ONLY things the buyer selects-and-buys (Size, Color) -> become variants.
|
|
@@ -202,17 +233,20 @@ async function listProducts(ctx) {
|
|
|
202
233
|
* @returns [{ id, slug, revision }]
|
|
203
234
|
*/
|
|
204
235
|
async function bulkCreateProducts(ctx, products) {
|
|
236
|
+
const fileIds = await Promise.all(products.map((p) =>
|
|
237
|
+
p.digitalFileUrl ? uploadDigitalFile(ctx, p.digitalFileUrl, digitalFileName(p)) : null));
|
|
205
238
|
const body = {
|
|
206
239
|
returnEntity: true,
|
|
207
240
|
products: products.map((p, i) => ({
|
|
208
241
|
name: p.name,
|
|
209
|
-
|
|
210
|
-
|
|
242
|
+
// DIGITAL drops physicalProperties and can't be POS-visible (DIGITAL_PRODUCT_CANNOT_BE_VISIBLE_IN_POS).
|
|
243
|
+
...(fileIds[i]
|
|
244
|
+
? { productType: "DIGITAL" }
|
|
245
|
+
: { productType: "PHYSICAL", physicalProperties: {}, visibleInPos: true }),
|
|
211
246
|
visible: true,
|
|
212
|
-
visibleInPos: true,
|
|
213
247
|
description: mkDesc(p.description, i),
|
|
214
248
|
options: buildOptions(p.options),
|
|
215
|
-
variantsInfo: { variants: expandVariants(p.options, p) },
|
|
249
|
+
variantsInfo: { variants: expandVariants(p.options, p, fileIds[i]) },
|
|
216
250
|
})),
|
|
217
251
|
};
|
|
218
252
|
const r = await req(ctx, "/stores/v3/bulk/products-with-inventory/create", { body });
|
|
@@ -221,6 +255,7 @@ async function bulkCreateProducts(ctx, products) {
|
|
|
221
255
|
id: x.item?.id, slug: x.item?.slug, revision: x.item?.revision,
|
|
222
256
|
variantId: x.item?.variantsInfo?.variants?.[0]?.id,
|
|
223
257
|
hasOptions: (products[i]?.options?.length ?? 0) > 0,
|
|
258
|
+
isDigital: !!fileIds[i],
|
|
224
259
|
quantity: products[i]?.quantity ?? 0,
|
|
225
260
|
}));
|
|
226
261
|
await stockOptionlessProducts(ctx, created);
|
|
@@ -233,7 +268,7 @@ async function bulkCreateProducts(ctx, products) {
|
|
|
233
268
|
// are already stocked by the create above, so they're skipped. Backfills the default variantId from a
|
|
234
269
|
// query if the create response didn't return it.
|
|
235
270
|
async function stockOptionlessProducts(ctx, created) {
|
|
236
|
-
const need = created.filter((p) => !p.hasOptions && p.id);
|
|
271
|
+
const need = created.filter((p) => !p.hasOptions && !p.isDigital && p.id); // digital variants ship inStock from the create
|
|
237
272
|
if (!need.length) return;
|
|
238
273
|
const missing = need.filter((p) => !p.variantId).map((p) => p.id);
|
|
239
274
|
if (missing.length) {
|
|
@@ -300,7 +335,8 @@ async function attachProductImages(ctx, items) {
|
|
|
300
335
|
* the DEFAULT path — call it once instead of the individual functions.
|
|
301
336
|
*
|
|
302
337
|
* @param plan {{
|
|
303
|
-
* products: [{ name, description, price, compareAtPrice?, quantity, options?, imageUrl?, altText
|
|
338
|
+
* products: [{ name, description, price, compareAtPrice?, quantity, options?, imageUrl?, altText?,
|
|
339
|
+
* digitalFileUrl?, digitalFileName? }],
|
|
304
340
|
* categories?: { [categoryName]: string[] }, // map of category name -> product NAMES in it
|
|
305
341
|
* }}
|
|
306
342
|
* @returns { products: [{id,slug,revision,name}], categories: [{id,name}], imagesAttached: number }
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
# Editor React Component A11y Review Reference
|
|
2
|
-
|
|
3
|
-
Use this reference for decisions that require code inspection after running the scanners in [`A11Y-REVIEW.md`](A11Y-REVIEW.md). The scanner output owns rule-specific context: rule ID, location, message, resolution path, evidence, and confidence. Do not maintain a separate rule catalog here.
|
|
4
|
-
|
|
5
|
-
## Scanner Result Handling
|
|
6
|
-
|
|
7
|
-
Treat every scanner finding as a lead until the component implementation confirms how the flagged behavior reaches the rendered element.
|
|
8
|
-
|
|
9
|
-
1. Read the full finding, including evidence and confidence when present.
|
|
10
|
-
2. Trace the component topology through local wrappers, shared primitives, and package implementations.
|
|
11
|
-
3. Deduplicate findings that identify the same issue at the same location.
|
|
12
|
-
4. Assign a verdict: `confirmed`, `false-positive`, or `not-relevant`.
|
|
13
|
-
5. Fix confirmed issues inline, then re-run both scanners on changed JSX files.
|
|
14
|
-
|
|
15
|
-
When both scanners flag the same issue, keep the finding with the strongest semantic evidence. The scanners complement each other; a finding from one scanner is not automatically stronger because of its tier.
|
|
16
|
-
|
|
17
|
-
## Confidence Model
|
|
18
|
-
|
|
19
|
-
### High
|
|
20
|
-
|
|
21
|
-
Use high confidence when the code and scanner evidence unambiguously show the violation, for example:
|
|
22
|
-
|
|
23
|
-
- the flagged rendered element and static props establish the behavior directly
|
|
24
|
-
- the component implementation resolves to the flagged semantic element
|
|
25
|
-
- an explicit polymorphic prop establishes the rendered element
|
|
26
|
-
|
|
27
|
-
Fix high-confidence findings immediately.
|
|
28
|
-
|
|
29
|
-
### Medium
|
|
30
|
-
|
|
31
|
-
Use medium confidence when:
|
|
32
|
-
|
|
33
|
-
- props strongly imply the rendered semantics
|
|
34
|
-
- the implementation only partially resolves but preserves likely semantics
|
|
35
|
-
- the component name, props, and surrounding evidence strongly agree
|
|
36
|
-
|
|
37
|
-
Read the surrounding code. If it confirms the inference, fix the issue. If it contradicts the inference, discard the finding. If the implementation remains unresolved, treat it as low confidence.
|
|
38
|
-
|
|
39
|
-
### Low
|
|
40
|
-
|
|
41
|
-
Use low confidence when:
|
|
42
|
-
|
|
43
|
-
- only weak heuristics support the semantic guess
|
|
44
|
-
- the implementation cannot be resolved
|
|
45
|
-
- runtime props or spreads can materially change the rendered semantics
|
|
46
|
-
|
|
47
|
-
Continue tracing the code. Fix only after the issue is confirmed; otherwise leave the code unchanged.
|
|
48
|
-
|
|
49
|
-
### Confidence vs. Actionability
|
|
50
|
-
|
|
51
|
-
Confidence answers whether the issue is real. It does not decide whether a confirmed fix is safe.
|
|
52
|
-
|
|
53
|
-
- Confirmed + safe/local fix: fix now.
|
|
54
|
-
- Confirmed + risky behavior change or non-local refactor: leave unchanged.
|
|
55
|
-
- Unconfirmed or ambiguous: leave unchanged.
|
|
56
|
-
|
|
57
|
-
If the violation is visible in the code and has a localized, behavior-preserving fix, treat it as confirmed and apply the fix.
|
|
58
|
-
|
|
59
|
-
Valid reasons to leave code unchanged:
|
|
60
|
-
|
|
61
|
-
- semantics remain ambiguous after reading the available code
|
|
62
|
-
- product intent cannot be derived from the code
|
|
63
|
-
- the fix requires a risky behavior change or a non-local refactor
|
|
64
|
-
|
|
65
|
-
Do not leave a confirmed safe/local issue unchanged because it is low severity, secondary, shared, or outside the first file in scope.
|
|
66
|
-
|
|
67
|
-
## Semantic Resolution
|
|
68
|
-
|
|
69
|
-
Resolve the rendered behavior in this order:
|
|
70
|
-
|
|
71
|
-
1. The flagged JSX element and its static props
|
|
72
|
-
2. Explicit polymorphic props such as `as="a"` or `component="button"`
|
|
73
|
-
3. The local component implementation
|
|
74
|
-
4. Installed package source or declarations in `node_modules`
|
|
75
|
-
5. Prop evidence such as `href`, `to`, `src`, `alt`, and `role`
|
|
76
|
-
6. Component-name heuristics
|
|
77
|
-
|
|
78
|
-
For local imports, follow the exported component's rendered root. Continue through local or package components until the semantics resolve or the evidence becomes too weak.
|
|
79
|
-
|
|
80
|
-
For package imports, resolve the import from `node_modules` and inspect its exported entry point. If the package hides its rendered semantics, use prop and naming evidence without assigning more confidence than the evidence supports.
|
|
81
|
-
|
|
82
|
-
## Tier 2 Manual Review Checklist
|
|
83
|
-
|
|
84
|
-
Run this checklist after scanner findings are triaged. Tier 2 is required even when both scanners return zero findings.
|
|
85
|
-
|
|
86
|
-
### Semantic Targeting
|
|
87
|
-
|
|
88
|
-
- Do ARIA attributes land on the semantically correct element instead of a layout wrapper?
|
|
89
|
-
- Do labels, descriptions, and roles reach the actual interactive or landmark element?
|
|
90
|
-
- Do wrappers preserve the semantics exposed by their API?
|
|
91
|
-
|
|
92
|
-
### Icon-Only and Visual-Only States
|
|
93
|
-
|
|
94
|
-
- Do icon-only buttons, links, or controls have an accessible name?
|
|
95
|
-
- If visible text is hidden, is it visually hidden in an accessibility-safe way instead of removed from the accessibility tree?
|
|
96
|
-
- Do meaningful icons or images expose accessible text when needed?
|
|
97
|
-
|
|
98
|
-
### CSS and Hidden Content
|
|
99
|
-
|
|
100
|
-
- Does `display: none` remove content that should remain available to assistive technology?
|
|
101
|
-
- Are hidden or collapsed states consistent across visuals, focusability, and the accessibility tree?
|
|
102
|
-
- Do conditional classes or CSS variables create states where labels or instructions disappear from assistive technology?
|
|
103
|
-
|
|
104
|
-
### Decorative vs. Meaningful Content
|
|
105
|
-
|
|
106
|
-
- Are decorative separators, ornaments, and repeated icons hidden from assistive technology?
|
|
107
|
-
- Are meaningful visuals, status icons, or graphics named appropriately?
|
|
108
|
-
|
|
109
|
-
### Focus and Interaction Consistency
|
|
110
|
-
|
|
111
|
-
- Can hidden or collapsed items still receive focus?
|
|
112
|
-
- Do interactive-looking elements expose the correct role and keyboard behavior?
|
|
113
|
-
- Do disabled, inert, or collapsed states behave consistently for keyboard users and assistive technology?
|
|
114
|
-
- Search all in-scope files for `onClick` on elements without built-in interaction (`div`, `span`, `section`, `header`, `footer`, `li`, `td`, and similar tags). Include conditional patterns such as `{...(condition && { onClick: handler })}`. Verify that each match also has the required `role`, `tabIndex`, and keyboard handler (`onKeyDown` or `onKeyUp`). A missing combination is a high-confidence finding.
|
|
115
|
-
- Before fixing missing keyboard semantics, check for nested interactive children, existing focus management, and the condition that enables interaction. Use the [pre-fix checks](#pre-fix-checks-for-adding-button-semantics-to-a-non-interactive-element).
|
|
116
|
-
|
|
117
|
-
### Structural Semantics
|
|
118
|
-
|
|
119
|
-
- Are landmarks, headings, and list semantics preserved through wrappers and layout components?
|
|
120
|
-
- When the component implements breadcrumbs, tabs, menus, dialogs, or similar patterns, do the expected semantics reach the rendered structure?
|
|
121
|
-
|
|
122
|
-
### Editor React Component Contracts
|
|
123
|
-
|
|
124
|
-
- Are ARIA attributes routed through the typed `a11y` prop and converted at the correct element?
|
|
125
|
-
- Do icon-only labels come from `constants.ts` or user-configurable `a11y` instead of hardcoded strings?
|
|
126
|
-
- Does the component preserve direction support and isolate each `ReactNode` content prop with `dir="ltr"`?
|
|
127
|
-
- Do extension overrides preserve a11y-relevant manifest fields generated from JSX?
|
|
128
|
-
|
|
129
|
-
## Fix Principles
|
|
130
|
-
|
|
131
|
-
- Use the rule ID, message, and evidence emitted by the scanner as the rule-specific fix context.
|
|
132
|
-
- Read the surrounding code before editing.
|
|
133
|
-
- Preserve visual and runtime behavior.
|
|
134
|
-
- Prefer the smallest correct change and avoid unrelated refactors.
|
|
135
|
-
- Fix the semantic owner: the component root, the correct inner element, a shared base, or the call site that supplies the value.
|
|
136
|
-
- When a wrapper already accepts and forwards a required prop, fix the call site. When it does not, update the wrapper contract and forwarding before fixing the call site.
|
|
137
|
-
- Do not hardcode reusable accessibility values such as alternative text. Accept them through the component API when they depend on consumer content.
|
|
138
|
-
- Route Editor React Component ARIA through `a11y` and `convertA11yKeysToHtmlFormat(a11y)` according to [`ACCESSIBILITY.md`](ACCESSIBILITY.md).
|
|
139
|
-
|
|
140
|
-
## Pre-Fix Checks for Adding Button Semantics to a Non-Interactive Element
|
|
141
|
-
|
|
142
|
-
Before adding `role="button"`, `tabIndex`, and keyboard handlers to an element such as `<div>`, verify all four conditions below.
|
|
143
|
-
|
|
144
|
-
### 1. Interactive Children
|
|
145
|
-
|
|
146
|
-
Check whether the element conditionally or unconditionally contains `<a>`, `<button>`, `<input>`, `<Link>`, or a component that resolves to an interactive element. Button semantics on the parent would create nested interaction.
|
|
147
|
-
|
|
148
|
-
If interactive children are possible, either exclude that branch from the parent's interaction condition or use a separate control element.
|
|
149
|
-
|
|
150
|
-
### 2. Existing Focus Management
|
|
151
|
-
|
|
152
|
-
Check whether the element already receives `tabIndex` from another source, such as `getTabIndexAttribute`, an a11y prop spread, or an interactions framework. Determine the prop merge order and keep one source authoritative.
|
|
153
|
-
|
|
154
|
-
When an existing a11y spread should win, place the conditional interaction spread before it so `tabIndex: 0` only acts as a fallback.
|
|
155
|
-
|
|
156
|
-
### 3. Interaction Condition
|
|
157
|
-
|
|
158
|
-
Read the full boolean expression that enables interaction. Verify that it:
|
|
159
|
-
|
|
160
|
-
- excludes states that already render an interactive child
|
|
161
|
-
- excludes editor preview, externally controlled, disabled, or reduced-motion states when required
|
|
162
|
-
- uses explicit comparisons such as `=== undefined` or `=== true` when `true`, `false`, and `undefined` have different meanings
|
|
163
|
-
|
|
164
|
-
Fix a fragile condition as part of the accessibility change. Correct semantics attached to the wrong state are still incorrect behavior.
|
|
165
|
-
|
|
166
|
-
### 4. Accessible Name Scope
|
|
167
|
-
|
|
168
|
-
Decide whether an accessible label names the interaction or the component as a whole. Keep a component-level label outside the interaction condition so it persists in non-interactive states. Apply an action-specific label only while that action is available.
|
|
169
|
-
|
|
170
|
-
## After Fixing
|
|
171
|
-
|
|
172
|
-
Re-run both scanners on changed `.tsx` / `.jsx` files. Continue with `npx wix build`, `npx wix generate manifest`, and the project's TypeScript check as required by [`A11Y-REVIEW.md`](A11Y-REVIEW.md#phase-5-verify).
|