@wix/agent-skills 1.6.0 → 1.8.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 (195) hide show
  1. package/README.md +5 -9
  2. package/package.json +1 -1
  3. package/skills/wix-app/SKILL.md +51 -42
  4. package/skills/wix-app/references/BACKEND_EVENT.md +10 -65
  5. package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +101 -406
  6. package/skills/wix-app/references/DASHBOARD_MENU_PLUGIN.md +14 -111
  7. package/skills/wix-app/references/DASHBOARD_MODAL.md +56 -205
  8. package/skills/wix-app/references/DASHBOARD_PAGE.md +19 -98
  9. package/skills/wix-app/references/DASHBOARD_PLUGIN.md +6 -108
  10. package/skills/wix-app/references/DATA_COLLECTION.md +113 -198
  11. package/skills/wix-app/references/EMBEDDED_SCRIPT.md +41 -268
  12. package/skills/wix-app/references/EXTENSION_REGISTRATION.md +27 -76
  13. package/skills/wix-app/references/SERVICE_PLUGIN.md +35 -188
  14. package/skills/wix-app/references/SITE_PLUGIN.md +8 -92
  15. package/skills/wix-app/references/STORES_VERSIONING.md +1 -0
  16. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +0 -44
  17. package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +19 -330
  18. package/skills/wix-app/references/dashboard-menu-plugin/bookings-slots.md +0 -12
  19. package/skills/wix-app/references/dashboard-menu-plugin/ecommerce-slots.md +7 -0
  20. package/skills/wix-app/references/dashboard-menu-plugin/restaurants-slots.md +0 -12
  21. package/skills/wix-app/references/dashboard-plugin/SLOTS.md +3 -15
  22. package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +2 -18
  23. package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +2 -42
  24. package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +1 -11
  25. package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +1 -11
  26. package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +2 -40
  27. package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +2 -19
  28. package/skills/wix-app/references/service-plugin/VALIDATIONS.md +2 -18
  29. package/skills/wix-app/references/site-plugin/SLOTS.md +17 -68
  30. package/skills/wix-design-system/SKILL.md +4 -0
  31. package/skills/wix-headless/SKILL.md +131 -386
  32. package/skills/wix-headless/references/BUILD-astro.md +246 -0
  33. package/skills/wix-headless/references/BUILD-own-build.md +167 -0
  34. package/skills/wix-headless/references/BUILD.md +105 -0
  35. package/skills/wix-headless/references/DESIGN_SYSTEM.md +175 -0
  36. package/skills/wix-headless/references/DISCOVERY-connect.md +55 -0
  37. package/skills/wix-headless/references/DISCOVERY-create.md +238 -0
  38. package/skills/wix-headless/references/DISCOVERY.md +50 -306
  39. package/skills/wix-headless/references/PLAN-connect.md +19 -0
  40. package/skills/wix-headless/references/PLAN-create.md +17 -0
  41. package/skills/wix-headless/references/PLAN.md +92 -0
  42. package/skills/wix-headless/references/SEED.md +214 -0
  43. package/skills/wix-headless/references/SETUP.md +73 -248
  44. package/skills/wix-headless/references/{blog → astro/blog}/BLOG_PAGES.md +6 -5
  45. package/skills/wix-headless/references/{blog → astro/blog}/BLOG_SETUP.md +2 -2
  46. package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +337 -0
  47. package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +428 -0
  48. package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +214 -0
  49. package/skills/wix-headless/references/{cms → astro/cms}/FAQ_KNOWLEDGE_BASE.md +14 -12
  50. package/skills/wix-headless/references/{cms → astro/cms}/PORTFOLIO.md +15 -16
  51. package/skills/wix-headless/references/{cms → astro/cms}/RESOURCE_LIBRARY.md +13 -15
  52. package/skills/wix-headless/references/{cms → astro/cms}/TEAM_DIRECTORY.md +11 -11
  53. package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +354 -0
  54. package/skills/wix-headless/references/{ecom → astro/ecom}/CART_PAGES.md +8 -9
  55. package/skills/wix-headless/references/{ecom → astro/ecom}/CART_WIRING.md +6 -6
  56. package/skills/wix-headless/references/{ecom → astro/ecom}/COMPONENTS_CSS.md +6 -6
  57. package/skills/wix-headless/references/{forms → astro/forms}/CONTACT_FORM.md +18 -32
  58. package/skills/wix-headless/references/{gift-cards → astro/gift-cards}/COMPONENTS.md +3 -3
  59. package/skills/wix-headless/references/{gift-cards → astro/gift-cards}/PAGES.md +2 -2
  60. package/skills/wix-headless/references/{stores → astro/stores}/BACK_IN_STOCK.md +7 -7
  61. package/skills/wix-headless/references/{stores → astro/stores}/CATEGORY_PAGES.md +12 -13
  62. package/skills/wix-headless/references/{stores → astro/stores}/COMPONENTS_CSS.md +7 -7
  63. package/skills/wix-headless/references/{stores → astro/stores}/HOME_AND_NAV.md +11 -9
  64. package/skills/wix-headless/references/{stores → astro/stores}/PRODUCT_PAGES.md +11 -9
  65. package/skills/wix-headless/references/{stores → astro/stores}/SHARED_WIRING.md +8 -7
  66. package/skills/wix-headless/references/astro/templates/Footer.astro +27 -0
  67. package/skills/wix-headless/references/astro/templates/Layout.astro +132 -0
  68. package/skills/wix-headless/references/astro/templates/Navigation.astro +38 -0
  69. package/skills/wix-headless/references/astro/templates/astro.config.mjs +41 -0
  70. package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +218 -0
  71. package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +194 -0
  72. package/skills/wix-headless/references/astro/templates/bookings/ManageBooking.tsx +84 -0
  73. package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +25 -0
  74. package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +50 -0
  75. package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +45 -0
  76. package/skills/wix-headless/references/astro/templates/bookings/api/confirm-booking.ts +34 -0
  77. package/skills/wix-headless/references/astro/templates/bookings/api/waitlist.ts +74 -0
  78. package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +111 -0
  79. package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +413 -0
  80. package/skills/wix-headless/references/astro/templates/bookings/manage-booking.astro +76 -0
  81. package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +81 -0
  82. package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +65 -0
  83. package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +302 -0
  84. package/skills/wix-headless/references/astro/templates/global.css +286 -0
  85. package/skills/wix-headless/references/astro/templates/index.astro +56 -0
  86. package/skills/wix-headless/{templates → references/astro/templates}/stores/back-in-stock.ts +1 -1
  87. package/skills/wix-headless/{templates → references/astro/templates}/stores/components-stores.css +138 -33
  88. package/skills/wix-headless/references/blog/BLOG_CONTENT.md +28 -19
  89. package/skills/wix-headless/references/blog/INSTRUCTIONS.md +6 -6
  90. package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +106 -0
  91. package/skills/wix-headless/references/bookings/SERVICES_DATA.md +295 -0
  92. package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +35 -232
  93. package/skills/wix-headless/references/cms/INSTRUCTIONS.md +39 -8
  94. package/skills/wix-headless/references/commands/known-apps.json +2 -1
  95. package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +142 -0
  96. package/skills/wix-headless/references/custom/INSTRUCTIONS.md +88 -0
  97. package/skills/wix-headless/references/custom/blog/WIRING.md +52 -0
  98. package/skills/wix-headless/references/custom/bookings/WIRING.md +88 -0
  99. package/skills/wix-headless/references/custom/cms/WIRING.md +97 -0
  100. package/skills/wix-headless/references/custom/ecom/WIRING.md +67 -0
  101. package/skills/wix-headless/references/custom/forms/WIRING.md +101 -0
  102. package/skills/wix-headless/references/custom/stores/WIRING.md +80 -0
  103. package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +12 -12
  104. package/skills/wix-headless/references/forms/INSTRUCTIONS.md +6 -6
  105. package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +13 -13
  106. package/skills/wix-headless/references/images/INSTRUCTIONS.md +58 -60
  107. package/skills/wix-headless/references/seed-recipes.md +49 -0
  108. package/skills/wix-headless/references/shared/AGENTS_MD.md +47 -0
  109. package/skills/wix-headless/references/shared/AUTHENTICATION.md +108 -0
  110. package/skills/wix-headless/references/shared/BUILD_NOISE.md +2 -2
  111. package/skills/wix-headless/references/shared/DESIGN_MD.md +85 -0
  112. package/skills/wix-headless/references/shared/DOCS_SEARCH.md +41 -0
  113. package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +40 -39
  114. package/skills/wix-headless/references/shared/IMPLEMENTER.md +92 -41
  115. package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +3 -3
  116. package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +32 -312
  117. package/skills/wix-headless/references/shared/STYLING.md +48 -21
  118. package/skills/wix-headless/references/stores/INSTRUCTIONS.md +59 -29
  119. package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +31 -28
  120. package/skills/wix-headless/references/verticals/_schema.json +31 -117
  121. package/skills/wix-headless/references/verticals/_schema.md +60 -150
  122. package/skills/wix-headless/references/verticals/blog.md +5 -99
  123. package/skills/wix-headless/references/verticals/bookings.md +41 -0
  124. package/skills/wix-headless/references/verticals/cms.md +9 -100
  125. package/skills/wix-headless/references/verticals/ecom.md +6 -77
  126. package/skills/wix-headless/references/verticals/forms.md +5 -85
  127. package/skills/wix-headless/references/verticals/gift-cards.md +6 -103
  128. package/skills/wix-headless/references/verticals/stores.md +10 -144
  129. package/skills/wix-headless/scripts/check-manifest.mjs +148 -11
  130. package/skills/wix-headless/scripts/compose.mjs +540 -0
  131. package/skills/wix-headless/scripts/emit-design-tokens.mjs +136 -53
  132. package/skills/wix-headless/scripts/flatten.sh +61 -0
  133. package/skills/wix-headless/scripts/generate-images.mjs +242 -0
  134. package/skills/wix-headless/scripts/patch-decorative-slots.mjs +67 -43
  135. package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +3 -3
  136. package/skills/wix-headless/scripts/scaffold.sh +113 -27
  137. package/skills/wix-headless/scripts/seed-utilities.sh +50 -12
  138. package/skills/wix-headless/scripts/write-decorative-json.mjs +62 -0
  139. package/skills/wix-manage/SKILL.md +4 -8
  140. package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +2 -0
  141. package/skills/wix-manage/references/cms/cms-data-items-crud.md +4 -0
  142. package/skills/wix-manage/references/cms/cms-references-and-relationships.md +2 -0
  143. package/skills/wix-manage/references/cms/cms-schema-management.md +4 -0
  144. package/skills/wix-manage/references/domains/domain-search-and-purchase.md +10 -7
  145. package/skills/wix-manage/references/ecommerce/api-shipping.md +443 -0
  146. package/skills/wix-manage/references/ecommerce/flow-add-free-shipping.md +5 -6
  147. package/skills/wix-manage/references/ecommerce/flow-fix-coverage-gaps.md +4 -5
  148. package/skills/wix-manage/references/ecommerce/flow-optimize-shipping-rates.md +4 -5
  149. package/skills/wix-manage/references/ecommerce/goal-increase-aov.md +1 -1
  150. package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +1 -2
  151. package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +2 -2
  152. package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +4 -5
  153. package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +7 -7
  154. package/skills/wix-manage/references/ecommerce/setup-discount-rules.md +209 -72
  155. package/skills/wix-manage/references/ecommerce/setup-store-pickup-location.md +9 -10
  156. package/skills/wix-manage/references/ecommerce/skill-graph.md +4 -4
  157. package/skills/wix-manage/references/forms/create-form.md +50 -0
  158. package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +2 -0
  159. package/skills/wix-manage/references/stores/create-product-from-image.md +91 -38
  160. package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +2 -0
  161. package/skills/wix-app/references/custom-element-widget/default-thumbnail.png +0 -0
  162. package/skills/wix-app/references/data-collection/extension-template.ts +0 -107
  163. package/skills/wix-headless/references/ORCHESTRATION.md +0 -269
  164. package/skills/wix-headless/references/commands/install-app.md +0 -42
  165. package/skills/wix-headless/references/commands/mcp-bootstrap.md +0 -28
  166. package/skills/wix-headless/references/designer/INSTRUCTIONS.md +0 -828
  167. package/skills/wix-headless/references/shared/MCP_PREFIX.md +0 -105
  168. package/skills/wix-headless/scripts/copy-utility-templates.mjs +0 -153
  169. package/skills/wix-headless/scripts/finalize-run-json.mjs +0 -141
  170. package/skills/wix-headless/scripts/init-site-json.mjs +0 -63
  171. package/skills/wix-headless/scripts/preview.sh +0 -45
  172. package/skills/wix-headless/scripts/release.sh +0 -73
  173. package/skills/wix-headless/templates/ecom/components-ecom.css +0 -215
  174. package/skills/wix-manage/references/events/list-events.md +0 -203
  175. /package/skills/wix-headless/{templates → references/astro/templates}/ecom/CartBadge.tsx +0 -0
  176. /package/skills/wix-headless/{templates → references/astro/templates}/ecom/CartView.tsx +0 -0
  177. /package/skills/wix-headless/{templates → references/astro/templates}/ecom/cart.astro +0 -0
  178. /package/skills/wix-headless/{templates → references/astro/templates}/ecom/discounts.ts +0 -0
  179. /package/skills/wix-headless/{templates → references/astro/templates}/ecom/thank-you.astro +0 -0
  180. /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/GiftCardPurchase.tsx +0 -0
  181. /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/_home-teaser-snippet.astro +0 -0
  182. /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/_nav-snippet.astro +0 -0
  183. /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/components-gift-cards.css +0 -0
  184. /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/gift-cards.astro +0 -0
  185. /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/gift-cards.ts +0 -0
  186. /package/skills/wix-headless/{templates → references/astro/templates}/stores/AddToCartButton.tsx +0 -0
  187. /package/skills/wix-headless/{templates → references/astro/templates}/stores/BackInStockForm.tsx +0 -0
  188. /package/skills/wix-headless/{templates → references/astro/templates}/stores/CategoryRail.astro +0 -0
  189. /package/skills/wix-headless/{templates → references/astro/templates}/stores/ProductCard.astro +0 -0
  190. /package/skills/wix-headless/{templates → references/astro/templates}/stores/ProductPurchase.tsx +0 -0
  191. /package/skills/wix-headless/{templates → references/astro/templates}/stores/SeoTags.astro +0 -0
  192. /package/skills/wix-headless/{templates → references/astro/templates}/stores/categories.ts +0 -0
  193. /package/skills/wix-headless/{templates → references/astro/templates}/stores/category/[slug].astro +0 -0
  194. /package/skills/wix-headless/{templates → references/astro/templates}/stores/products/[slug].astro +0 -0
  195. /package/skills/wix-headless/{templates → references/astro/templates}/stores/products/index.astro +0 -0
