@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.
- package/README.md +5 -9
- package/package.json +1 -1
- package/skills/wix-app/SKILL.md +51 -42
- package/skills/wix-app/references/BACKEND_EVENT.md +10 -65
- package/skills/wix-app/references/CUSTOM_ELEMENT_WIDGET.md +101 -406
- package/skills/wix-app/references/DASHBOARD_MENU_PLUGIN.md +14 -111
- package/skills/wix-app/references/DASHBOARD_MODAL.md +56 -205
- package/skills/wix-app/references/DASHBOARD_PAGE.md +19 -98
- package/skills/wix-app/references/DASHBOARD_PLUGIN.md +6 -108
- package/skills/wix-app/references/DATA_COLLECTION.md +113 -198
- package/skills/wix-app/references/EMBEDDED_SCRIPT.md +41 -268
- package/skills/wix-app/references/EXTENSION_REGISTRATION.md +27 -76
- package/skills/wix-app/references/SERVICE_PLUGIN.md +35 -188
- package/skills/wix-app/references/SITE_PLUGIN.md +8 -92
- package/skills/wix-app/references/STORES_VERSIONING.md +1 -0
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +0 -44
- package/skills/wix-app/references/custom-element-widget/SETTINGS_PANEL.md +19 -330
- package/skills/wix-app/references/dashboard-menu-plugin/bookings-slots.md +0 -12
- package/skills/wix-app/references/dashboard-menu-plugin/ecommerce-slots.md +7 -0
- package/skills/wix-app/references/dashboard-menu-plugin/restaurants-slots.md +0 -12
- package/skills/wix-app/references/dashboard-plugin/SLOTS.md +3 -15
- package/skills/wix-app/references/service-plugin/ADDITIONAL-FEES.md +2 -18
- package/skills/wix-app/references/service-plugin/BOOKINGS-STAFF-SORTING.md +2 -42
- package/skills/wix-app/references/service-plugin/DISCOUNT-TRIGGERS.md +1 -11
- package/skills/wix-app/references/service-plugin/GIFT-CARDS.md +1 -11
- package/skills/wix-app/references/service-plugin/PAYMENT-SETTINGS.md +2 -40
- package/skills/wix-app/references/service-plugin/SHIPPING-RATES.md +2 -19
- package/skills/wix-app/references/service-plugin/VALIDATIONS.md +2 -18
- package/skills/wix-app/references/site-plugin/SLOTS.md +17 -68
- package/skills/wix-design-system/SKILL.md +4 -0
- package/skills/wix-headless/SKILL.md +131 -386
- package/skills/wix-headless/references/BUILD-astro.md +246 -0
- package/skills/wix-headless/references/BUILD-own-build.md +167 -0
- package/skills/wix-headless/references/BUILD.md +105 -0
- package/skills/wix-headless/references/DESIGN_SYSTEM.md +175 -0
- package/skills/wix-headless/references/DISCOVERY-connect.md +55 -0
- package/skills/wix-headless/references/DISCOVERY-create.md +238 -0
- package/skills/wix-headless/references/DISCOVERY.md +50 -306
- package/skills/wix-headless/references/PLAN-connect.md +19 -0
- package/skills/wix-headless/references/PLAN-create.md +17 -0
- package/skills/wix-headless/references/PLAN.md +92 -0
- package/skills/wix-headless/references/SEED.md +214 -0
- package/skills/wix-headless/references/SETUP.md +73 -248
- package/skills/wix-headless/references/{blog → astro/blog}/BLOG_PAGES.md +6 -5
- package/skills/wix-headless/references/{blog → astro/blog}/BLOG_SETUP.md +2 -2
- package/skills/wix-headless/references/astro/bookings/COMPONENTS.md +337 -0
- package/skills/wix-headless/references/astro/bookings/SERVICES_PAGES.md +428 -0
- package/skills/wix-headless/references/astro/cms/CMS_FOUNDATIONS.md +214 -0
- package/skills/wix-headless/references/{cms → astro/cms}/FAQ_KNOWLEDGE_BASE.md +14 -12
- package/skills/wix-headless/references/{cms → astro/cms}/PORTFOLIO.md +15 -16
- package/skills/wix-headless/references/{cms → astro/cms}/RESOURCE_LIBRARY.md +13 -15
- package/skills/wix-headless/references/{cms → astro/cms}/TEAM_DIRECTORY.md +11 -11
- package/skills/wix-headless/references/astro/designer/INSTRUCTIONS.md +354 -0
- package/skills/wix-headless/references/{ecom → astro/ecom}/CART_PAGES.md +8 -9
- package/skills/wix-headless/references/{ecom → astro/ecom}/CART_WIRING.md +6 -6
- package/skills/wix-headless/references/{ecom → astro/ecom}/COMPONENTS_CSS.md +6 -6
- package/skills/wix-headless/references/{forms → astro/forms}/CONTACT_FORM.md +18 -32
- package/skills/wix-headless/references/{gift-cards → astro/gift-cards}/COMPONENTS.md +3 -3
- package/skills/wix-headless/references/{gift-cards → astro/gift-cards}/PAGES.md +2 -2
- package/skills/wix-headless/references/{stores → astro/stores}/BACK_IN_STOCK.md +7 -7
- package/skills/wix-headless/references/{stores → astro/stores}/CATEGORY_PAGES.md +12 -13
- package/skills/wix-headless/references/{stores → astro/stores}/COMPONENTS_CSS.md +7 -7
- package/skills/wix-headless/references/{stores → astro/stores}/HOME_AND_NAV.md +11 -9
- package/skills/wix-headless/references/{stores → astro/stores}/PRODUCT_PAGES.md +11 -9
- package/skills/wix-headless/references/{stores → astro/stores}/SHARED_WIRING.md +8 -7
- package/skills/wix-headless/references/astro/templates/Footer.astro +27 -0
- package/skills/wix-headless/references/astro/templates/Layout.astro +132 -0
- package/skills/wix-headless/references/astro/templates/Navigation.astro +38 -0
- package/skills/wix-headless/references/astro/templates/astro.config.mjs +41 -0
- package/skills/wix-headless/references/astro/templates/bookings/AvailabilityCalendar.tsx +218 -0
- package/skills/wix-headless/references/astro/templates/bookings/BookingForm.tsx +194 -0
- package/skills/wix-headless/references/astro/templates/bookings/ManageBooking.tsx +84 -0
- package/skills/wix-headless/references/astro/templates/bookings/SeoTags.astro +25 -0
- package/skills/wix-headless/references/astro/templates/bookings/ServiceBookingFlow.tsx +50 -0
- package/skills/wix-headless/references/astro/templates/bookings/ServiceCard.astro +45 -0
- package/skills/wix-headless/references/astro/templates/bookings/api/confirm-booking.ts +34 -0
- package/skills/wix-headless/references/astro/templates/bookings/api/waitlist.ts +74 -0
- package/skills/wix-headless/references/astro/templates/bookings/booking-confirmation.astro +111 -0
- package/skills/wix-headless/references/astro/templates/bookings/components-bookings.css +413 -0
- package/skills/wix-headless/references/astro/templates/bookings/manage-booking.astro +76 -0
- package/skills/wix-headless/references/astro/templates/bookings/services/[slug].astro +81 -0
- package/skills/wix-headless/references/astro/templates/bookings/services/index.astro +65 -0
- package/skills/wix-headless/references/astro/templates/ecom/components-ecom.css +302 -0
- package/skills/wix-headless/references/astro/templates/global.css +286 -0
- package/skills/wix-headless/references/astro/templates/index.astro +56 -0
- package/skills/wix-headless/{templates → references/astro/templates}/stores/back-in-stock.ts +1 -1
- package/skills/wix-headless/{templates → references/astro/templates}/stores/components-stores.css +138 -33
- package/skills/wix-headless/references/blog/BLOG_CONTENT.md +28 -19
- package/skills/wix-headless/references/blog/INSTRUCTIONS.md +6 -6
- package/skills/wix-headless/references/bookings/INSTRUCTIONS.md +106 -0
- package/skills/wix-headless/references/bookings/SERVICES_DATA.md +295 -0
- package/skills/wix-headless/references/cms/CMS_FOUNDATIONS.md +35 -232
- package/skills/wix-headless/references/cms/INSTRUCTIONS.md +39 -8
- package/skills/wix-headless/references/commands/known-apps.json +2 -1
- package/skills/wix-headless/references/custom/CONNECTION_PLAN.md +142 -0
- package/skills/wix-headless/references/custom/INSTRUCTIONS.md +88 -0
- package/skills/wix-headless/references/custom/blog/WIRING.md +52 -0
- package/skills/wix-headless/references/custom/bookings/WIRING.md +88 -0
- package/skills/wix-headless/references/custom/cms/WIRING.md +97 -0
- package/skills/wix-headless/references/custom/ecom/WIRING.md +67 -0
- package/skills/wix-headless/references/custom/forms/WIRING.md +101 -0
- package/skills/wix-headless/references/custom/stores/WIRING.md +80 -0
- package/skills/wix-headless/references/ecom/INSTRUCTIONS.md +12 -12
- package/skills/wix-headless/references/forms/INSTRUCTIONS.md +6 -6
- package/skills/wix-headless/references/gift-cards/INSTRUCTIONS.md +13 -13
- package/skills/wix-headless/references/images/INSTRUCTIONS.md +58 -60
- package/skills/wix-headless/references/seed-recipes.md +49 -0
- package/skills/wix-headless/references/shared/AGENTS_MD.md +47 -0
- package/skills/wix-headless/references/shared/AUTHENTICATION.md +108 -0
- package/skills/wix-headless/references/shared/BUILD_NOISE.md +2 -2
- package/skills/wix-headless/references/shared/DESIGN_MD.md +85 -0
- package/skills/wix-headless/references/shared/DOCS_SEARCH.md +41 -0
- package/skills/wix-headless/references/shared/IMAGE_GENERATION.md +40 -39
- package/skills/wix-headless/references/shared/IMPLEMENTER.md +92 -41
- package/skills/wix-headless/references/shared/PRODUCTION_SHARP_EDGES.md +3 -3
- package/skills/wix-headless/references/shared/RETURN_CONTRACT.md +32 -312
- package/skills/wix-headless/references/shared/STYLING.md +48 -21
- package/skills/wix-headless/references/stores/INSTRUCTIONS.md +59 -29
- package/skills/wix-headless/references/stores/PRODUCT_CATALOG_DATA.md +31 -28
- package/skills/wix-headless/references/verticals/_schema.json +31 -117
- package/skills/wix-headless/references/verticals/_schema.md +60 -150
- package/skills/wix-headless/references/verticals/blog.md +5 -99
- package/skills/wix-headless/references/verticals/bookings.md +41 -0
- package/skills/wix-headless/references/verticals/cms.md +9 -100
- package/skills/wix-headless/references/verticals/ecom.md +6 -77
- package/skills/wix-headless/references/verticals/forms.md +5 -85
- package/skills/wix-headless/references/verticals/gift-cards.md +6 -103
- package/skills/wix-headless/references/verticals/stores.md +10 -144
- package/skills/wix-headless/scripts/check-manifest.mjs +148 -11
- package/skills/wix-headless/scripts/compose.mjs +540 -0
- package/skills/wix-headless/scripts/emit-design-tokens.mjs +136 -53
- package/skills/wix-headless/scripts/flatten.sh +61 -0
- package/skills/wix-headless/scripts/generate-images.mjs +242 -0
- package/skills/wix-headless/scripts/patch-decorative-slots.mjs +67 -43
- package/skills/wix-headless/scripts/plan-entity-image-waves.mjs +3 -3
- package/skills/wix-headless/scripts/scaffold.sh +113 -27
- package/skills/wix-headless/scripts/seed-utilities.sh +50 -12
- package/skills/wix-headless/scripts/write-decorative-json.mjs +62 -0
- package/skills/wix-manage/SKILL.md +4 -8
- package/skills/wix-manage/references/blog/how-to-create-blog-posts.md +2 -0
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +4 -0
- package/skills/wix-manage/references/cms/cms-references-and-relationships.md +2 -0
- package/skills/wix-manage/references/cms/cms-schema-management.md +4 -0
- package/skills/wix-manage/references/domains/domain-search-and-purchase.md +10 -7
- package/skills/wix-manage/references/ecommerce/api-shipping.md +443 -0
- package/skills/wix-manage/references/ecommerce/flow-add-free-shipping.md +5 -6
- package/skills/wix-manage/references/ecommerce/flow-fix-coverage-gaps.md +4 -5
- package/skills/wix-manage/references/ecommerce/flow-optimize-shipping-rates.md +4 -5
- package/skills/wix-manage/references/ecommerce/goal-increase-aov.md +1 -1
- package/skills/wix-manage/references/ecommerce/goal-reduce-cart-abandonment.md +1 -2
- package/skills/wix-manage/references/ecommerce/guardrail-shipping-health.md +2 -2
- package/skills/wix-manage/references/ecommerce/recipe-apply-shipping-recommendations.md +4 -5
- package/skills/wix-manage/references/ecommerce/recommend-ecommerce-strategy.md +7 -7
- package/skills/wix-manage/references/ecommerce/setup-discount-rules.md +209 -72
- package/skills/wix-manage/references/ecommerce/setup-store-pickup-location.md +9 -10
- package/skills/wix-manage/references/ecommerce/skill-graph.md +4 -4
- package/skills/wix-manage/references/forms/create-form.md +50 -0
- package/skills/wix-manage/references/stores/bulk-create-products-with-options.md +2 -0
- package/skills/wix-manage/references/stores/create-product-from-image.md +91 -38
- package/skills/wix-manage/references/stores/setup-online-store-catalog-v3.md +2 -0
- package/skills/wix-app/references/custom-element-widget/default-thumbnail.png +0 -0
- package/skills/wix-app/references/data-collection/extension-template.ts +0 -107
- package/skills/wix-headless/references/ORCHESTRATION.md +0 -269
- package/skills/wix-headless/references/commands/install-app.md +0 -42
- package/skills/wix-headless/references/commands/mcp-bootstrap.md +0 -28
- package/skills/wix-headless/references/designer/INSTRUCTIONS.md +0 -828
- package/skills/wix-headless/references/shared/MCP_PREFIX.md +0 -105
- package/skills/wix-headless/scripts/copy-utility-templates.mjs +0 -153
- package/skills/wix-headless/scripts/finalize-run-json.mjs +0 -141
- package/skills/wix-headless/scripts/init-site-json.mjs +0 -63
- package/skills/wix-headless/scripts/preview.sh +0 -45
- package/skills/wix-headless/scripts/release.sh +0 -73
- package/skills/wix-headless/templates/ecom/components-ecom.css +0 -215
- package/skills/wix-manage/references/events/list-events.md +0 -203
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/CartBadge.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/CartView.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/cart.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/discounts.ts +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/ecom/thank-you.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/GiftCardPurchase.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/_home-teaser-snippet.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/_nav-snippet.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/components-gift-cards.css +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/gift-cards.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/gift-cards/gift-cards.ts +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/AddToCartButton.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/BackInStockForm.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/CategoryRail.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/ProductCard.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/ProductPurchase.tsx +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/SeoTags.astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/categories.ts +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/category/[slug].astro +0 -0
- /package/skills/wix-headless/{templates → references/astro/templates}/stores/products/[slug].astro +0 -0
- /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
|
-
|
|
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
|
-
##
|
|
6
|
+
## Scaffold
|
|
7
7
|
|
|
8
|
-
|
|
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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
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
|
-
|
|
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
|
-
|
|
19
|
+
## Widget Component (`<name>.tsx`)
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
Wix calls `customElements.define()` for you using the builder's `tagName`; do NOT call it in your code.
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
Key authoring rules:
|
|
23
24
|
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
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
|
-
|
|
33
|
+
## Settings Panel (`<name>.panel.tsx`)
|
|
31
34
|
|
|
32
|
-
|
|
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
|
-
##
|
|
45
|
+
## Builder file (`<name>.extension.ts`)
|
|
43
46
|
|
|
44
|
-
|
|
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
|
-
|
|
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
|
-
**
|
|
70
|
+
All cross-boundary prop names are **kebab-case**. Both sides of the widget/panel boundary use the same string:
|
|
305
71
|
|
|
306
|
-
|
|
|
307
|
-
|
|
|
308
|
-
|
|
|
309
|
-
|
|
|
310
|
-
|
|
|
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
|
|
320
|
-
import { window as wixWindow } from
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
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 `
|
|
371
|
-
- Check `await wixWindow.viewMode()` before fetching data
|
|
372
|
-
- If `viewMode === 'Editor'`,
|
|
373
|
-
- Only
|
|
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
|
-
-
|
|
585
|
-
-
|
|
586
|
-
- Handle Wix Editor environment when using Wix Data API.
|
|
587
|
-
-
|
|
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`).
|