@wix/agent-skills 1.20.1 → 1.22.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.
Files changed (262) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +71 -113
  3. package/skills/wix-app/references/APP_TOOLS.md +2 -1
  4. package/skills/wix-app/references/BACKEND_EVENT.md +3 -3
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +41 -152
  6. package/skills/wix-app/references/DASHBOARD_MODAL.md +4 -4
  7. package/skills/wix-app/references/DASHBOARD_PAGE.md +11 -25
  8. package/skills/wix-app/references/DATA_COLLECTION.md +16 -219
  9. package/skills/wix-app/references/SDK_MODULE_MAP.md +44 -0
  10. package/skills/wix-app/references/SITE_PLUGIN.md +36 -190
  11. package/skills/wix-app/references/app-tools/TOOLS.md +3 -1
  12. package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +21 -0
  13. package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +182 -0
  14. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +97 -0
  15. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_COLLECTION.md +184 -0
  16. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_ROUTER.md +203 -0
  17. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE_SETTINGS.md +44 -0
  18. package/skills/wix-app/references/dashboard-page/ECOM_NAVIGATION.md +17 -0
  19. package/skills/wix-app/references/dashboard-page/QUERY_AND_PAGING.md +182 -0
  20. package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +133 -0
  21. package/skills/wix-app/references/dashboard-page/UX_SUCCESS_MODEL.md +10 -5
  22. package/skills/wix-app/references/dashboard-plugin/SLOTS.md +4 -18
  23. package/skills/wix-app/references/data-collection/LIFECYCLE.md +68 -0
  24. package/skills/wix-app/references/data-collection/PERMISSIONS.md +47 -0
  25. package/skills/wix-app/references/data-collection/SCHEMA.md +181 -0
  26. package/skills/wix-app/references/data-collection/WIX_DATA.md +38 -66
  27. package/skills/wix-app/references/site-plugin/EXAMPLES.md +1 -1
  28. package/skills/wix-headless-fast/SKILL.md +144 -221
  29. package/skills/wix-headless-fast/cold-start/bootstrap.mjs +156 -0
  30. package/skills/wix-headless-fast/{entry/skill.md → cold-start/cold-start.md} +15 -15
  31. package/skills/wix-headless-fast/guides/existing-site.md +76 -0
  32. package/skills/wix-headless-fast/guides/reference-mode.md +97 -0
  33. package/skills/wix-headless-fast/install/AGENTS.md +35 -0
  34. package/skills/wix-headless-fast/install/agents-md.mjs +39 -0
  35. package/skills/wix-headless-fast/install/attach.mjs +161 -86
  36. package/skills/wix-headless-fast/install/deploy.mjs +21 -60
  37. package/skills/wix-headless-fast/install/lock.mjs +55 -0
  38. package/skills/wix-headless-fast/install/setup.mjs +259 -0
  39. package/skills/wix-headless-fast/install/templates.mjs +168 -0
  40. package/skills/wix-manage/references/ecommerce/pricing-promotions/ecom-pricing-create-coupon.md +10 -19
  41. package/skills/wix-manage/references/events/create-wix-event.md +5 -1
  42. package/skills/wix-manage/references/google-ads/google-ads-dashboard-navigation.md +27 -0
  43. package/skills/wix-manage/references/google-ads/manage-campaign-success-guide.md +83 -37
  44. package/skills/wix-headless-fast/install/fast-path.mjs +0 -181
  45. package/skills/wix-headless-fast/references/blog/INSTRUCTIONS.md +0 -301
  46. package/skills/wix-headless-fast/references/blog/app/components/blog/BlogFeedView.tsx +0 -136
  47. package/skills/wix-headless-fast/references/blog/app/components/blog/PostView.tsx +0 -112
  48. package/skills/wix-headless-fast/references/blog/app/components/blog/RichContent.tsx +0 -42
  49. package/skills/wix-headless-fast/references/blog/app/hooks/blog/useBlogFeed.ts +0 -31
  50. package/skills/wix-headless-fast/references/blog/app/hooks/blog/usePost.ts +0 -22
  51. package/skills/wix-headless-fast/references/blog/app/wix/blog/blog-feed-store.ts +0 -137
  52. package/skills/wix-headless-fast/references/blog/app/wix/blog/post-store.ts +0 -78
  53. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts-core.ts +0 -117
  54. package/skills/wix-headless-fast/references/blog/app/wix/blog/posts.ts +0 -52
  55. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy-core.ts +0 -47
  56. package/skills/wix-headless-fast/references/blog/app/wix/blog/taxonomy.ts +0 -58
  57. package/skills/wix-headless-fast/references/blog/app/wix/blog/types.ts +0 -62
  58. package/skills/wix-headless-fast/references/blog/app-astro/layouts/SiteLayout.astro +0 -40
  59. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog/[...slug].astro +0 -97
  60. package/skills/wix-headless-fast/references/blog/app-astro/pages/blog.astro +0 -24
  61. package/skills/wix-headless-fast/references/blog/lock/astro/package-lock.json +0 -16156
  62. package/skills/wix-headless-fast/references/blog/rest/posts.ts +0 -42
  63. package/skills/wix-headless-fast/references/blog/rest/taxonomy.ts +0 -62
  64. package/skills/wix-headless-fast/references/blog/seed/SEED.md +0 -81
  65. package/skills/wix-headless-fast/references/blog/seed/seed-blog.mjs +0 -287
  66. package/skills/wix-headless-fast/references/bookings/INSTRUCTIONS.md +0 -275
  67. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServiceBookingView.tsx +0 -144
  68. package/skills/wix-headless-fast/references/bookings/app/components/bookings/ServicesView.tsx +0 -119
  69. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useBookingFlow.ts +0 -32
  70. package/skills/wix-headless-fast/references/bookings/app/hooks/bookings/useServices.ts +0 -23
  71. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-core.ts +0 -218
  72. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking-flow-store.ts +0 -169
  73. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/booking.ts +0 -121
  74. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-core.ts +0 -92
  75. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services-store.ts +0 -90
  76. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/services.ts +0 -57
  77. package/skills/wix-headless-fast/references/bookings/app/wix/bookings/types.ts +0 -72
  78. package/skills/wix-headless-fast/references/bookings/app-astro/layouts/SiteLayout.astro +0 -40
  79. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services/[slug].astro +0 -76
  80. package/skills/wix-headless-fast/references/bookings/app-astro/pages/services.astro +0 -22
  81. package/skills/wix-headless-fast/references/bookings/lock/astro/package-lock.json +0 -11962
  82. package/skills/wix-headless-fast/references/bookings/rest/booking.ts +0 -113
  83. package/skills/wix-headless-fast/references/bookings/rest/services.ts +0 -55
  84. package/skills/wix-headless-fast/references/bookings/seed/SEED.md +0 -71
  85. package/skills/wix-headless-fast/references/bookings/seed/seed-bookings.mjs +0 -302
  86. package/skills/wix-headless-fast/references/cms/INSTRUCTIONS.md +0 -353
  87. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useCollection.ts +0 -50
  88. package/skills/wix-headless-fast/references/cms/app/hooks/cms/useItem.ts +0 -37
  89. package/skills/wix-headless-fast/references/cms/app/wix/cms/collection-store.ts +0 -158
  90. package/skills/wix-headless-fast/references/cms/app/wix/cms/item-store.ts +0 -93
  91. package/skills/wix-headless-fast/references/cms/app/wix/cms/items-core.ts +0 -177
  92. package/skills/wix-headless-fast/references/cms/app/wix/cms/items.ts +0 -123
  93. package/skills/wix-headless-fast/references/cms/app/wix/cms/types.ts +0 -75
  94. package/skills/wix-headless-fast/references/cms/app-astro/layouts/SiteLayout.astro +0 -41
  95. package/skills/wix-headless-fast/references/cms/lock/astro/package-lock.json +0 -11262
  96. package/skills/wix-headless-fast/references/cms/rest/items.ts +0 -125
  97. package/skills/wix-headless-fast/references/cms/seed/SEED.md +0 -112
  98. package/skills/wix-headless-fast/references/cms/seed/seed-cms.mjs +0 -324
  99. package/skills/wix-headless-fast/references/events/INSTRUCTIONS.md +0 -305
  100. package/skills/wix-headless-fast/references/events/app/components/events/EventConfirmationView.tsx +0 -66
  101. package/skills/wix-headless-fast/references/events/app/components/events/EventRegistrationView.tsx +0 -178
  102. package/skills/wix-headless-fast/references/events/app/components/events/EventsView.tsx +0 -118
  103. package/skills/wix-headless-fast/references/events/app/hooks/events/useEventRegistration.ts +0 -35
  104. package/skills/wix-headless-fast/references/events/app/hooks/events/useEvents.ts +0 -24
  105. package/skills/wix-headless-fast/references/events/app/wix/events/events-core.ts +0 -130
  106. package/skills/wix-headless-fast/references/events/app/wix/events/events-store.ts +0 -97
  107. package/skills/wix-headless-fast/references/events/app/wix/events/events.ts +0 -55
  108. package/skills/wix-headless-fast/references/events/app/wix/events/registration-core.ts +0 -113
  109. package/skills/wix-headless-fast/references/events/app/wix/events/registration-store.ts +0 -156
  110. package/skills/wix-headless-fast/references/events/app/wix/events/registration.ts +0 -97
  111. package/skills/wix-headless-fast/references/events/app/wix/events/types.ts +0 -61
  112. package/skills/wix-headless-fast/references/events/app-astro/layouts/SiteLayout.astro +0 -40
  113. package/skills/wix-headless-fast/references/events/app-astro/pages/event-confirmation.astro +0 -12
  114. package/skills/wix-headless-fast/references/events/app-astro/pages/events/[slug].astro +0 -80
  115. package/skills/wix-headless-fast/references/events/app-astro/pages/events.astro +0 -21
  116. package/skills/wix-headless-fast/references/events/lock/astro/package-lock.json +0 -11884
  117. package/skills/wix-headless-fast/references/events/rest/events.ts +0 -57
  118. package/skills/wix-headless-fast/references/events/rest/registration.ts +0 -83
  119. package/skills/wix-headless-fast/references/events/seed/SEED.md +0 -95
  120. package/skills/wix-headless-fast/references/events/seed/seed-events.mjs +0 -276
  121. package/skills/wix-headless-fast/references/forms/INSTRUCTIONS.md +0 -338
  122. package/skills/wix-headless-fast/references/forms/app/hooks/forms/useWixForm.ts +0 -85
  123. package/skills/wix-headless-fast/references/forms/app/wix/forms/form-store.ts +0 -332
  124. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms-core.ts +0 -238
  125. package/skills/wix-headless-fast/references/forms/app/wix/forms/forms.ts +0 -54
  126. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions-core.ts +0 -216
  127. package/skills/wix-headless-fast/references/forms/app/wix/forms/submissions.ts +0 -59
  128. package/skills/wix-headless-fast/references/forms/app/wix/forms/types.ts +0 -135
  129. package/skills/wix-headless-fast/references/forms/lock/astro/package-lock.json +0 -10593
  130. package/skills/wix-headless-fast/references/forms/rest/forms.ts +0 -34
  131. package/skills/wix-headless-fast/references/forms/rest/submissions.ts +0 -56
  132. package/skills/wix-headless-fast/references/forms/seed/SEED.md +0 -116
  133. package/skills/wix-headless-fast/references/forms/seed/seed-forms.mjs +0 -327
  134. package/skills/wix-headless-fast/references/members/INSTRUCTIONS.md +0 -314
  135. package/skills/wix-headless-fast/references/members/app/components/members/AccountView.tsx +0 -60
  136. package/skills/wix-headless-fast/references/members/app/components/members/LoginForm.tsx +0 -155
  137. package/skills/wix-headless-fast/references/members/app/components/members/MemberMenu.tsx +0 -78
  138. package/skills/wix-headless-fast/references/members/app/components/members/RequireAuth.tsx +0 -47
  139. package/skills/wix-headless-fast/references/members/app/hooks/members/useMember.ts +0 -66
  140. package/skills/wix-headless-fast/references/members/app/wix/members/auth-core.ts +0 -105
  141. package/skills/wix-headless-fast/references/members/app/wix/members/auth.ts +0 -59
  142. package/skills/wix-headless-fast/references/members/app/wix/members/client.ts +0 -53
  143. package/skills/wix-headless-fast/references/members/app/wix/members/member-store.ts +0 -122
  144. package/skills/wix-headless-fast/references/members/app/wix/members/members-core.ts +0 -43
  145. package/skills/wix-headless-fast/references/members/app/wix/members/members.ts +0 -29
  146. package/skills/wix-headless-fast/references/members/app/wix/members/types.ts +0 -21
  147. package/skills/wix-headless-fast/references/members/app-astro/layouts/SiteLayout.astro +0 -42
  148. package/skills/wix-headless-fast/references/members/app-astro/pages/account.astro +0 -10
  149. package/skills/wix-headless-fast/references/members/app-astro/pages/login.astro +0 -11
  150. package/skills/wix-headless-fast/references/members/lock/astro/package-lock.json +0 -10329
  151. package/skills/wix-headless-fast/references/members/rest/auth.ts +0 -215
  152. package/skills/wix-headless-fast/references/members/rest/members.ts +0 -26
  153. package/skills/wix-headless-fast/references/members/seed/SEED.md +0 -39
  154. package/skills/wix-headless-fast/references/members/seed/seed-members.mjs +0 -94
  155. package/skills/wix-headless-fast/references/portfolio/INSTRUCTIONS.md +0 -313
  156. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionProjectsView.tsx +0 -110
  157. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/CollectionsView.tsx +0 -90
  158. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/GalleryMedia.tsx +0 -35
  159. package/skills/wix-headless-fast/references/portfolio/app/components/portfolio/ProjectDetailView.tsx +0 -85
  160. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollectionProjects.ts +0 -32
  161. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useCollections.ts +0 -21
  162. package/skills/wix-headless-fast/references/portfolio/app/hooks/portfolio/useProjectDetail.ts +0 -31
  163. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collection-projects-store.ts +0 -82
  164. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/collections-store.ts +0 -58
  165. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio-core.ts +0 -177
  166. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/portfolio.ts +0 -78
  167. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/project-detail-store.ts +0 -81
  168. package/skills/wix-headless-fast/references/portfolio/app/wix/portfolio/types.ts +0 -55
  169. package/skills/wix-headless-fast/references/portfolio/app-astro/layouts/SiteLayout.astro +0 -40
  170. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio/[slug].astro +0 -30
  171. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/portfolio.astro +0 -21
  172. package/skills/wix-headless-fast/references/portfolio/app-astro/pages/projects/[slug].astro +0 -29
  173. package/skills/wix-headless-fast/references/portfolio/lock/astro/package-lock.json +0 -10197
  174. package/skills/wix-headless-fast/references/portfolio/rest/portfolio.ts +0 -75
  175. package/skills/wix-headless-fast/references/portfolio/seed/SEED.md +0 -86
  176. package/skills/wix-headless-fast/references/portfolio/seed/seed-portfolio.mjs +0 -258
  177. package/skills/wix-headless-fast/references/pricing-plans/INSTRUCTIONS.md +0 -294
  178. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlanDetailView.tsx +0 -47
  179. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/PlansView.tsx +0 -101
  180. package/skills/wix-headless-fast/references/pricing-plans/app/components/pricing-plans/SubscribeButton.tsx +0 -41
  181. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlanPurchase.ts +0 -16
  182. package/skills/wix-headless-fast/references/pricing-plans/app/hooks/pricing-plans/usePlans.ts +0 -22
  183. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plan-purchase-store.ts +0 -54
  184. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-core.ts +0 -106
  185. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans-store.ts +0 -64
  186. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/plans.ts +0 -27
  187. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase-core.ts +0 -43
  188. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/purchase.ts +0 -22
  189. package/skills/wix-headless-fast/references/pricing-plans/app/wix/pricing-plans/types.ts +0 -30
  190. package/skills/wix-headless-fast/references/pricing-plans/app-astro/layouts/SiteLayout.astro +0 -41
  191. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans/[slug].astro +0 -40
  192. package/skills/wix-headless-fast/references/pricing-plans/app-astro/pages/plans.astro +0 -21
  193. package/skills/wix-headless-fast/references/pricing-plans/lock/astro/package-lock.json +0 -11226
  194. package/skills/wix-headless-fast/references/pricing-plans/rest/plans.ts +0 -31
  195. package/skills/wix-headless-fast/references/pricing-plans/rest/purchase.ts +0 -20
  196. package/skills/wix-headless-fast/references/pricing-plans/seed/SEED.md +0 -79
  197. package/skills/wix-headless-fast/references/pricing-plans/seed/seed-pricing-plans.mjs +0 -279
  198. package/skills/wix-headless-fast/references/restaurants/INSTRUCTIONS.md +0 -358
  199. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/MenuView.tsx +0 -142
  200. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartButton.tsx +0 -26
  201. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/OrderCartDrawer.tsx +0 -121
  202. package/skills/wix-headless-fast/references/restaurants/app/components/restaurants/ReservationView.tsx +0 -155
  203. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useMenus.ts +0 -34
  204. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useOrderCart.ts +0 -43
  205. package/skills/wix-headless-fast/references/restaurants/app/hooks/restaurants/useReservation.ts +0 -34
  206. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-core.ts +0 -155
  207. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu-store.ts +0 -89
  208. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/menu.ts +0 -71
  209. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/order-store.ts +0 -103
  210. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering-core.ts +0 -124
  211. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/ordering.ts +0 -185
  212. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservation-store.ts +0 -193
  213. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations-core.ts +0 -94
  214. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/reservations.ts +0 -74
  215. package/skills/wix-headless-fast/references/restaurants/app/wix/restaurants/types.ts +0 -168
  216. package/skills/wix-headless-fast/references/restaurants/app-astro/layouts/SiteLayout.astro +0 -47
  217. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/menu.astro +0 -22
  218. package/skills/wix-headless-fast/references/restaurants/app-astro/pages/reservations.astro +0 -12
  219. package/skills/wix-headless-fast/references/restaurants/lock/astro/package-lock.json +0 -12560
  220. package/skills/wix-headless-fast/references/restaurants/rest/menu.ts +0 -60
  221. package/skills/wix-headless-fast/references/restaurants/rest/ordering.ts +0 -169
  222. package/skills/wix-headless-fast/references/restaurants/rest/reservations.ts +0 -68
  223. package/skills/wix-headless-fast/references/restaurants/seed/SEED.md +0 -89
  224. package/skills/wix-headless-fast/references/restaurants/seed/seed-restaurants.mjs +0 -479
  225. package/skills/wix-headless-fast/references/shared/CONTENT.md +0 -22
  226. package/skills/wix-headless-fast/references/shared/CUSTOM_OPERATIONS.md +0 -73
  227. package/skills/wix-headless-fast/references/shared/DESIGN.md +0 -26
  228. package/skills/wix-headless-fast/references/shared/SUPPLIED-CONTENT.md +0 -23
  229. package/skills/wix-headless-fast/references/shared/app/styles/global.css +0 -52
  230. package/skills/wix-headless-fast/references/shared/app/wix/config.ts +0 -15
  231. package/skills/wix-headless-fast/references/shared/app/wix/media.ts +0 -81
  232. package/skills/wix-headless-fast/references/shared/app/wix/money.ts +0 -24
  233. package/skills/wix-headless-fast/references/shared/app/wix/sdk.ts +0 -89
  234. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app/wix/media-upload/client.ts +0 -46
  235. package/skills/wix-headless-fast/references/shared/capabilities/media-upload/app-astro/pages/api/wix/media-upload.ts +0 -46
  236. package/skills/wix-headless-fast/references/shared/rest/client.ts +0 -155
  237. package/skills/wix-headless-fast/references/shared/rest/config.ts +0 -3
  238. package/skills/wix-headless-fast/references/shared/rest/media.ts +0 -65
  239. package/skills/wix-headless-fast/references/shared/seed/images.mjs +0 -145
  240. package/skills/wix-headless-fast/references/storefront/INSTRUCTIONS.md +0 -608
  241. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartButton.tsx +0 -26
  242. package/skills/wix-headless-fast/references/storefront/app/components/storefront/CartDrawer.tsx +0 -155
  243. package/skills/wix-headless-fast/references/storefront/app/components/storefront/FilterPanel.tsx +0 -266
  244. package/skills/wix-headless-fast/references/storefront/app/components/storefront/OptionPicker.tsx +0 -95
  245. package/skills/wix-headless-fast/references/storefront/app/components/storefront/QuickAdd.tsx +0 -136
  246. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useCart.ts +0 -48
  247. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useProductDetail.ts +0 -39
  248. package/skills/wix-headless-fast/references/storefront/app/hooks/storefront/useShop.ts +0 -34
  249. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-core.ts +0 -121
  250. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart-store.ts +0 -107
  251. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/cart.ts +0 -138
  252. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog-core.ts +0 -309
  253. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/catalog.ts +0 -133
  254. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/product-detail-store.ts +0 -147
  255. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/shop-store.ts +0 -289
  256. package/skills/wix-headless-fast/references/storefront/app/wix/storefront/types.ts +0 -167
  257. package/skills/wix-headless-fast/references/storefront/app-astro/layouts/SiteLayout.astro +0 -65
  258. package/skills/wix-headless-fast/references/storefront/lock/astro/package-lock.json +0 -12247
  259. package/skills/wix-headless-fast/references/storefront/rest/cart.ts +0 -132
  260. package/skills/wix-headless-fast/references/storefront/rest/catalog.ts +0 -123
  261. package/skills/wix-headless-fast/references/storefront/seed/SEED.md +0 -124
  262. package/skills/wix-headless-fast/references/storefront/seed/seed-store.mjs +0 -525