@@ -1,299 +1,65 @@
1
1
 
2
2
  # Wix Custom Element Widget Builder
3
3
 
4
- Creates custom element widget extensions for Wix CLI applications. Custom element widgets are React components converted to web components that appear in the Wix Editor, allowing site owners to add interactive, configurable widgets to their pages with a built-in settings panel.
4
+ Custom element widgets are native web components (HTML custom elements) that appear in the Wix Editor. Site owners add interactive, configurable widgets to their pages and edit them through a built-in settings panel.
5
5
 
6
- ## Quick Start Checklist
6
+ ## Scaffold
7
7
 
8
- Follow these steps in order when creating a custom element widget:
8
+ Use `wix generate --params` with `extensionType: CUSTOM_ELEMENT`. `folder` must be a valid custom-element tag name (lowercase, starts with a letter, contains at least one hyphen). The CLI generates 4 files plus the `src/extensions.ts` registration:
9
9
 
10
- 1. [ ] Create widget folder: `src/extensions/site/widgets/custom-elements/<widget-name>/`
11
- 2. [ ] Create `widget.tsx` with React component and `reactToWebComponent` conversion
12
- 3. [ ] Create `panel.tsx` with WDS components and `widget.getProp/setProp`
13
- 4. [ ] Create `extensions.ts` with `extensions.customElement()` and unique UUID
14
- 5. [ ] Update `src/extensions.ts` to import and use the new extension
10
+ | File | Purpose |
11
+ |------|---------|
12
+ | `<name>.tsx` | The widget — a class that extends `HTMLElement` |
13
+ | `<name>.panel.tsx` | The settings panel React component shown in the Editor sidebar |
14
+ | `<name>.module.css` | CSS Modules stylesheet pre-wired with a `.root` class and CSS custom-property tokens |
15
+ | `<name>.extension.ts` | Builder file (UUID, name, sizing defaults, auto-add, presets, tagName, file paths) |
15
16
 
