@wix/agent-skills 1.16.3 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +134 -127
- package/skills/wix-app/references/SITE_PLUGIN.md +2 -2
- package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
- package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
- package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +92 -48
- package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +15 -6
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
- package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +29 -42
- package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +153 -449
- package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +53 -29
- package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
- package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
- package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
- package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +11 -3
- package/skills/wix-app/references/editor-react-component/PARTS.md +46 -24
- package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
- package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
- package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
- package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
- package/skills/wix-base44-connector/SKILL.md +34 -17
- package/skills/wix-base44-connector/scripts/utils.js +33 -25
- package/skills/wix-headless/entry/bootstrap.mjs +9 -2
- package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
- package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +42 -23
- package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
- package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
- package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
- package/skills/wix-manage/SKILL.md +11 -1
- package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
- package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
- package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
- package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
- package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
- package/skills/wix-manage/references/sites/query-sites.md +72 -161
- package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
- package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +13 -9
- package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +10 -7
- package/skills/wix-vibe-headless/platforms/base44.md +13 -10
- package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +2 -0
- package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
- package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
- package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
- package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
- package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
- package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +15 -8
- package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
- package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
- package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
- package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
- package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -516
- package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
- package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
- package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
|
@@ -7,20 +7,22 @@ import { wixApiRequest } from "./wix-client.js";
|
|
|
7
7
|
const STORES_APP_ID = "215238eb-22a5-4c36-9e7b-e7c08025e04e";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Wix eCom Cart — key fields for building a cart UI.
|
|
10
|
+
* Wix eCom Cart V2 — key fields for building a cart UI.
|
|
11
11
|
* Full model: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/get-current-cart.md
|
|
12
12
|
*
|
|
13
|
-
* id {string}
|
|
13
|
+
* id {string} — the cart id IS the checkout id (currency lives under businessInfo.currencyCode / customerInfo.currencyCode, not at the cart root),
|
|
14
14
|
* lineItems[].id {string} — lineItemId for update/remove (NOT catalogItemId),
|
|
15
|
-
* lineItems[].
|
|
16
|
-
* lineItems[].catalogReference.catalogItemId {string},
|
|
17
|
-
* lineItems[].
|
|
18
|
-
* lineItems[].
|
|
19
|
-
* lineItems[].
|
|
20
|
-
*
|
|
15
|
+
* lineItems[].quantityInfo.confirmedQuantity {number},
|
|
16
|
+
* lineItems[].source.catalogReference.catalogItemId {string} — NOT top-level in V2,
|
|
17
|
+
* lineItems[].name.original {string},
|
|
18
|
+
* lineItems[].pricing.unitPrice {ConvertedMoney} — per-unit price after discounts,
|
|
19
|
+
* lineItems[].pricing.totalPrice {ConvertedMoney} — line total after discounts,
|
|
20
|
+
* ConvertedMoney is { amount, convertedAmount } with NO formatted string — `amount` is in the
|
|
21
|
+
* site currency, `convertedAmount` in the display currency; format the number client-side.
|
|
22
|
+
* lineItems[].attributes.descriptionLines {array} — human-readable option/modifier labels:
|
|
21
23
|
* [{ name: { original }, plainText: { original } OR colorInfo: { original, code } }],
|
|
22
|
-
* lineItems[].image
|
|
23
|
-
* lineItems[].
|
|
24
|
+
* lineItems[].attributes.image {object} — { id, url, height, width, altText } (use .url),
|
|
25
|
+
* lineItems[].status {string} — "IN_STOCK"|"PARTIALLY_IN_STOCK"|"OUT_OF_STOCK"|"REMOVED_FROM_CATALOG"
|
|
24
26
|
*/
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -52,20 +54,22 @@ export async function addToCart(catalogItemId, variantId, quantity = 1, { modifi
|
|
|
52
54
|
|
|
53
55
|
const catalogReference = { appId: STORES_APP_ID, catalogItemId };
|
|
54
56
|
if (Object.keys(catalogReferenceOptions).length) catalogReference.options = catalogReferenceOptions;
|
|
55
|
-
const res = await wixApiRequest("/ecom/
|
|
57
|
+
const res = await wixApiRequest("/ecom/v2/carts/current/add-line-items", {
|
|
56
58
|
method: "POST",
|
|
57
|
-
body: {
|
|
59
|
+
body: { catalogItems: [{ catalogReference, quantity }] },
|
|
58
60
|
});
|
|
61
|
+
// V2 nests the reference under `source` — a top-level lineItem.catalogReference no longer exists.
|
|
59
62
|
const line = (res?.cart?.lineItems ?? []).find(
|
|
60
|
-
(l) => l.catalogReference?.catalogItemId === catalogItemId && (!variantId || l.catalogReference?.options?.variantId === variantId),
|
|
63
|
+
(l) => l.source?.catalogReference?.catalogItemId === catalogItemId && (!variantId || l.source?.catalogReference?.options?.variantId === variantId),
|
|
61
64
|
);
|
|
62
|
-
//
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
// Cart V2 rejects an unbuyable line with an explicit error rather than silently dropping it, but
|
|
66
|
+
// guard both signals defensively:
|
|
67
|
+
// 1. status set to something other than IN_STOCK
|
|
68
|
+
// 2. no matching line at all (confirmed quantity 0 / line absent)
|
|
69
|
+
if (line?.status && line.status !== "IN_STOCK") {
|
|
70
|
+
throw new Error(`Item not available for sale (status: ${line.status}). Is it in stock?`);
|
|
67
71
|
}
|
|
68
|
-
if (!line || line.
|
|
72
|
+
if (!line || line.quantityInfo?.confirmedQuantity === 0) {
|
|
69
73
|
// A missing line usually means a required selection wasn't sent — a mandatory modifier
|
|
70
74
|
// (pass modifierChoices/customTextFields) or the variantId for a product with options —
|
|
71
75
|
// not necessarily out of stock. Verify every required choice is included in this call.
|
|
@@ -81,7 +85,7 @@ export async function addToCart(catalogItemId, variantId, quantity = 1, { modifi
|
|
|
81
85
|
/** Read the visitor's current cart. Returns null if no cart exists yet. */
|
|
82
86
|
export async function getCurrentCart() {
|
|
83
87
|
try {
|
|
84
|
-
const res = await wixApiRequest("/ecom/
|
|
88
|
+
const res = await wixApiRequest("/ecom/v2/carts/current", { method: "GET" });
|
|
85
89
|
return res?.cart ?? null;
|
|
86
90
|
} catch {
|
|
87
91
|
return null;
|
|
@@ -89,7 +93,9 @@ export async function getCurrentCart() {
|
|
|
89
93
|
}
|
|
90
94
|
|
|
91
95
|
/**
|
|
92
|
-
*
|
|
96
|
+
* Start the hosted checkout for the current cart and return its URL.
|
|
97
|
+
* In Cart V2 the cart id IS the checkout id — there is no separate checkout-creation call; the
|
|
98
|
+
* redirect session is created straight from the current cart's id.
|
|
93
99
|
* Throws on empty cart, unavailable lines, or a missing redirect URL.
|
|
94
100
|
* Usage: window.location.href = await checkout()
|
|
95
101
|
* @returns {Promise<string>}
|
|
@@ -98,22 +104,16 @@ export async function checkout() {
|
|
|
98
104
|
const cart = await getCurrentCart();
|
|
99
105
|
const lines = cart?.lineItems ?? [];
|
|
100
106
|
if (!lines.length) throw new Error("Cannot check out: the cart is empty.");
|
|
101
|
-
const unavailable = lines.filter((l) => l.
|
|
107
|
+
const unavailable = lines.filter((l) => l.status && l.status !== "IN_STOCK");
|
|
102
108
|
if (unavailable.length) {
|
|
103
|
-
const names = unavailable.map((l) => l.
|
|
109
|
+
const names = unavailable.map((l) => l.name?.original ?? l.source?.catalogReference?.catalogItemId).join(", ");
|
|
104
110
|
throw new Error(`Cannot check out: ${unavailable.length} item(s) not available — ${names}.`);
|
|
105
111
|
}
|
|
106
|
-
|
|
107
|
-
const checkoutRes = await wixApiRequest("/ecom/v1/carts/current/create-checkout", {
|
|
108
|
-
method: "POST",
|
|
109
|
-
body: { channelType: "WEB" },
|
|
110
|
-
});
|
|
111
|
-
const checkoutId = checkoutRes?.checkoutId;
|
|
112
|
-
if (!checkoutId) throw new Error("Failed to create checkout from the current cart.");
|
|
112
|
+
if (!cart.id) throw new Error("Failed to check out: the current cart has no id.");
|
|
113
113
|
|
|
114
114
|
const redirect = await wixApiRequest("/headless/v1/redirect-session", {
|
|
115
115
|
method: "POST",
|
|
116
|
-
body: { ecomCheckout: { checkoutId }, callbacks: { postFlowUrl: window.location.href } },
|
|
116
|
+
body: { ecomCheckout: { checkoutId: cart.id }, callbacks: { postFlowUrl: window.location.href } },
|
|
117
117
|
});
|
|
118
118
|
const url = redirect?.redirectSession?.fullUrl;
|
|
119
119
|
if (!url) throw new Error("Failed to create the checkout redirect session.");
|
|
@@ -122,13 +122,13 @@ export async function checkout() {
|
|
|
122
122
|
|
|
123
123
|
/**
|
|
124
124
|
* Update the quantity of a cart line. lineItemId is cart.lineItems[].id, not catalogItemId.
|
|
125
|
-
*
|
|
125
|
+
* Cart V2 rejects an over-stock quantity with an explicit error rather than clamping it.
|
|
126
126
|
* @returns {Promise<object>} Updated cart.
|
|
127
127
|
*/
|
|
128
128
|
export async function updateCartItemQuantity(lineItemId, quantity) {
|
|
129
|
-
const res = await wixApiRequest("/ecom/
|
|
129
|
+
const res = await wixApiRequest("/ecom/v2/carts/current/update-line-items", {
|
|
130
130
|
method: "POST",
|
|
131
|
-
body: { lineItems: [{
|
|
131
|
+
body: { lineItems: [{ lineItemId, quantity: { newQuantity: quantity } }] },
|
|
132
132
|
});
|
|
133
133
|
return res?.cart;
|
|
134
134
|
}
|
|
@@ -139,7 +139,7 @@ export async function updateCartItemQuantity(lineItemId, quantity) {
|
|
|
139
139
|
* @returns {Promise<object>} Updated cart.
|
|
140
140
|
*/
|
|
141
141
|
export async function removeFromCart(lineItemId) {
|
|
142
|
-
const res = await wixApiRequest("/ecom/
|
|
142
|
+
const res = await wixApiRequest("/ecom/v2/carts/current/remove-line-items", {
|
|
143
143
|
method: "POST",
|
|
144
144
|
body: { lineItemIds: [lineItemId] },
|
|
145
145
|
});
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
# Editor React Component A11y Review Reference
|
|
2
|
-
|
|
3
|
-
Use this reference for decisions that require code inspection after running the scanners in [`A11Y-REVIEW.md`](A11Y-REVIEW.md). The scanner output owns rule-specific context: rule ID, location, message, resolution path, evidence, and confidence. Do not maintain a separate rule catalog here.
|
|
4
|
-
|
|
5
|
-
## Scanner Result Handling
|
|
6
|
-
|
|
7
|
-
Treat every scanner finding as a lead until the component implementation confirms how the flagged behavior reaches the rendered element.
|
|
8
|
-
|
|
9
|
-
1. Read the full finding, including evidence and confidence when present.
|
|
10
|
-
2. Trace the component topology through local wrappers, shared primitives, and package implementations.
|
|
11
|
-
3. Deduplicate findings that identify the same issue at the same location.
|
|
12
|
-
4. Assign a verdict: `confirmed`, `false-positive`, or `not-relevant`.
|
|
13
|
-
5. Fix confirmed issues inline, then re-run both scanners on changed JSX files.
|
|
14
|
-
|
|
15
|
-
When both scanners flag the same issue, keep the finding with the strongest semantic evidence. The scanners complement each other; a finding from one scanner is not automatically stronger because of its tier.
|
|
16
|
-
|
|
17
|
-
## Confidence Model
|
|
18
|
-
|
|
19
|
-
### High
|
|
20
|
-
|
|
21
|
-
Use high confidence when the code and scanner evidence unambiguously show the violation, for example:
|
|
22
|
-
|
|
23
|
-
- the flagged rendered element and static props establish the behavior directly
|
|
24
|
-
- the component implementation resolves to the flagged semantic element
|
|
25
|
-
- an explicit polymorphic prop establishes the rendered element
|
|
26
|
-
|
|
27
|
-
Fix high-confidence findings immediately.
|
|
28
|
-
|
|
29
|
-
### Medium
|
|
30
|
-
|
|
31
|
-
Use medium confidence when:
|
|
32
|
-
|
|
33
|
-
- props strongly imply the rendered semantics
|
|
34
|
-
- the implementation only partially resolves but preserves likely semantics
|
|
35
|
-
- the component name, props, and surrounding evidence strongly agree
|
|
36
|
-
|
|
37
|
-
Read the surrounding code. If it confirms the inference, fix the issue. If it contradicts the inference, discard the finding. If the implementation remains unresolved, treat it as low confidence.
|
|
38
|
-
|
|
39
|
-
### Low
|
|
40
|
-
|
|
41
|
-
Use low confidence when:
|
|
42
|
-
|
|
43
|
-
- only weak heuristics support the semantic guess
|
|
44
|
-
- the implementation cannot be resolved
|
|
45
|
-
- runtime props or spreads can materially change the rendered semantics
|
|
46
|
-
|
|
47
|
-
Continue tracing the code. Fix only after the issue is confirmed; otherwise leave the code unchanged.
|
|
48
|
-
|
|
49
|
-
### Confidence vs. Actionability
|
|
50
|
-
|
|
51
|
-
Confidence answers whether the issue is real. It does not decide whether a confirmed fix is safe.
|
|
52
|
-
|
|
53
|
-
- Confirmed + safe/local fix: fix now.
|
|
54
|
-
- Confirmed + risky behavior change or non-local refactor: leave unchanged.
|
|
55
|
-
- Unconfirmed or ambiguous: leave unchanged.
|
|
56
|
-
|
|
57
|
-
If the violation is visible in the code and has a localized, behavior-preserving fix, treat it as confirmed and apply the fix.
|
|
58
|
-
|
|
59
|
-
Valid reasons to leave code unchanged:
|
|
60
|
-
|
|
61
|
-
- semantics remain ambiguous after reading the available code
|
|
62
|
-
- product intent cannot be derived from the code
|
|
63
|
-
- the fix requires a risky behavior change or a non-local refactor
|
|
64
|
-
|
|
65
|
-
Do not leave a confirmed safe/local issue unchanged because it is low severity, secondary, shared, or outside the first file in scope.
|
|
66
|
-
|
|
67
|
-
## Semantic Resolution
|
|
68
|
-
|
|
69
|
-
Resolve the rendered behavior in this order:
|
|
70
|
-
|
|
71
|
-
1. The flagged JSX element and its static props
|
|
72
|
-
2. Explicit polymorphic props such as `as="a"` or `component="button"`
|
|
73
|
-
3. The local component implementation
|
|
74
|
-
4. Installed package source or declarations in `node_modules`
|
|
75
|
-
5. Prop evidence such as `href`, `to`, `src`, `alt`, and `role`
|
|
76
|
-
6. Component-name heuristics
|
|
77
|
-
|
|
78
|
-
For local imports, follow the exported component's rendered root. Continue through local or package components until the semantics resolve or the evidence becomes too weak.
|
|
79
|
-
|
|
80
|
-
For package imports, resolve the import from `node_modules` and inspect its exported entry point. If the package hides its rendered semantics, use prop and naming evidence without assigning more confidence than the evidence supports.
|
|
81
|
-
|
|
82
|
-
## Tier 2 Manual Review Checklist
|
|
83
|
-
|
|
84
|
-
Run this checklist after scanner findings are triaged. Tier 2 is required even when both scanners return zero findings.
|
|
85
|
-
|
|
86
|
-
### Semantic Targeting
|
|
87
|
-
|
|
88
|
-
- Do ARIA attributes land on the semantically correct element instead of a layout wrapper?
|
|
89
|
-
- Do labels, descriptions, and roles reach the actual interactive or landmark element?
|
|
90
|
-
- Do wrappers preserve the semantics exposed by their API?
|
|
91
|
-
|
|
92
|
-
### Icon-Only and Visual-Only States
|
|
93
|
-
|
|
94
|
-
- Do icon-only buttons, links, or controls have an accessible name?
|
|
95
|
-
- If visible text is hidden, is it visually hidden in an accessibility-safe way instead of removed from the accessibility tree?
|
|
96
|
-
- Do meaningful icons or images expose accessible text when needed?
|
|
97
|
-
|
|
98
|
-
### CSS and Hidden Content
|
|
99
|
-
|
|
100
|
-
- Does `display: none` remove content that should remain available to assistive technology?
|
|
101
|
-
- Are hidden or collapsed states consistent across visuals, focusability, and the accessibility tree?
|
|
102
|
-
- Do conditional classes or CSS variables create states where labels or instructions disappear from assistive technology?
|
|
103
|
-
|
|
104
|
-
### Decorative vs. Meaningful Content
|
|
105
|
-
|
|
106
|
-
- Are decorative separators, ornaments, and repeated icons hidden from assistive technology?
|
|
107
|
-
- Are meaningful visuals, status icons, or graphics named appropriately?
|
|
108
|
-
|
|
109
|
-
### Focus and Interaction Consistency
|
|
110
|
-
|
|
111
|
-
- Can hidden or collapsed items still receive focus?
|
|
112
|
-
- Do interactive-looking elements expose the correct role and keyboard behavior?
|
|
113
|
-
- Do disabled, inert, or collapsed states behave consistently for keyboard users and assistive technology?
|
|
114
|
-
- Search all in-scope files for `onClick` on elements without built-in interaction (`div`, `span`, `section`, `header`, `footer`, `li`, `td`, and similar tags). Include conditional patterns such as `{...(condition && { onClick: handler })}`. Verify that each match also has the required `role`, `tabIndex`, and keyboard handler (`onKeyDown` or `onKeyUp`). A missing combination is a high-confidence finding.
|
|
115
|
-
- Before fixing missing keyboard semantics, check for nested interactive children, existing focus management, and the condition that enables interaction. Use the [pre-fix checks](#pre-fix-checks-for-adding-button-semantics-to-a-non-interactive-element).
|
|
116
|
-
|
|
117
|
-
### Structural Semantics
|
|
118
|
-
|
|
119
|
-
- Are landmarks, headings, and list semantics preserved through wrappers and layout components?
|
|
120
|
-
- When the component implements breadcrumbs, tabs, menus, dialogs, or similar patterns, do the expected semantics reach the rendered structure?
|
|
121
|
-
|
|
122
|
-
### Editor React Component Contracts
|
|
123
|
-
|
|
124
|
-
- Are ARIA attributes routed through the typed `a11y` prop and converted at the correct element?
|
|
125
|
-
- Do icon-only labels come from `constants.ts` or user-configurable `a11y` instead of hardcoded strings?
|
|
126
|
-
- Does the component preserve direction support and isolate each `ReactNode` content prop with `dir="ltr"`?
|
|
127
|
-
- Do extension overrides preserve a11y-relevant manifest fields generated from JSX?
|
|
128
|
-
|
|
129
|
-
## Fix Principles
|
|
130
|
-
|
|
131
|
-
- Use the rule ID, message, and evidence emitted by the scanner as the rule-specific fix context.
|
|
132
|
-
- Read the surrounding code before editing.
|
|
133
|
-
- Preserve visual and runtime behavior.
|
|
134
|
-
- Prefer the smallest correct change and avoid unrelated refactors.
|
|
135
|
-
- Fix the semantic owner: the component root, the correct inner element, a shared base, or the call site that supplies the value.
|
|
136
|
-
- When a wrapper already accepts and forwards a required prop, fix the call site. When it does not, update the wrapper contract and forwarding before fixing the call site.
|
|
137
|
-
- Do not hardcode reusable accessibility values such as alternative text. Accept them through the component API when they depend on consumer content.
|
|
138
|
-
- Route Editor React Component ARIA through `a11y` and `convertA11yKeysToHtmlFormat(a11y)` according to [`ACCESSIBILITY.md`](ACCESSIBILITY.md).
|
|
139
|
-
|
|
140
|
-
## Pre-Fix Checks for Adding Button Semantics to a Non-Interactive Element
|
|
141
|
-
|
|
142
|
-
Before adding `role="button"`, `tabIndex`, and keyboard handlers to an element such as `<div>`, verify all four conditions below.
|
|
143
|
-
|
|
144
|
-
### 1. Interactive Children
|
|
145
|
-
|
|
146
|
-
Check whether the element conditionally or unconditionally contains `<a>`, `<button>`, `<input>`, `<Link>`, or a component that resolves to an interactive element. Button semantics on the parent would create nested interaction.
|
|
147
|
-
|
|
148
|
-
If interactive children are possible, either exclude that branch from the parent's interaction condition or use a separate control element.
|
|
149
|
-
|
|
150
|
-
### 2. Existing Focus Management
|
|
151
|
-
|
|
152
|
-
Check whether the element already receives `tabIndex` from another source, such as `getTabIndexAttribute`, an a11y prop spread, or an interactions framework. Determine the prop merge order and keep one source authoritative.
|
|
153
|
-
|
|
154
|
-
When an existing a11y spread should win, place the conditional interaction spread before it so `tabIndex: 0` only acts as a fallback.
|
|
155
|
-
|
|
156
|
-
### 3. Interaction Condition
|
|
157
|
-
|
|
158
|
-
Read the full boolean expression that enables interaction. Verify that it:
|
|
159
|
-
|
|
160
|
-
- excludes states that already render an interactive child
|
|
161
|
-
- excludes editor preview, externally controlled, disabled, or reduced-motion states when required
|
|
162
|
-
- uses explicit comparisons such as `=== undefined` or `=== true` when `true`, `false`, and `undefined` have different meanings
|
|
163
|
-
|
|
164
|
-
Fix a fragile condition as part of the accessibility change. Correct semantics attached to the wrong state are still incorrect behavior.
|
|
165
|
-
|
|
166
|
-
### 4. Accessible Name Scope
|
|
167
|
-
|
|
168
|
-
Decide whether an accessible label names the interaction or the component as a whole. Keep a component-level label outside the interaction condition so it persists in non-interactive states. Apply an action-specific label only while that action is available.
|
|
169
|
-
|
|
170
|
-
## After Fixing
|
|
171
|
-
|
|
172
|
-
Re-run both scanners on changed `.tsx` / `.jsx` files. Continue with `npx wix build`, `npx wix generate manifest`, and the project's TypeScript check as required by [`A11Y-REVIEW.md`](A11Y-REVIEW.md#phase-5-verify).
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
# Editor React Component A11y Review
|
|
2
|
-
|
|
3
|
-
Use this reference to audit and fix accessibility issues in an Editor React Component. This complements [`ACCESSIBILITY.md`](ACCESSIBILITY.md), which covers ARIA prop conventions and patterns, with an automated scan and triage workflow over the component's runtime, manifest extension, and shared code.
|
|
4
|
-
|
|
5
|
-
This is not a separate skill. It runs as part of the Editor React Component workflow described in [`../EDITOR_REACT_COMPONENT.md`](../EDITOR_REACT_COMPONENT.md). Run it after editing the React/CSS sources and before `npx wix build && npx wix generate manifest`.
|
|
6
|
-
|
|
7
|
-
## Scanner Invocation
|
|
8
|
-
|
|
9
|
-
Two scanners are bundled under `<SKILL_ROOT>/scripts`, where `<SKILL_ROOT>` is
|
|
10
|
-
the absolute path to the directory containing the active skill's `SKILL.md`:
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
node <SKILL_ROOT>/scripts/scan-a11y-eslint.cjs <file1> [file2] ...
|
|
14
|
-
node <SKILL_ROOT>/scripts/scan-a11y-code.cjs <file1> [file2] ...
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Replace `<SKILL_ROOT>` with that absolute path, but run the commands from the
|
|
18
|
-
consumer project root (the Wix CLI app's working directory) so dependencies
|
|
19
|
-
resolve from the project's `package.json`. Pass target paths relative to that
|
|
20
|
-
cwd. The dependency preflight is part of the workflow in
|
|
21
|
-
[`../EDITOR_REACT_COMPONENT.md`](../EDITOR_REACT_COMPONENT.md).
|
|
22
|
-
|
|
23
|
-
The ESLint scanner uses the explicitly declared `eslint-plugin-jsx-a11y` dev dependency. The semantic scanner follows imports up to four levels deep and adds resolution evidence and confidence to its findings.
|
|
24
|
-
|
|
25
|
-
## When To Run
|
|
26
|
-
|
|
27
|
-
Run the review when:
|
|
28
|
-
|
|
29
|
-
- You finished editing an Editor React Component's `.tsx` / `.module.css` files.
|
|
30
|
-
- The user asks for an a11y audit, accessibility review, or a11y fix on an Editor React Component.
|
|
31
|
-
- The user mentions missing alt text, invalid ARIA, broken semantics, direction issues, icon-only controls, or wrappers that hide accessibility issues.
|
|
32
|
-
|
|
33
|
-
Do not run on generated files (`*.generated.ts`); they are regenerated from JSX and CSS Modules.
|
|
34
|
-
|
|
35
|
-
## Target Resolution
|
|
36
|
-
|
|
37
|
-
Resolve scope before scanning:
|
|
38
|
-
|
|
39
|
-
| User says | Required scope |
|
|
40
|
-
|-----------|----------------|
|
|
41
|
-
| Specific file | That file plus any imported wrappers / shared components it renders |
|
|
42
|
-
| "this component" | `<componentName>.tsx`, `component.tsx`, `<componentName>.extension.ts`, plus shared imports |
|
|
43
|
-
| A component name | All in-component files (excluding `*.generated.ts`) |
|
|
44
|
-
| "full audit" | Every Editor React Component folder under `src/extensions/site/components/`, excluding `*.generated.ts` |
|
|
45
|
-
|
|
46
|
-
## Workflow
|
|
47
|
-
|
|
48
|
-
Execute every phase inline while editing. Do not pause for approval or add a separate summary phase.
|
|
49
|
-
|
|
50
|
-
### Phase 1: Resolve Topology
|
|
51
|
-
|
|
52
|
-
1. Enumerate in-scope files under `src/extensions/site/components/<componentName>/`.
|
|
53
|
-
2. Include imported shared components or utilities that affect rendered semantics.
|
|
54
|
-
3. Exclude `*.generated.ts`.
|
|
55
|
-
4. Trace the topology from the component through wrappers and shared primitives to the rendered element.
|
|
56
|
-
|
|
57
|
-
### Phase 2a: ESLint JSX A11y Scan (Tier 0)
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
node <SKILL_ROOT>/scripts/scan-a11y-eslint.cjs <file1> [file2] ...
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
Use each finding's rule ID, message, and location as the rule-specific context. Validate the finding against the component implementation before editing.
|
|
64
|
-
|
|
65
|
-
### Phase 2b: Semantic Scan (Tier 1)
|
|
66
|
-
|
|
67
|
-
```bash
|
|
68
|
-
node <SKILL_ROOT>/scripts/scan-a11y-code.cjs <file1> [file2] ...
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
Use the emitted resolution path, evidence, and confidence to trace each finding. The scanner output is the source of rule-specific details; the reference only defines how to evaluate and act on those details.
|
|
72
|
-
|
|
73
|
-
Neither scanner validates manifest contracts or all Editor React Component patterns. Complete Phase 3 even when both scanners return zero findings.
|
|
74
|
-
|
|
75
|
-
### Deduplication and Triage
|
|
76
|
-
|
|
77
|
-
Evaluate every finding before fixing it.
|
|
78
|
-
|
|
79
|
-
**Deduplicate.** When both scanners flag the same location for the same issue, keep the finding with richer evidence. Prefer the semantic scanner when it resolved the component topology; prefer ESLint when the issue is outside the semantic scanner's scope.
|
|
80
|
-
|
|
81
|
-
| Verdict | Meaning | Action |
|
|
82
|
-
|---------|---------|--------|
|
|
83
|
-
| `confirmed` | The violation is real | Fix it |
|
|
84
|
-
| `false-positive` | The rule fires but the rendered behavior is correct | Discard it |
|
|
85
|
-
| `not-relevant` | The rule does not apply to this architecture | Discard it |
|
|
86
|
-
|
|
87
|
-
Use this order to evaluate a finding:
|
|
88
|
-
|
|
89
|
-
1. Trace the component implementation and confirm that the flagged behavior reaches the rendered element.
|
|
90
|
-
2. Check delegated semantics. Editor React Components route ARIA through the typed `a11y` prop and `convertA11yKeysToHtmlFormat(a11y)` (see [`ACCESSIBILITY.md`](ACCESSIBILITY.md)). If the attributes reach the correct element through a runtime path the scanner cannot see, discard the finding as a false positive.
|
|
91
|
-
3. Check conditional interactivity. When `onClick` is spread conditionally with `role`, `tabIndex`, and `onKeyDown`, discard the finding as a false positive. If only `onClick` is conditional, confirm it.
|
|
92
|
-
4. Apply the semantic checks in [`A11Y-REVIEW-REFERENCE.md`](A11Y-REVIEW-REFERENCE.md#tier-2-manual-review-checklist).
|
|
93
|
-
5. When uncertain, continue tracing the implementation. Default to `confirmed` only after checking the available code and evidence.
|
|
94
|
-
|
|
95
|
-
Only confirmed findings proceed to edits.
|
|
96
|
-
|
|
97
|
-
### Phase 3: Editor React Component Semantic Review
|
|
98
|
-
|
|
99
|
-
Perform a manual semantic review even when scanners return zero findings.
|
|
100
|
-
|
|
101
|
-
- All ARIA attributes come through the typed `a11y?: A11y` prop, never individual `ariaLabel?: string`, `role?: string`, and similar props. See [`ACCESSIBILITY.md`](ACCESSIBILITY.md).
|
|
102
|
-
- `a11y` is forwarded to the root via `{...(a11y && convertA11yKeysToHtmlFormat(a11y))}`, or to an inner element via `elementProps.<name>.a11y` when requirements specify.
|
|
103
|
-
- Icon-only interactive elements (icon/emoji/image/svg with no text node) have an accessible name from `constants.ts` or user-configurable `a11y`, never a hardcoded string literal.
|
|
104
|
-
- Direction support is mandatory: props include `direction?: Direction`, the root applies `dir={direction}` and the unconditional `fallbackDirection` class, and CSS defines `.fallbackDirection:not([dir])`. See [`DIRECTIONALITY.md`](DIRECTIONALITY.md).
|
|
105
|
-
- Every `ReactNode` content prop is rendered inside an element with `dir="ltr"` so user-provided nested content does not inherit the component direction.
|
|
106
|
-
- `<componentName>.extension.ts` overrides do not strip a11y-relevant manifest fields generated from the JSX.
|
|
107
|
-
- Decorative-only output is hidden with `aria-hidden` when appropriate.
|
|
108
|
-
- Heading/tag selection, when configurable, reaches the rendered semantic element.
|
|
109
|
-
- Interactive-looking elements expose the required keyboard behavior and roles.
|
|
110
|
-
|
|
111
|
-
Use the full Tier 2 checklist in [`A11Y-REVIEW-REFERENCE.md`](A11Y-REVIEW-REFERENCE.md#tier-2-manual-review-checklist).
|
|
112
|
-
|
|
113
|
-
### Phase 4: Fix
|
|
114
|
-
|
|
115
|
-
Apply fixes only to findings that survived triage:
|
|
116
|
-
|
|
117
|
-
- `high`: fix immediately
|
|
118
|
-
- `medium`: read the surrounding code, confirm, then fix
|
|
119
|
-
- `low`: resolve the semantics from code and evidence; fix only when confirmed
|
|
120
|
-
|
|
121
|
-
Confirmed safe/local fixes must be applied. Leave code unchanged only when the semantics remain ambiguous or the fix requires a risky, non-local behavior change. See [`A11Y-REVIEW-REFERENCE.md`](A11Y-REVIEW-REFERENCE.md#confidence-model).
|
|
122
|
-
|
|
123
|
-
Fix principles:
|
|
124
|
-
|
|
125
|
-
- Preserve intended visual and runtime behavior.
|
|
126
|
-
- Fix the real semantic owner: component root, inner element via `elementProps`, or shared base.
|
|
127
|
-
- Follow established Editor React Component patterns: route ARIA through `a11y`, use `constants.ts` for required labels, and never hardcode string literals.
|
|
128
|
-
- Before adding `role`, `tabIndex`, or keyboard handlers to a non-interactive element, run the [pre-fix checks](A11Y-REVIEW-REFERENCE.md#pre-fix-checks-for-adding-button-semantics-to-a-non-interactive-element).
|
|
129
|
-
|
|
130
|
-
### Phase 5: Verify
|
|
131
|
-
|
|
132
|
-
If any `.tsx` / `.jsx` file was edited:
|
|
133
|
-
|
|
134
|
-
1. Re-run both scanners on the modified files.
|
|
135
|
-
2. Run `npx wix build && npx wix generate manifest` so the manifest reflects any JSX changes.
|
|
136
|
-
3. Run the project's TypeScript check (`npx tsc --noEmit`), which is already part of the wix-app validation flow.
|
|
137
|
-
|
|
138
|
-
Verification is mandatory after edits. Continue directly from fixes to verification, and do not consider the workflow complete while a required check remains unrun.
|
|
139
|
-
|
|
140
|
-
## References
|
|
141
|
-
|
|
142
|
-
- [`A11Y-REVIEW-REFERENCE.md`](A11Y-REVIEW-REFERENCE.md) - triage, confidence, semantic resolution, Tier 2 checks, and pre-fix safeguards
|
|
143
|
-
- [`ACCESSIBILITY.md`](ACCESSIBILITY.md) - ARIA conventions for Editor React Components
|