@@ -1,332 +0,0 @@
1
- // One form as a framework-free store — the logic behind useWixForm, usable from React (useWixForm
2
- // wraps it with useSyncExternalStore), from a static page or Vue/Svelte (subscribe and render), or
3
- // as the specification for a port. Schema in, validated submission out, minus the markup: load the
4
- // form, hold the visitor's values, validate them against the schema's own rules in our wording,
5
- // upload attachments, create the submission, and map a rejection back onto the controls.
6
- //
7
- // It imports the data layer by names the REST twin exports identically (getForm, uploadFiles,
8
- // createSubmission, submissionErrors, toSubmissionValues), so the same file runs over the SDK in
9
- // Astro/React and over REST on a static page.
10
- //
11
- // SSR-friendly: pass a server-fetched FormDto as `initialForm` and no client fetch happens;
12
- // `start()` then does nothing. Without it `start()` loads the schema. One store per mounted form:
13
- // createFormStore(), not a singleton — a page can hold two forms.
14
- import { getForm } from "./forms";
15
- import {
16
- createSubmission,
17
- normalizePhone,
18
- submissionErrors,
19
- toSubmissionValues,
20
- uploadFiles,
21
- } from "./submissions";
22
- import type { FormDto, FormErrors, FormFieldDto, FormValues } from "./types";
23
-
24
- /**
25
- * The key in `errors` for a message that belongs to the FORM rather than one field — a schema
26
- * that failed to load, or a rejection with no per-field violations. `@` cannot appear in a
27
- * form `target`, so this never collides with a field's own error.
28
- */
29
- export const FORM_ERROR = "@form";
30
-
31
- /** The empty form: every field at a value of the shape its control binds to. */
32
- export function defaultValues(fields: FormFieldDto[]): FormValues {
33
- const values: FormValues = {};
34
- for (const f of fields) values[f.target] = Array.isArray(f.defaultValue) ? [...f.defaultValue] : f.defaultValue;
35
- return values;
36
- }
37
-
38
- /**
39
- * Check one field's value against its own schema. A plain function — usable outside the store,
40
- * and the place to look when a message needs rewording.
41
- *
42
- * Every rule comes from the schema, never from a field's NAME. (The classic mistake is keying
43
- * the email check on `target === "email"`; deriving it from `format` means an owner-added
44
- * PHONE/URL/length rule is honored with no code change.)
45
- *
46
- * A client check LAXER than the server's is worse than none — the visitor then learns about
47
- * the problem only after a round trip, in the server's wording rather than yours.
48
- */
49
- export function validateValue(field: FormFieldDto, value: unknown): string {
50
- const v = String(value ?? "").trim();
51
- const rules = field.validation;
52
-
53
- if (field.required && !v) return `${field.label} is required.`;
54
- if (!v) return ""; // optional and empty → fine
55
-
56
- if (field.control === "number" || field.control === "rating") {
57
- // The control hands back a string, so parse before comparing: "9" > 10 is false but
58
- // "9" > "10" is true.
59
- const n = Number(v);
60
- if (!Number.isFinite(n)) return `${field.label} must be a number.`;
61
- if (rules.minimum != null && n < rules.minimum) return `${field.label} must be ${rules.minimum} or more.`;
62
- if (rules.maximum != null && n > rules.maximum) return `${field.label} must be ${rules.maximum} or less.`;
63
- return "";
64
- }
65
-
66
- if (rules.minLength && v.length < rules.minLength)
67
- return `${field.label} must be at least ${rules.minLength} characters.`;
68
- if (rules.maxLength && v.length > rules.maxLength)
69
- return `${field.label} must be at most ${rules.maxLength} characters.`;
70
- if (rules.format === "EMAIL" && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v))
71
- return "Please enter a valid email address.";
72
- if (rules.format === "URL" && !/^https?:\/\/.+/.test(v)) return "Please enter a valid URL.";
73
- // PHONE is E.164 server-side: leading +, country code, digits. Strip formatting first —
74
- // visitors add spaces, dashes and parens, and rejecting those is a UX bug, not validation.
75
- if (rules.format === "PHONE" && !/^\+[1-9]\d{6,14}$/.test(normalizePhone(v)))
76
- return "Use international format, starting with + and the country code.";
77
- if (rules.pattern && !new RegExp(rules.pattern).test(v))
78
- return `${field.label} is not in the expected format.`;
79
- return "";
80
- }
81
-
82
- /**
83
- * One field's error entries, keyed the way the controls are named. A plain field yields at most
84
- * one (`target`); an ADDRESS yields one per failing subfield (`target/sub`).
85
- *
86
- * An address subfield gets the `required` check only — `country` and `subdivision` are
87
- * country-dependent enums the schema does not enumerate, so their content is the server's call.
88
- */
89
- export function errorsForField(field: FormFieldDto, values: FormValues): FormErrors {
90
- const errors: FormErrors = {};
91
-
92
- if (field.control === "address") {
93
- const parts = (values[field.target] ?? {}) as Record<string, unknown>;
94
- for (const { sub, label, required } of field.addressParts) {
95
- if (required && !String(parts[sub] ?? "").trim()) errors[`${field.target}/${sub}`] = `${label} is required.`;
96
- }
97
- return errors;
98
- }
99
-
100
- if (field.control === "file" || field.control === "signature") {
101
- // Files are File objects, which no string rule can judge — check the count instead.
102
- const picked = ([] as unknown[]).concat(values[field.target] ?? []).filter(Boolean);
103
- const limit = field.validation.fileLimit;
104
- if (field.required && !picked.length) errors[field.target] = `${field.label} is required.`;
105
- else if (limit && picked.length > limit)
106
- errors[field.target] = `Attach at most ${limit} file${limit === 1 ? "" : "s"}.`;
107
- return errors;
108
- }
109
-
110
- if (field.inputType === "ARRAY") {
111
- const picked = (Array.isArray(values[field.target]) ? (values[field.target] as unknown[]) : []).filter(Boolean);
112
- const { minItems, maxItems } = field.validation;
113
- if (field.required && !picked.length) errors[field.target] = `${field.label} is required.`;
114
- else if (minItems && picked.length < minItems) errors[field.target] = `Choose at least ${minItems}.`;
115
- else if (maxItems && picked.length > maxItems) errors[field.target] = `Choose at most ${maxItems}.`;
116
- return errors;
117
- }
118
-
119
- if (field.control === "checkbox") {
120
- if (field.required && values[field.target] !== true) errors[field.target] = `${field.label} is required.`;
121
- return errors;
122
- }
123
-
124
- const message = validateValue(field, values[field.target]);
125
- if (message) errors[field.target] = message;
126
- return errors;
127
- }
128
-
129
- export function errorsForForm(fields: FormFieldDto[], values: FormValues): FormErrors {
130
- const errors: FormErrors = {};
131
- for (const field of fields) Object.assign(errors, errorsForField(field, values));
132
- return errors;
133
- }
134
-
135
- /**
136
- * Move focus to a control by input name. `namedItem` returns a RadioNodeList for a radio or
137
- * checkbox group and an element for everything else — a guard checking only for an element
138
- * silently skips every choice group. FOCUS, not scrollIntoView: scrolling moves the viewport and
139
- * nothing else, leaving a keyboard or screen-reader user where they were.
140
- */
141
- export function focusControl(formEl: HTMLFormElement | null, name: string): void {
142
- const control = formEl?.elements?.namedItem?.(name) as unknown;
143
- const node =
144
- typeof RadioNodeList !== "undefined" && control instanceof RadioNodeList
145
- ? (control[0] as HTMLElement | undefined)
146
- : (control as HTMLElement | undefined);
147
- node?.focus?.();
148
- }
149
-
150
- export interface FormStoreOptions {
151
- /** The form to load (the seed's `formId`). Ignored when `initialForm` is given. */
152
- formId: string;
153
- /** Server-fetched form (Astro frontmatter) — skips the client fetch entirely. */
154
- initialForm?: FormDto;
155
- }
156
-
157
- /** Everything a form surface renders from. Read it with getState() or through a subscription. */
158
- export interface FormState {
159
- /** null while the schema is loading — render a skeleton, not an empty form. */
160
- form: FormDto | null;
161
- /** `target` → current value. Arrays for multi-choice and files, objects for an address. */
162
- values: FormValues;
163
- /** `target` (or `target/sub`) → a visitor-facing message; errors[FORM_ERROR] is form-level. */
164
- errors: FormErrors;
165
- /** Loading the schema, or submitting. */
166
- loading: boolean;
167
- }
168
-
169
- /** A submit event as the store needs it — a React SyntheticEvent or a native Event both fit. */
170
- export type FormSubmitEvent = { preventDefault?: () => void; currentTarget?: unknown };
171
-
172
- export interface FormStore {
173
- getState(): FormState;
174
- subscribe(listener: () => void): () => void;
175
- /** Load the schema when no `initialForm` was given. Call once when mounted. */
176
- start(): void;
177
- /** Stop reacting; drop a late schema response. */
178
- stop(): void;
179
- setValues(next: FormValues | ((prev: FormValues) => FormValues)): void;
180
- /** One field's value — what a control's change handler calls. */
181
- setValue(target: string, value: unknown): void;
182
- /** One field, one address subfield (`target/sub`), or the whole form when called with nothing. */
183
- validate(target?: string): boolean;
184
- /**
185
- * The `onSubmit` handler. Client validation in our wording first (focus lands on the first
186
- * invalid control), then uploads, then the create. Resolves TRUE when the submission was
187
- * created — that IS the success signal; the values are back at the schema's defaults.
188
- */
189
- submit(event?: FormSubmitEvent): Promise<boolean>;
190
- }
191
-
192
- export function createFormStore({ formId, initialForm }: FormStoreOptions): FormStore {
193
- let form: FormDto | null = initialForm ?? null;
194
- // The empty form to reset to after a successful submit — the schema's own defaults.
195
- let empty: FormValues = defaultValues(form?.fields ?? []);
196
- let values: FormValues = empty;
197
- let errors: FormErrors = {};
198
- let loading = !initialForm;
199
- let started = false;
200
- let generation = 0;
201
- const listeners = new Set<() => void>();
202
- let snapshot: FormState | null = null;
203
- const emit = () => { snapshot = null; for (const fn of listeners) fn(); };
204
- const fields = (): FormFieldDto[] => form?.fields ?? [];
205
-
206
- function getState(): FormState {
207
- if (snapshot) return snapshot;
208
- snapshot = { form, values, errors, loading };
209
- return snapshot;
210
- }
211
-
212
- function adopt(loaded: FormDto): void {
213
- form = loaded;
214
- // Seed the controls once the schema is in: every control is controlled from the first
215
- // render, so each target holds a value of the right shape before any of them mount.
216
- empty = defaultValues(loaded.fields);
217
- values = empty;
218
- errors = {};
219
- loading = false;
220
- emit();
221
- }
222
-
223
- function setErrors(next: FormErrors): void { errors = next; emit(); }
224
-
225
- return {
226
- getState,
227
- subscribe(fn) { listeners.add(fn); return () => listeners.delete(fn); },
228
- start() {
229
- if (started) return;
230
- started = true;
231
- if (form) return; // the SSR pass already answered this
232
- if (!formId) {
233
- loading = false;
234
- errors = { [FORM_ERROR]: "No formId — pass one from the seed's forms map." };
235
- emit();
236
- return;
237
- }
238
- const id = ++generation;
239
- loading = true;
240
- emit();
241
- getForm(formId)
242
- .then((loaded) => { if (started && generation === id) adopt(loaded); })
243
- .catch((e: unknown) => {
244
- if (!started || generation !== id) return;
245
- // Fail loudly. A form that cannot load is a setup problem — never fall back to a
246
- // hand-built form, which would drop real enquiries silently.
247
- loading = false;
248
- errors = { [FORM_ERROR]: e instanceof Error ? e.message : "Could not load the form." };
249
- emit();
250
- });
251
- },
252
- stop() { started = false; generation++; },
253
- setValues(next) {
254
- values = typeof next === "function" ? next(values) : next;
255
- emit();
256
- },
257
- setValue(target, value) {
258
- values = { ...values, [target]: value };
259
- emit();
260
- },
261
- validate(target) {
262
- if (!target) {
263
- const all = errorsForForm(fields(), values);
264
- setErrors(all);
265
- return Object.keys(all).length === 0;
266
- }
267
- const key = String(target);
268
- const field = fields().find((f) => f.target === key.split("/")[0]);
269
- if (!field) return true;
270
-
271
- // The keys this call owns, so a re-check CLEARS what it fixed as well as flagging what it
272
- // did not: one key for a plain field, or every subfield when an address itself is named.
273
- const owned = key.includes("/")
274
- ? [key]
275
- : field.control === "address"
276
- ? field.addressParts.map(({ sub }) => `${field.target}/${sub}`)
277
- : [field.target];
278
-
279
- const found = errorsForField(field, values);
280
- const next = { ...errors };
281
- for (const k of owned) {
282
- delete next[k];
283
- if (found[k]) next[k] = found[k];
284
- }
285
- setErrors(next);
286
- return owned.every((k) => !found[k]);
287
- },
288
- async submit(event) {
289
- event?.preventDefault?.();
290
- // Capture the <form> NOW: React clears currentTarget once the handler returns, so reading
291
- // it after the await below (to focus a server-rejected control) comes back null.
292
- const formEl = (event?.currentTarget ?? null) as HTMLFormElement | null;
293
- if (!form) return false;
294
- const current = form;
295
- const currentFields = current.fields;
296
-
297
- // Client pass first, so the visitor gets inline feedback in OUR wording before a round trip.
298
- const clientErrors = errorsForForm(currentFields, values);
299
- if (Object.keys(clientErrors).length) {
300
- setErrors(clientErrors);
301
- focusControl(formEl, Object.keys(clientErrors)[0]);
302
- return false;
303
- }
304
-
305
- loading = true;
306
- emit();
307
- try {
308
- // Attachments go up FIRST — a File is not something the submission API takes, and its
309
- // value is the upload URL this hands back. No file fields → nothing happens here.
310
- const uploaded = await uploadFiles(current.id, currentFields, values);
311
- values = uploaded; // keep the URLs, so a rejection on another field never re-uploads
312
- emit();
313
- await createSubmission(current.id, toSubmissionValues(currentFields, uploaded));
314
- errors = {};
315
- values = empty; // back to the schema's defaults, ready for another
316
- return true;
317
- } catch (e) {
318
- const mapped = submissionErrors(e, currentFields);
319
- if (Object.keys(mapped).length) {
320
- errors = mapped;
321
- focusControl(formEl, Object.keys(mapped)[0]);
322
- } else {
323
- errors = { [FORM_ERROR]: e instanceof Error ? e.message : "Could not send the form. Please try again." };
324
- }
325
- return false;
326
- } finally {
327
- loading = false;
328
- emit();
329
- }
330
- },
331
- };
332
- }
@@ -1,238 +0,0 @@
1
- // Form-schema rules and DTO mapping — transport-agnostic, imported by BOTH transports: ./forms.ts
2
- // (the SDK, managed Astro and React) and the REST twin in references/forms/rest/forms.ts (fetch, a
3
- // static site or a port to another language). Every rule about how a raw Form Schemas v4 entity
4
- // flattens into a FormDto lives HERE, once. A raw form may come from the SDK (`_id`) or from REST
5
- // (`id`); the mappers accept both. Imports are type-only so a strip to JS emits no imports.
6
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/about-form-fields.md
7
- import type {
8
- FormAddressPart,
9
- FormChoice,
10
- FormControl,
11
- FormDto,
12
- FormFieldDto,
13
- FormValidation,
14
- } from "./types";
15
-
16
- /** A raw Form Schemas v4 entity as either transport returns it. */
17
- export type Raw = Record<string, any>;
18
-
19
- /** The Wix Forms app namespace. Every form this vertical touches lives here. */
20
- export const FORMS_NAMESPACE = "wix.form_app.form";
21
-
22
- const id = (raw: Raw | undefined): string => raw?._id ?? raw?.id ?? "";
23
-
24
- // A field's settings nest TWO levels deep, under blocks named after its own enums:
25
- // inputOptions.<inputType block>.<componentType block>.label
26
- // These tables resolve those names. Spelling them at a call site is one typo away from
27
- // silently reading back no label at all — which is the whole reason this file exists.
28
- const INPUT_BLOCK: Record<string, string> = {
29
- STRING: "stringOptions",
30
- NUMBER: "numberOptions",
31
- BOOLEAN: "booleanOptions",
32
- ARRAY: "arrayOptions",
33
- ADDRESS: "addressOptions",
34
- WIX_FILE: "wixFileOptions",
35
- PAYMENT: "paymentOptions",
36
- SCHEDULING: "schedulingOptions",
37
- };
38
-
39
- const COMPONENT_BLOCK: Record<string, string> = {
40
- TEXT_INPUT: "textInputOptions",
41
- NUMBER_INPUT: "numberInputOptions",
42
- RATING_INPUT: "ratingInputOptions",
43
- PHONE_INPUT: "phoneInputOptions",
44
- DATE_INPUT: "dateInputOptions",
45
- DATE_PICKER: "datePickerOptions",
46
- DATE_TIME: "dateTimeOptions",
47
- TIME_INPUT: "timeInputOptions",
48
- CHECKBOX: "checkboxOptions",
49
- CHECKBOX_GROUP: "checkboxGroupOptions",
50
- RADIO_GROUP: "radioGroupOptions",
51
- DROPDOWN: "dropdownOptions",
52
- TAGS: "tagsOptions",
53
- MULTILINE_ADDRESS: "multilineAddressOptions",
54
- FILE_UPLOAD: "fileUploadOptions",
55
- SIGNATURE: "signatureOptions",
56
- FIXED_PAYMENT: "fixedPaymentOptions",
57
- PAYMENT_INPUT: "paymentInputOptions",
58
- DONATION_INPUT: "donationInputOptions",
59
- APPOINTMENT: "appointmentOptions",
60
- SERVICES_DROPDOWN: "servicesDropdownOptions",
61
- SERVICES_CHECKBOX_GROUP: "servicesCheckboxGroupOptions",
62
- };
63
-
64
- // componentType → the control to render. Several field kinds share one component (short and
65
- // long answer are both TEXT_INPUT), so `format` and `inputType` refine it below.
66
- const CONTROL: Record<string, FormControl> = {
67
- TEXT_INPUT: "text",
68
- NUMBER_INPUT: "number",
69
- RATING_INPUT: "rating",
70
- PHONE_INPUT: "phone",
71
- DATE_INPUT: "date",
72
- DATE_PICKER: "date",
73
- DATE_TIME: "datetime",
74
- TIME_INPUT: "time",
75
- CHECKBOX: "checkbox",
76
- CHECKBOX_GROUP: "checkboxGroup",
77
- RADIO_GROUP: "radio",
78
- DROPDOWN: "select",
79
- TAGS: "tags",
80
- MULTILINE_ADDRESS: "address",
81
- FILE_UPLOAD: "file",
82
- SIGNATURE: "signature",
83
- FIXED_PAYMENT: "payment",
84
- PAYMENT_INPUT: "payment",
85
- DONATION_INPUT: "payment",
86
- SERVICES_DROPDOWN: "select",
87
- SERVICES_CHECKBOX_GROUP: "checkboxGroup",
88
- APPOINTMENT: "appointment",
89
- };
90
-
91
- // An enum missing from a table means Wix added a type. Say so ONCE — a silent empty block
92
- // renders a field labelled by its storage key with none of its settings.
93
- const warned = new Set<string>();
94
- function blockName(table: Record<string, string>, key: string | undefined, what: string): string | undefined {
95
- const name = key ? table[key] : undefined;
96
- if (!name && key && !warned.has(what + key)) {
97
- warned.add(what + key);
98
- console.warn(
99
- `forms: no ${what} block mapped for "${key}" — that field renders without its label or ` +
100
- `options. Add it to the table in wix/forms/forms-core.ts.`,
101
- );
102
- }
103
- return name;
104
- }
105
-
106
- /** A BOOLEAN consent field labels itself with Ricos rich content; take its plain text. */
107
- export function plainText(label: unknown): string {
108
- if (typeof label === "string") return label;
109
- const nodes = (label as Raw)?.nodes;
110
- if (!Array.isArray(nodes)) return "";
111
- const walk = (list: Raw[]): string =>
112
- list
113
- .map((n) => (n?.textData?.text ?? "") + (Array.isArray(n?.nodes) ? walk(n.nodes) : ""))
114
- .join("");
115
- return walk(nodes).trim();
116
- }
117
-
118
- /** `postalCode` → "Postal code". A subfield is a key; the schema carries no label for it. */
119
- export function humanizeSub(sub: string): string {
120
- const words = sub.replace(/([A-Z])|(\d+)/g, " $1$2").toLowerCase().trim();
121
- return words.charAt(0).toUpperCase() + words.slice(1);
122
- }
123
-
124
- export function toField(raw: Raw): FormFieldDto {
125
- const input = raw.inputOptions ?? {};
126
- const inputType: string = input.inputType ?? "";
127
- const optionsBlock: Raw = input[blockName(INPUT_BLOCK, inputType, "inputType") ?? ""] ?? {};
128
- const componentType: string = optionsBlock.componentType ?? "";
129
- const component: Raw = optionsBlock[blockName(COMPONENT_BLOCK, componentType, "componentType") ?? ""] ?? {};
130
- const rules: Raw = optionsBlock.validation ?? {};
131
-
132
- const validation: FormValidation = {
133
- ...(rules.format ? { format: rules.format } : {}),
134
- ...(rules.minLength != null ? { minLength: rules.minLength } : {}),
135
- ...(rules.maxLength != null ? { maxLength: rules.maxLength } : {}),
136
- ...(rules.pattern ? { pattern: rules.pattern } : {}),
137
- // JSON-Schema spelling everywhere else in this block; minValue/maxValue is read too since
138
- // the public reference documents neither and an older schema may carry them.
139
- ...((rules.minimum ?? rules.minValue) != null ? { minimum: rules.minimum ?? rules.minValue } : {}),
140
- ...((rules.maximum ?? rules.maxValue) != null ? { maximum: rules.maximum ?? rules.maxValue } : {}),
141
- ...(rules.fileLimit != null ? { fileLimit: rules.fileLimit } : {}),
142
- ...(rules.minItems != null ? { minItems: rules.minItems } : {}),
143
- ...(rules.maxItems != null ? { maxItems: rules.maxItems } : {}),
144
- };
145
-
146
- // TEXT_INPUT covers short answer, long answer, email, url and phone — and a long answer is
147
- // NOT flagged on the component (no `multiline`, no `numberOfLines`). Only `identifier` says
148
- // TEXT_AREA, which is why it is carried on the DTO.
149
- const identifier: string = raw.identifier ?? "";
150
- let control: FormControl = CONTROL[componentType] ?? "unknown";
151
- // A product list is a PAYMENT field wearing a CHECKBOX_GROUP component — typed by its
152
- // component it would look like a multi-choice and be bound to an array of strings, when what
153
- // it submits is a payment structure. The input type wins.
154
- if (inputType === "PAYMENT") control = "payment";
155
- if (control === "text") {
156
- if (identifier === "TEXT_AREA" || component.multiline || component.numberOfLines > 1) control = "textarea";
157
- else if (rules.format === "EMAIL") control = "email";
158
- else if (rules.format === "URL") control = "url";
159
- else if (rules.format === "PHONE") control = "phone";
160
- }
161
-
162
- const choices: FormChoice[] = Array.isArray(component.options)
163
- ? component.options.map((o: Raw) => ({ value: String(o.value), label: String(o.label ?? o.value) }))
164
- : [];
165
-
166
- const addressParts: FormAddressPart[] = Object.entries((rules.fields ?? {}) as Raw)
167
- // Only addressLine2 carries a visibility setting; hide it when the owner turned it off.
168
- .filter(([sub]) => component.fieldSettings?.[sub]?.show !== false)
169
- .map(([sub, cfg]) => ({ sub, label: humanizeSub(sub), required: (cfg as Raw)?.required ?? false }));
170
-
171
- const target: string = input.target ?? "";
172
- const label = plainText(component.label) || target;
173
-
174
- // Every control is controlled from the first render, so each field starts at a value of the
175
- // right SHAPE — [] for multi-choice and files, {} for an address, the owner's prefill else "".
176
- // Wix spells the prefill `default` on most components and `defaultValue` on a rating.
177
- const prefill = component.default ?? component.defaultValue;
178
- const defaultValue =
179
- control === "address" ? {} :
180
- inputType === "ARRAY" || inputType === "WIX_FILE" ? [] :
181
- // a consent checkbox is a BOOLEAN: "" would bind to `checked` as false and work by
182
- // accident, but the DTO promises the shape its control writes back
183
- inputType === "BOOLEAN" ? ((prefill as boolean | undefined) ?? false) :
184
- (prefill as string | number | boolean | undefined) ?? "";
185
-
186
- return {
187
- target,
188
- label,
189
- control,
190
- required: input.required ?? false,
191
- ...(component.placeholder ? { placeholder: String(component.placeholder) } : {}),
192
- ...(component.description ? { description: plainText(component.description) } : {}),
193
- defaultValue,
194
- choices,
195
- addressParts,
196
- validation,
197
- ...(component.defaultCountryCode || rules.phoneOptions?.allowedCountryCodes?.[0]
198
- ? { phoneCountry: component.defaultCountryCode ?? rules.phoneOptions.allowedCountryCodes[0] }
199
- : {}),
200
- identifier,
201
- inputType,
202
- componentType,
203
- };
204
- }
205
-
206
- /**
207
- * Display order comes from `steps[].layout`, NOT from `formFields[]` array order. Sort WITHIN
208
- * each step and concatenate in step order: `row` restarts at 0 in every step, so one sort
209
- * across the flattened list interleaves them. A field the owner never placed sorts LAST — it
210
- * still stores values. The submit button is `fieldType: "DISPLAY"`, so filtering to INPUT
211
- * drops it automatically.
212
- */
213
- export function orderedInputs(raw: Raw): Raw[] {
214
- const order = new Map<string, number>(
215
- ((raw.steps ?? []) as Raw[])
216
- .flatMap((s) =>
217
- ((s.layout?.large?.items ?? s.layout?.medium?.items ?? s.layout?.small?.items ?? []) as Raw[])
218
- .slice()
219
- .sort((a, b) => a.row - b.row || a.column - b.column),
220
- )
221
- .map((item, i) => [item.fieldId as string, i] as const),
222
- );
223
- return ((raw.formFields ?? []) as Raw[])
224
- .filter((f) => f.fieldType === "INPUT" && !f.hidden)
225
- .sort((a, b) => (order.get(a.id) ?? Infinity) - (order.get(b.id) ?? Infinity));
226
- }
227
-
228
- export function toForm(raw: Raw): FormDto {
229
- const submit = ((raw.formFields ?? []) as Raw[]).find((f) => f.identifier === "SUBMIT_BUTTON");
230
- return {
231
- id: id(raw),
232
- name: raw.name ?? "",
233
- fields: orderedInputs(raw).map(toField),
234
- // The submit wording lives on a DISPLAY field, nested under pageNavigationOptions because
235
- // one control drives both multi-page navigation and the final submit.
236
- submitText: submit?.displayOptions?.pageNavigationOptions?.submitText ?? "",
237
- };
238
- }
@@ -1,54 +0,0 @@
1
- // Wix Forms schema reads — the only file that touches a raw Form on this transport. Returns flat
2
- // FormDto / FormFieldDto from ./types. The flattening rules live in ./forms-core (shared with the
3
- // REST twin in references/forms/rest/); this file is the transport only. Copy as-is; extend by
4
- // adding functions.
5
- //
6
- // The reads go over `wixFetch` (the SDK's own authenticated fetch), NOT the `forms` module of
7
- // @wix/forms: that generated module is 15 MB. Bundled server-side it pushes a Wix deploy past its
8
- // size limit (HTTP 413 on release); bundled client-side every visitor downloads it. The
9
- // submissions module (./submissions.ts) is 100 KB and stays on the SDK.
10
- //
11
- // The visitor token is enough, and the spec says otherwise. Every schema read is listed under
12
- // the owner scope `SCOPE.FORMS.VIEW-FORM`, and returns 200 on an anonymous visitor: Wix grants
13
- // implicit visitor access so a published site can render its own forms. Do NOT add a backend, a
14
- // connector token, or auth.elevate to make a form load.
15
- //
16
- // docs: https://dev.wix.com/docs/sdk/business-solutions/forms/forms/get-form.md
17
- // docs: https://dev.wix.com/docs/sdk/business-solutions/forms/forms/list-forms.md
18
- // docs: https://dev.wix.com/docs/api-reference/crm/forms/form-schemas/about-form-fields.md
19
- import { wixFetch } from "../sdk";
20
- import { FORMS_NAMESPACE, toForm, type Raw } from "./forms-core";
21
- import type { FormDto } from "./types";
22
-
23
- export { FORMS_NAMESPACE };
24
-
25
- async function getJson(path: string): Promise<Raw> {
26
- const res = await wixFetch(path);
27
- if (!res.ok) throw new Error(`forms: GET ${path} failed (${res.status}).`);
28
- return (await res.json()) as Raw;
29
- }
30
-
31
- /**
32
- * Read one form by id. Throws when the id is wrong or the form was deleted — a form that
33
- * cannot load is a setup problem, so fail loudly rather than rendering a hand-built fallback
34
- * that would drop real enquiries silently.
35
- */
36
- export async function getForm(formId: string): Promise<FormDto> {
37
- // GET /form-schema-service/v4/forms/{formId} → { form }; 404 FORM_NOT_FOUND on a wrong id.
38
- const res = await getJson(`/form-schema-service/v4/forms/${encodeURIComponent(formId)}`);
39
- if (!res?.form) throw new Error(`forms: form "${formId}" not found.`);
40
- return toForm(res.form as Raw);
41
- }
42
-
43
- /**
44
- * Every form on the site, in the Wix Forms namespace. Use ONE call for several forms on a page
45
- * rather than a getForm each.
46
- *
47
- * Returns only ENABLED forms — a form the owner disabled vanishes from the listing rather
48
- * than erroring. That is usually right for a public site.
49
- */
50
- export async function listForms(): Promise<FormDto[]> {
51
- // GET /form-schema-service/v4/forms?namespace=… → { forms }; the namespace is required (400 without).
52
- const res = await getJson(`/form-schema-service/v4/forms?namespace=${encodeURIComponent(FORMS_NAMESPACE)}`);
53
- return ((res?.forms ?? []) as Raw[]).map(toForm);
54
- }