16
- ## Architecture
17
+ After scaffolding, edit `<name>.tsx` for the widget logic, `<name>.panel.tsx` for the settings UI, `<name>.module.css` for the visual design, and the builder file only for non-default sizing, auto-add, or preset behavior.
17
18
 
18
- Custom element widgets consist of **two required files**:
19
+ ## Widget Component (`<name>.tsx`)
19
20
 
20
- ### 1. Widget Component (`widget.tsx`)
21
+ Wix calls `customElements.define()` for you using the builder's `tagName`; do NOT call it in your code.
21
22
 
22
- React component converted to a web component using `react-to-webcomponent`:
23
+ Key authoring rules:
23
24
 
24
- - Define Props interface with configurable properties (camelCase)
25
- - Create a React functional component that renders the widget UI
26
- - Convert to web component with props mapping
27
- - Use inline styles (no CSS imports)
28
- - Handle Wix Editor environment when using Wix Data API
25
+ - Extend `HTMLElement` and export the class as the default export.
26
+ - Declare every reactive attribute in a static `observedAttributes` getter that returns an array of **kebab-case** strings (HTML attributes don't preserve camelCase).
27
+ - Initialize and start side effects (timers, listeners, fetches) in `connectedCallback`. Tear them down in `disconnectedCallback` to avoid leaks when the widget is unmounted in the Editor.
28
+ - Re-render in `attributeChangedCallback` when a watched attribute changes.
29
+ - Read attribute values with `this.getAttribute('attr-name')` and provide sensible defaults — attributes may be missing on first paint.
30
+ - Render output via `this.innerHTML = \`...\`` (template strings) or imperative DOM, not JSX.
31
+ - Pull design tokens from the generated `<name>.module.css` (e.g., apply the `.root` class) rather than hard-coding colors inline; the settings panel is the place for user-controlled colors.
29
32
 
30
- ### 2. Settings Panel (`panel.tsx`)
33
+ ## Settings Panel (`<name>.panel.tsx`)
31
34
 
32
- Settings panel shown in the Wix Editor sidebar:
35
+ React component shown in the Wix Editor sidebar.
33
36
 
34
- - Uses Wix Design System components (see [SETTINGS_PANEL.md](custom-element-widget/SETTINGS_PANEL.md))
35
- - Manages widget properties via `@wix/editor` widget API
36
- - Loads initial values with `widget.getProp('kebab-case-name')`
37
- - Updates properties with `widget.setProp('kebab-case-name', value)`
38
- - Wrapped in `WixDesignSystemProvider > SidePanel > SidePanel.Content`
39
- - For color pickers, use `inputs.selectColor()` from `@wix/editor` with `FillPreview` — NOT `<Input type="color">`
40
- - For font pickers, use `inputs.selectFont()` from `@wix/editor` with a `Button` — NOT a text Input
37
+ - Uses Wix Design System components (see [SETTINGS_PANEL.md](custom-element-widget/SETTINGS_PANEL.md)).
38
+ - Manages widget properties via the `@wix/editor` `widget` API.
39
+ - Loads initial values with `widget.getProp('kebab-case-name')`.
40
+ - Updates properties with `widget.setProp('kebab-case-name', value)`. Always update both local React state AND the widget prop in onChange handlers.
41
+ - Wrapped in `WixDesignSystemProvider > SidePanel > SidePanel.Content`.
42
+ - For color pickers, use `inputs.selectColor()` from `@wix/editor` with `FillPreview` — NOT `<Input type="color">`.
43
+ - For font pickers, use `inputs.selectFont()` from `@wix/editor` with a `Button` — NOT a text Input.
41
44
 
42
- ## Widget Component Pattern
45
+ ## Builder file (`<name>.extension.ts`)
43
46
 
44
- ```typescript
45
- import React, { type FC, useState, useEffect } from 'react';
46
- import ReactDOM from 'react-dom';
47
- import reactToWebComponent from 'react-to-webcomponent';
48
-
49
- interface WidgetProps {
50
- title?: string;
51
- targetDate?: string;
52
- targetTime?: string;
53
- bgColor?: string;
54
- textColor?: string;
55
- font?: string;
56
- }
57
-
58
- const CustomElement: FC<WidgetProps> = ({
59
- title = 'Countdown',
60
- targetDate = '',
61
- targetTime = '00:00',
62
- bgColor = '#ffffff',
63
- textColor = '#333333',
64
- font = "{}",
65
- }) => {
66
- const { font: textFont, textDecoration } = JSON.parse(font);
67
- const [time, setTime] = useState({ days: 0, hours: 0, minutes: 0, seconds: 0, isExpired: false });
68
-
69
- useEffect(() => {
70
- if (!targetDate) return;
71
-
72
- const update = () => {
73
- const target = new Date(`${targetDate}T${targetTime}`);
74
- const diff = target.getTime() - Date.now();
75
- if (diff <= 0) {
76
- setTime({ days: 0, hours: 0, minutes: 0, seconds: 0, isExpired: true });
77
- return;
78
- }
79
- setTime({
80
- days: Math.floor(diff / (1000 * 60 * 60 * 24)),
81
- hours: Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)),
82
- minutes: Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)),
83
- seconds: Math.floor((diff % (1000 * 60)) / 1000),
84
- isExpired: false,
85
- });
86
- };
87
-
88
- update();
89
- const interval = setInterval(update, 1000);
90
- return () => clearInterval(interval);
91
- }, [targetDate, targetTime]);
92
-
93
- const styles = {
94
- wrapper: {
95
- backgroundColor: bgColor,
96
- padding: '24px 32px',
97
- textAlign: 'center' as const,
98
- display: 'inline-block',
99
- },
100
- title: {
101
- font: textFont || '600 24px sans-serif',
102
- color: textColor,
103
- textDecoration,
104
- marginBottom: '16px',
105
- },
106
- };
107
-
108
- return (
109
- <div style={styles.wrapper}>
110
- {title && <div style={styles.title}>{title}</div>}
111
- {/* Widget content */}
112
- </div>
113
- );
114
- };
115
-
116
- const customElement = reactToWebComponent(CustomElement, React, ReactDOM, {
117
- props: {
118
- title: 'string',
119
- targetDate: 'string',
120
- targetTime: 'string',
121
- bgColor: 'string',
122
- textColor: 'string',
123
- font: 'string',
124
- },
125
- });
126
-
127
- export default customElement;
128
- ```
129
-
130
- **Key Points:**
131
-
132
- - Props interface uses **camelCase** (e.g., `targetDate`, `bgColor`)
133
- - `reactToWebComponent` config uses camelCase keys with `'string'` type
134
- - All props are passed as strings from the web component
135
- - Use inline styles, not CSS imports. Do NOT put functions in styles objects (causes TS2560/TS2349). For conditional styles, use ternary expressions directly in the `style` prop: `style={{ ...styles.itemBase, color: item.done ? '#999' : '#000' }}`
136
- - Parse complex props (like `font`) from JSON strings: `const { font: textFont, textDecoration } = JSON.parse(font)`
137
- - Apply font via `font` CSS shorthand and `textDecoration` property
138
- - Extract helper components, utility functions, and styles into separate files for clean code organization
139
-
140
- ## Settings Panel Pattern
141
-
142
- ```typescript
143
- import React, { type FC, useState, useEffect, useCallback } from "react";
144
- import { widget } from "@wix/editor";
145
- import {
146
- SidePanel,
147
- WixDesignSystemProvider,
148
- Input,
149
- FormField,
150
- TimeInput,
151
- Box,
152
- } from "@wix/design-system";
153
- import "@wix/design-system/styles.global.css";
154
- import { ColorPickerField } from "./components/ColorPickerField";
155
- import { FontPickerField } from "./components/FontPickerField";
156
- import { parseTimeValue } from "./utils";
157
-
158
- const DEFAULT_BG_COLOR = "#0a0e27";
159
- const DEFAULT_TEXT_COLOR = "#00ff88";
160
- const DEFAULT_TEXT_FONT = "";
161
- const DEFAULT_TEXT_DECORATION = "";
162
-
163
- const Panel: FC = () => {
164
- const [title, setTitle] = useState<string>("Countdown");
165
- const [targetDate, setTargetDate] = useState<string>("");
166
- const [targetTime, setTargetTime] = useState<string>("00:00");
167
- const [bgColor, setBgColor] = useState<string>(DEFAULT_BG_COLOR);
168
- const [textColor, setTextColor] = useState<string>(DEFAULT_TEXT_COLOR);
169
- const [font, setFont] = useState({ font: DEFAULT_TEXT_FONT, textDecoration: DEFAULT_TEXT_DECORATION });
170
-
171
- useEffect(() => {
172
- Promise.all([
173
- widget.getProp("title"),
174
- widget.getProp("target-date"),
175
- widget.getProp("target-time"),
176
- widget.getProp("bg-color"),
177
- widget.getProp("text-color"),
178
- widget.getProp("font"),
179
- ])
180
- .then(([titleVal, dateVal, timeVal, bgColorVal, textColorVal, fontString]) => {
181
- setTitle(titleVal || "Countdown");
182
- setTargetDate(dateVal || "");
183
- setTargetTime(timeVal || "00:00");
184
- setBgColor(bgColorVal || DEFAULT_BG_COLOR);
185
- setTextColor(textColorVal || DEFAULT_TEXT_COLOR);
186
- setFont(JSON.parse(fontString || "{}"));
187
- })
188
- .catch((error) => console.error("Failed to fetch widget properties:", error));
189
- }, []);
190
-
191
- const handleTitleChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
192
- const newTitle = event.target.value;
193
- setTitle(newTitle);
194
- widget.setProp("title", newTitle);
195
- }, []);
196
-
197
- const handleDateChange = useCallback((event: React.ChangeEvent<HTMLInputElement>) => {
198
- const newDate = event.target.value;
199
- setTargetDate(newDate);
200
- widget.setProp("target-date", newDate);
201
- }, []);
202
-
203
- const handleTimeChange = useCallback(({ date }: { date: Date }) => {
204
- if (date) {
205
- const hours = String(date.getHours()).padStart(2, '0');
206
- const minutes = String(date.getMinutes()).padStart(2, '0');
207
- const newTime = `${hours}:${minutes}`;
208
- setTargetTime(newTime);
209
- widget.setProp("target-time", newTime);
210
- }
211
- }, []);
212
-
213
- const handleBgColorChange = (value: string) => {
214
- setBgColor(value);
215
- widget.setProp("bg-color", value);
216
- };
217
-
218
- const handleTextColorChange = (value: string) => {
219
- setTextColor(value);
220
- widget.setProp("text-color", value);
221
- };
222
-
223
- const handleFontChange = (value: { font: string; textDecoration: string }) => {
224
- setFont(value);
225
- widget.setProp("font", JSON.stringify(value));
226
- };
227
-
228
- return (
229
- <WixDesignSystemProvider>
230
- <SidePanel width="300" height="100vh">
231
- <SidePanel.Header title="Countdown Settings" />
232
- <SidePanel.Content noPadding stretchVertically>
233
- <Box direction="vertical" gap="24px">
234
- <SidePanel.Field>
235
- <FormField label="Title" required>
236
- <Input
237
- type="text"
238
- value={title}
239
- onChange={handleTitleChange}
240
- placeholder="Enter countdown title"
241
- />
242
- </FormField>
243
- </SidePanel.Field>
244
-
245
- <SidePanel.Field>
246
- <FormField label="Target Date" required>
247
- <Input
248
- type="date"
249
- value={targetDate}
250
- onChange={handleDateChange}
251
- />
252
- </FormField>
253
- </SidePanel.Field>
254
-
255
- <SidePanel.Field>
256
- <FormField label="Target Time" required>
257
- <TimeInput
258
- value={parseTimeValue(targetTime)}
259
- onChange={handleTimeChange}
260
- />
261
- </FormField>
262
- </SidePanel.Field>
263
-
264
- <ColorPickerField
265
- label="Background Color"
266
- value={bgColor}
267
- onChange={handleBgColorChange}
268
- />
269
-
270
- <ColorPickerField
271
- label="Text Color"
272
- value={textColor}
273
- onChange={handleTextColorChange}
274
- />
275
-
276
- <FontPickerField
277
- label="Text Font"
278
- value={font}
279
- onChange={handleFontChange}
280
- />
281
- </Box>
282
- </SidePanel.Content>
283
- </SidePanel>
284
- </WixDesignSystemProvider>
285
- );
286
- };
287
-
288
- export default Panel;
289
- ```
47
+ The CLI scaffolds the builder file with sensible defaults — edit it only to customize sizing, auto-add behavior, or presets.
290
48
 
291
- **Key Points:**
49
+ | Field | Type | Default | Purpose |
50
+ |---|---|---|---|
51
+ | `id` | UUID | generated | Extension ID. Don't change after scaffolding. |
52
+ | `name` | string | from scaffold param | Display name. |
53
+ | `tagName` | kebab-case | derived from `folder` | Custom-element tag the widget is registered under. Used by the Editor and by `customElements.define()`. |
54
+ | `width.defaultWidth` | number (px) | `450` | Initial width when the widget is added to a page. |
55
+ | `width.allowStretch` | boolean | `true` | Whether the site owner can stretch the widget to the page width. |
56
+ | `height.defaultHeight` | number (px) | `250` | Initial height. |
57
+ | `installation.autoAdd` | boolean | `true` | If true, the widget is auto-added to the site when the app is installed. Set to `false` for opt-in widgets. |
58
+ | `presets` | array | one default preset | Editor presets (saved configurations) the site owner can pick from. Each preset has its own `id`, `name`, and `thumbnailUrl`. |
59
+ | `presets[].thumbnailUrl` | string | `{{BASE_URL}}/<name>-thumbnail.png` | Path to a preview image. `{{BASE_URL}}` is resolved at build time. Replace the placeholder image at the same relative path with your actual asset. |
60
+ | `element` | path | `./extensions/site/widgets/<name>/<name>.tsx` | Path to the widget custom element file. Don't change unless renaming files. |
61
+ | `settings` | path | `./extensions/site/widgets/<name>/<name>.panel.tsx` | Path to the settings panel file. Don't change unless renaming files. |
292
62
 
293
- - Prop names in `widget.getProp()` and `widget.setProp()` use **kebab-case** (e.g., `"target-date"`, `"bg-color"`)
294
- - Always update both local state AND widget prop in onChange handlers
295
- - Wrap content in `WixDesignSystemProvider > SidePanel > SidePanel.Content`
296
- - Use WDS components from `@wix/design-system` (see [SETTINGS_PANEL.md](custom-element-widget/SETTINGS_PANEL.md))
297
63
  - Import `@wix/design-system/styles.global.css` for styles
298
64
  - For colors, use `ColorPickerField` with `inputs.selectColor()` from `@wix/editor` — NOT `<Input type="color">`
299
65
  - For fonts, use `FontPickerField` with `inputs.selectFont()` from `@wix/editor` — NOT a text Input
@@ -301,76 +67,71 @@ export default Panel;
301
67
 
302
68
  ## Props Naming Convention
303
69
 
304
- **Critical:** Props use different naming conventions in each file:
70
+ All cross-boundary prop names are **kebab-case**. Both sides of the widget/panel boundary use the same string:
305
71
 
306
- | File | Convention | Example |
307
- | ------------------------------ | ---------- | --------------------------------------------- |
308
- | `widget.tsx` (Props interface) | camelCase | `targetDate`, `bgColor`, `textColor` |
309
- | `panel.tsx` (widget API) | kebab-case | `"target-date"`, `"bg-color"`, `"text-color"` |
310
- | `reactToWebComponent` config | camelCase | `targetDate: 'string'` |
311
-
312
- The web component automatically converts between camelCase (React props) and kebab-case (HTML attributes).
72
+ | Site | Convention | Example |
73
+ | ------------------------------------------------------ | ---------- | ---------------------------------- |
74
+ | `<name>.tsx` — `observedAttributes`, `getAttribute` | kebab-case | `"display-name"`, `"bg-color"` |
75
+ | `<name>.panel.tsx` — `widget.getProp` / `widget.setProp` | kebab-case | `"display-name"`, `"bg-color"` |
76
+ | Local TypeScript variables | camelCase | `displayName`, `bgColor` |
313
77
 
314
78
  ## Wix Data API Integration
315
79
 
316
- When using Wix Data API in widgets, you **must** handle the Wix Editor environment gracefully:
80
+ When using the Wix Data API in widgets, you **must** handle the Wix Editor environment gracefully — fetching data inside the Editor produces empty results and noisy errors.
317
81
 
318
82
  ```typescript
319
- import { items } from "@wix/data";
320
- import { window as wixWindow } from "@wix/site-window";
321
-
322
- const CustomElement: FC<WidgetProps> = ({ collectionId }) => {
323
- const [data, setData] = useState(null);
324
- const [isEditor, setIsEditor] = useState(false);
325
-
326
- useEffect(() => {
327
- const loadData = async () => {
328
- const currentViewMode = await wixWindow.viewMode();
329
-
330
- if (currentViewMode === "Editor") {
331
- // Don't fetch data in editor - show placeholder
332
- setIsEditor(true);
333
- return;
334
- }
335
-
336
- // Fetch real data only on live site
337
- try {
338
- const results = await items.query(collectionId).limit(10).find();
339
- setData(results.items);
340
- } catch (error) {
341
- console.error("Failed to load data:", error);
342
- }
343
- };
344
-
345
- loadData();
346
- }, [collectionId]);
347
-
348
- if (isEditor) {
349
- return (
350
- <div style={{ padding: "20px", border: "2px dashed #ccc" }}>
351
- <p>Widget will display data on the live site</p>
352
- <p>Collection: {collectionId}</p>
353
- </div>
354
- );
83
+ import { items } from '@wix/data';
84
+ import { window as wixWindow } from '@wix/site-window';
85
+
86
+ class MyWidget extends HTMLElement {
87
+ static get observedAttributes() {
88
+ return ['collection-id'];
355
89
  }
356
90
 
357
- // Render widget with real data
358
- return (
359
- <div>
360
- {data?.map((item) => (
361
- <div key={item._id}>{item.title}</div>
362
- ))}
363
- </div>
364
- );
365
- };
91
+ constructor() {
92
+ super();
93
+ }
94
+
95
+ connectedCallback() {
96
+ this.render();
97
+ }
98
+
99
+ attributeChangedCallback() {
100
+ this.render();
101
+ }
102
+
103
+ async render() {
104
+ const collectionId = this.getAttribute('collection-id') || '';
105
+ const viewMode = await wixWindow.viewMode();
106
+
107
+ if (viewMode === 'Editor') {
108
+ this.innerHTML = `
109
+ <div style="padding: 20px; border: 2px dashed #ccc">
110
+ <p>Widget will display data on the live site</p>
111
+ <p>Collection: ${collectionId}</p>
112
+ </div>
113
+ `;
114
+ return;
115
+ }
116
+
117
+ try {
118
+ const { items: results } = await items.query(collectionId).limit(10).find();
119
+ this.innerHTML = results.map((item) => `<div>${item.title}</div>`).join('');
120
+ } catch (error) {
121
+ console.error('Failed to load data:', error);
122
+ }
123
+ }
124
+ }
125
+
126
+ export default MyWidget;
366
127
  ```
367
128
 
368
129
  **Requirements:**
369
130
 
370
- - Import `{ window as wixWindow }` from `"@wix/site-window"`
371
- - Check `await wixWindow.viewMode()` before fetching data
372
- - If `viewMode === 'Editor'`, show a placeholder UI instead
373
- - Only fetch and render real data when NOT in editor mode
131
+ - Import `{ window as wixWindow }` from `'@wix/site-window'`.
132
+ - Check `await wixWindow.viewMode()` before fetching data.
133
+ - If `viewMode === 'Editor'`, render a placeholder via `this.innerHTML` instead of fetching.
134
+ - Only query and render real data when NOT in Editor mode.
374
135
 
375
136
  ## Color Selection
376
137
 
@@ -475,21 +236,6 @@ const handleFontChange = (value: FontValue) => {
475
236
 
476
237
  **Important:** Use `inputs.selectFont(value, { onChange })` from `@wix/editor` with the callback pattern. This provides a rich font picker dialog with bold, italic, size, and typography features. Font values are stored as JSON strings.
477
238
 
478
- ## Output Structure
479
-
480
- ```
481
- src/extensions/site/widgets/custom-elements/
482
- └── {widget-name}/
483
- ├── widget.tsx # Main widget component
484
- ├── panel.tsx # Settings panel component
485
- ├── extensions.ts # Extension registration
486
- ├── components/ # Optional sub-components
487
- │ ├── ColorPickerField.tsx
488
- │ └── FontPickerField.tsx
489
- └── utils/ # Optional helper functions
490
- └── formatters.ts
491
- ```
492
-
493
239
  ## Examples
494
240
 
495
241
  ### Countdown Timer Widget
@@ -528,60 +274,9 @@ src/extensions/site/widgets/custom-elements/
528
274
 
529
275
  Avoid generic aesthetics. Create distinctive designs with unique fonts (avoid Inter, Roboto, Arial), cohesive color palettes, CSS animations for micro-interactions, and context-specific choices. Don't use clichéd color schemes or predictable layouts.
530
276
 
531
- ## Extension Registration
532
-
533
- **Extension registration is MANDATORY and has TWO required steps.**
534
-
535
- ### Step 1: Create Widget-Specific Extension File
536
-
537
- Each custom element widget requires an `extensions.ts` file in its folder:
538
-
539
- ```typescript
540
- import { extensions } from "@wix/astro/builders";
541
-
542
- export const customelementwidgetMyWidget = extensions.customElement({
543
- id: "{{GENERATE_UUID}}",
544
- name: "My Widget",
545
- tagName: "my-widget",
546
- element: "./extensions/site/widgets/custom-elements/my-widget/widget.tsx",
547
- settings: "./extensions/site/widgets/custom-elements/my-widget/panel.tsx",
548
- installation: {
549
- autoAdd: true,
550
- },
551
- width: {
552
- defaultWidth: 500,
553
- allowStretch: true,
554
- },
555
- height: {
556
- defaultHeight: 500,
557
- },
558
- });
559
- ```
560
-
561
- **CRITICAL: UUID Generation**
562
-
563
- The `id` must be a unique, static UUID v4 string. Generate a fresh UUID for each extension - do NOT use `randomUUID()` or copy UUIDs from examples. Replace `{{GENERATE_UUID}}` with a freshly generated UUID like `"a1b2c3d4-e5f6-7890-abcd-ef1234567890"`.
564
-
565
- | Property | Type | Description |
566
- | -------------- | ------ | -------------------------------------- |
567
- | `id` | string | Unique static UUID v4 (generate fresh) |
568
- | `name` | string | Display name in editor |
569
- | `tagName` | string | HTML custom element tag (kebab-case) |
570
- | `element` | string | Path to widget React component |
571
- | `settings` | string | Path to settings panel component |
572
- | `installation` | object | Auto-add behavior |
573
- | `width` | object | Default width and stretch settings |
574
- | `height` | object | Default height settings |
575
-
576
- ### Step 2: Register in Main Extensions File
577
-
578
- **CRITICAL:** After creating the widget-specific extension file, you MUST read [Extension Registration reference](EXTENSION_REGISTRATION.md) and follow the "App Registration" section to update `src/extensions.ts`.
579
-
580
- **Without completing Step 2, the custom element widget will not be available in the Wix Editor.**
581
-
582
277
  ## Custom-element-specific Conventions
583
278
 
584
- - Functional React components with hooks.
585
- - Inline styles only (no CSS imports).
586
- - Handle Wix Editor environment when using Wix Data API.
587
- - Consistent prop naming (camelCase in widget, kebab-case in panel).
279
+ - Widget (`<name>.tsx`) extends `HTMLElement` and renders via `this.innerHTML`; the settings panel (`<name>.panel.tsx`) is a functional React component with hooks.
280
+ - Style via the generated `<name>.module.css` (preferred) or inline styles. Don't import other global CSS.
281
+ - Handle the Wix Editor environment when using the Wix Data API.
282
+ - Cross-boundary prop names are kebab-case on both sides (`observedAttributes`, `getAttribute`, `getProp`, `setProp`).