@wix/agent-skills 1.16.2 → 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.
Files changed (58) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +134 -120
  3. package/skills/wix-app/references/EMBEDDED_SCRIPT.md +6 -0
  4. package/skills/wix-app/references/SITE_PLUGIN.md +2 -2
  5. package/skills/wix-app/references/backend-event/COMMON-EVENTS.md +2 -2
  6. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +182 -99
  7. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +92 -47
  8. package/skills/wix-app/references/editor-react-component/BRANDED-COMPONENTS.md +15 -6
  9. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +275 -0
  10. package/skills/wix-app/references/editor-react-component/COMPONENT-PREVIEW.md +29 -42
  11. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +153 -449
  12. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +66 -19
  13. package/skills/wix-app/references/editor-react-component/DIRECTIONALITY.md +53 -158
  14. package/skills/wix-app/references/editor-react-component/EDITOR-EXTENSION-CONFIGURATION.md +78 -0
  15. package/skills/wix-app/references/editor-react-component/FUNCTION-HANDLERS.md +42 -134
  16. package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +27 -0
  17. package/skills/wix-app/references/editor-react-component/PARTS.md +45 -24
  18. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +63 -179
  19. package/skills/wix-app/references/editor-react-component/REACT-GUIDELINES.md +79 -163
  20. package/skills/wix-app/references/editor-react-component/SITE-CONTEXT-HOOKS.md +36 -21
  21. package/skills/wix-app/references/editor-react-component/SSR.md +30 -99
  22. package/skills/wix-base44-connector/SKILL.md +34 -17
  23. package/skills/wix-base44-connector/scripts/utils.js +33 -25
  24. package/skills/wix-headless/entry/bootstrap.mjs +9 -2
  25. package/skills/wix-headless/references/SDK_HANDOFF.md +1 -1
  26. package/skills/wix-headless/references/inline-recipes/how-to-code-a-store.md +42 -23
  27. package/skills/wix-headless/references/inline-recipes/how-to-code-pricing-plans.md +10 -8
  28. package/skills/wix-headless/references/inline-recipes/how-to-code-restaurant-orders.md +27 -24
  29. package/skills/wix-headless/references/managed/AUTHENTICATION.md +5 -0
  30. package/skills/wix-manage/SKILL.md +14 -2
  31. package/skills/wix-manage/references/bookings/booking-system-integration-gaps.md +20 -13
  32. package/skills/wix-manage/references/bookings/create-class-service.md +1 -1
  33. package/skills/wix-manage/references/bookings/end-to-end-booking-flow.md +24 -11
  34. package/skills/wix-manage/references/cms/cms-ecommerce-catalog-integration.md +5 -5
  35. package/skills/wix-manage/references/rich-content/author-ricos-rich-content.md +182 -5
  36. package/skills/wix-manage/references/seo/manage-seo-tags.md +315 -0
  37. package/skills/wix-manage/references/seo/manage-url-redirects.md +250 -0
  38. package/skills/wix-manage/references/sites/query-sites.md +72 -161
  39. package/skills/wix-replatform/resources/rp-mapper/wix-business-solutions-taxonomy.md +5 -6
  40. package/skills/wix-vibe-headless/platforms/base44-ecom-light-seed.md +13 -9
  41. package/skills/wix-vibe-headless/platforms/base44-ecom-light.md +10 -7
  42. package/skills/wix-vibe-headless/platforms/base44.md +13 -10
  43. package/skills/wix-vibe-headless/references/bookings/INSTRUCTIONS.md +2 -0
  44. package/skills/wix-vibe-headless/references/bookings/app/rest/wix-bookings-checkout.js +9 -8
  45. package/skills/wix-vibe-headless/references/restaurants/INSTRUCTIONS.md +4 -1
  46. package/skills/wix-vibe-headless/references/restaurants/app/components/OrderCartDrawer.jsx +23 -11
  47. package/skills/wix-vibe-headless/references/restaurants/app/context/OrderCartContext.jsx +1 -1
  48. package/skills/wix-vibe-headless/references/restaurants/app/rest/wix-restaurants-ordering.js +29 -31
  49. package/skills/wix-vibe-headless/references/storefront/INSTRUCTIONS.md +15 -8
  50. package/skills/wix-vibe-headless/references/storefront/app/components/CartDrawer.jsx +37 -38
  51. package/skills/wix-vibe-headless/references/storefront/app/context/CartContext.jsx +2 -2
  52. package/skills/wix-vibe-headless/references/storefront/app/rest/wix-store-cart.js +35 -35
  53. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW-REFERENCE.md +0 -172
  54. package/skills/wix-app/references/editor-react-component/A11Y-REVIEW.md +0 -143
  55. package/skills/wix-app/references/editor-react-component/COMPONENT-API.md +0 -484
  56. package/skills/wix-app/references/editor-react-component/COMPONENT-CONFIGURATION.md +0 -225
  57. package/skills/wix-app/references/editor-react-component/EDIT-FLOW.md +0 -6
  58. package/skills/wix-app/references/editor-react-component/REACT-PATTERNS.md +0 -95
@@ -1,519 +1,223 @@
1
- # CSS guidelines
2
-
3
- These rules govern the CSS authored for each generated site
4
- component. The rules exist so the rendered component is editable in
5
- the Wix visual editor, fits any user-resizable container, and can be
6
- parsed by zeroConfig to produce a correct manifest. Each rule states
7
- _why_; when an edge case isn't covered literally, follow the intent.
8
-
9
- ## Naming and class application
10
-
11
- ### Apply classes via the `classnames` helper; merge `className` on the root
12
-
13
- All CSS lives in a single CSS module file imported as `import styles from './[ComponentName].module.css';`. There is no separate global CSS import.
14
-
15
- There are two kinds of classes, determined by whether the element is a named part:
16
-
17
- | Element type | className | Why |
18
- |---|---|---|
19
- | Named part | `classNames('profile-card-heading', styles.heading)` | Global string → zeroConfig creates an editor element; module class → applies the component's own CSS |
20
- | Non-part (layout/structural) | `styles.contentWrapper` | Module class only — invisible to zeroConfig, no spurious editor element created |
21
-
22
- **Named parts** get both a global plain string and a module class. The global string is what zeroConfig scans: use `'<component-name>'` for the root and **`'<component-name>-<part-name>'` for every inner part** (kebab-case) — always prefix inner parts with the component name. The root here is the element elected per [`PARTS.md`](PARTS.md) Step 0, which is the component's own semantic element (`<button>`, `<a>`, `<ul>`) when the component reduces to one. The module class is what carries the component's structural CSS for that element; it stays short (`styles.heading`) because module classes are hashed and scoped, so they never need the prefix.
23
-
24
- **Why prefix inner parts:** the global string is a literal class that ends up on the live page, and its design-state variants are derived from it (`<component-name>-<part>--<state>`, e.g. `profile-card-cta--hover`). Those state classes are applied at runtime as global literals, so they must be unique across every component that can share a page — a bare `cta--hover` would collide between two different components. Prefixing with the component name guarantees uniqueness.
25
-
26
- **Non-part elements** (layout wrappers, grouping containers, structural helpers) get only a module class. CSS module classes are mangled and invisible to zeroConfig.
27
-
28
- The root also merges the consumer-provided `className` prop via the `classnames` helper.
29
-
30
- **Why:** zeroConfig creates one editor element per global class. A global class on a non-part produces a spurious editor element with no meaningful surface. The root's global class is unavoidable, which is why the root must be an element that deserves it.
31
-
32
- ```tsx
33
- import classNames from 'classnames';
34
- import styles from './ProfileCard.module.css';
35
-
36
- // ✅ Root: global string + module class + consumer className
37
- // (a <div> here only because this component lays out several sibling parts)
38
- <div className={classNames(className, 'profile-card', styles.root)} id={id}>
39
-
40
- {/* ✅ Named part: prefixed global string + short module class */}
41
- <h2 className={classNames('profile-card-heading', styles.heading)}>{heading}</h2>
42
-
43
- {/* ✅ Named part: interactive elements always get both classes */}
44
- <button type="button" className={classNames('profile-card-cta', styles.cta)}>
45
- {ctaLabel}
46
- </button>
47
-
48
- {/* ✅ Non-part layout wrapper: module class only */}
49
- <div className={styles.contentWrapper}>
50
- <span className={classNames('profile-card-label', styles.label)}>{label}</span>
51
- </div>
52
- </div>
53
-
54
- // ✅ Internal sub-components — same pattern on part slots
55
- <CardHeader className={classNames('profile-card-header', styles.header)}>
56
- <CardTitle className={classNames('profile-card-title', styles.title)}>{title}</CardTitle>
57
- </CardHeader>
58
- ```
59
-
60
- A component that reduces to one control is the other shape, and it has exactly one
61
- part — its root ([`PARTS.md`](PARTS.md) Step 0). The text it renders and any decoration
62
- stay inside that root, on module classes:
1
+ # CSS Guidelines
2
+
3
+ Use these rules for the scaffolded `<component-name>.module.css` file and any
4
+ colocated CSS Modules owned by internal sub-components. Keep existing visual
5
+ decisions outside the request unchanged. These rules keep the component
6
+ editable by zero config, responsive to its Wix-owned container, and safe in
7
+ both LTR and RTL layouts.
8
+
9
+ ## Contents
10
+
11
+ - [Classes and Named Parts](#classes-and-named-parts)
12
+ - [Selector Rules](#selector-rules)
13
+ - [Root Layout](#root-layout)
14
+ - [Sizing Through the Tree](#sizing-through-the-tree)
15
+ - [Responsiveness and Direction](#responsiveness-and-direction)
16
+ - [Editable Values](#editable-values)
17
+ - [Interaction and Motion](#interaction-and-motion)
18
+ - [Default Visual Quality](#default-visual-quality)
19
+ - [Checklist](#checklist)
20
+
21
+ ## Classes and Named Parts
22
+
23
+ Apply classes with `classnames`:
24
+
25
+ | Element | Classes |
26
+ | --- | --- |
27
+ | Elected root | `'<component-name>'`, `styles.root`, incoming `className`, fallback-direction class |
28
+ | Named inner part | `'<component-name>-<part-name>'`, its module class, injected `elementProps` class |
29
+ | Structural/decorative non-part | Module class only |
30
+
31
+ The global class lets zero config create an editor element. Prefix every inner
32
+ part with the component name to prevent collisions between components. The
33
+ module class carries the component's default CSS. Preserve the scaffolded root
34
+ pattern. For a new named part, add only the wiring the scaffold cannot infer:
35
+ spread its `elementProps` entry and merge the injected class.
63
36
 
64
37
  ```tsx
65
- // ✅ The <button> is the root: unprefixed global string, no elementProps entry
66
- <button
67
- type="button"
68
- id={id}
69
- dir={direction}
70
- className={classNames('like-button', styles.root, className, styles.fallbackDirection)}
38
+ <h2
39
+ {...elementProps?.heading}
40
+ className={classNames(
41
+ 'profile-card-heading',
42
+ styles.heading,
43
+ elementProps?.heading?.className,
44
+ )}
71
45
  >
72
- {label}
73
-
74
- {/* ✅ Decoration: module class only, out of the a11y tree, not a part */}
75
- <span className={styles.burst} aria-hidden="true" />
76
- </button>
46
+ {heading}
47
+ </h2>
77
48
  ```
78
49
 
79
- ### Use single-class selectors
50
+ If a component reduces to one meaningful control, link, media surface, or list,
51
+ that semantic element is the root. Do not wrap it just to host root props.
80
52
 
81
- Every selector is exactly one class, written as a flat top-level
82
- rule. Compound selectors (`.a.b`), descendant
83
- selectors (`.a .b`), child combinators (`.a > .b`), sibling
84
- combinators (`.a + .b`), tag selectors, and CSS nesting (the `&`
85
- syntax) are not permitted in component CSS.
53
+ ## Selector Rules
86
54
 
87
- **Why:** zeroConfig pairs each editor element with the single CSS
88
- rule keyed on its class. A compound or relational selector means
89
- either two elements share a rule or one element's appearance depends
90
- on context — either way the editor cannot decide which rule to
91
- modify when a user changes a property. CSS nesting compiles to
92
- descendant selectors and has the same effect.
93
-
94
- A state modifier on the element's own class (`.title:hover`,
95
- `.title:global(.profile-card-title--featured)`) is allowed — see [`DESIGN-STATES.md`](DESIGN-STATES.md).
55
+ Use flat, top-level selectors. Each selector must target one class plus an
56
+ optional state pseudo-class or global state modifier.
96
57
 
97
58
  ```css
98
- /* ✅ Do: Single-class selector — unambiguous mapping to an editor control */
99
- .profile-card {
100
- }
101
- .title {
102
- }
103
- .content {
104
- }
105
-
106
- /* ❌ Compound selector — rule applies only when both classes match the same element */
107
- .profile-card.featured {
108
- }
109
-
110
- /* ❌ Descendant selector — rule depends on ancestor structure */
111
- .profile-card .title {
112
- }
113
-
114
- /* ❌ Child combinator — rule depends on direct parent */
115
- .profile-card > .content {
116
- }
117
-
118
- /* ❌ Sibling combinator — rule depends on a sibling element */
119
- .title + .subtitle {
59
+ .heading {
60
+ color: #1e293b;
120
61
  }
121
62
 
122
- /* ❌ CSS nesting — compiles to a descendant selector */
123
- .profile-card {
124
- & .title {
125
- color: black;
126
- }
63
+ .cta:global(.profile-card-cta--hover),
64
+ .cta:hover {
65
+ background: #4f46e5;
127
66
  }
128
67
  ```
129
68
 
130
- ## Layout and responsiveness
69
+ Do not use compound selectors, tag selectors, child/sibling combinators, or CSS
70
+ nesting for editable styling. They make an element's editor surface depend on
71
+ DOM context.
131
72
 
132
- ### Root fills its container
73
+ Narrow exception: a relationship selector may control behavior-only visibility
74
+ when the behavior requires ancestor state and the rule does not define editable
75
+ appearance. A hover-revealed play/pause control is the canonical case. Keep all
76
+ of the control's size, color, border, typography, and state styling on its own
77
+ single-class rules.
133
78
 
134
- The root element sets `width: 100%`, `height: 100%`, and
135
- `box-sizing: border-box`. The component never assumes a specific
136
- pixel size for its outer box.
79
+ ## Root Layout
137
80
 
138
- **Why:** Wix users place components in resizable slots whose
139
- dimensions aren't known at authoring time. A root with hardcoded
140
- width or height overflows or leaves gaps inside its slot.
81
+ The root must fill the available inline size and use border-box sizing:
141
82
 
142
83
  ```css
143
- /* ✅ Do: Root fills any slot the user creates */
144
- .profile-card {
84
+ .root {
85
+ --display: flex;
145
86
  width: 100%;
146
- height: 100%;
147
87
  box-sizing: border-box;
148
88
  }
149
89
  ```
150
90
 
151
- ### Pipe sizing through every layer below the root
91
+ Add `height: 100%` only when the editor extension gives the component a pixel
92
+ height or the requested behavior requires a bounded height. Omit it when the
93
+ extension uses `LAYOUT.SIZING_TYPE.content`; the component's content must then
94
+ establish its block size.
95
+
96
+ Set `--display` on the root; do not set root `display` directly. The platform
97
+ resolves and overrides this custom property. Inner elements use `display`
98
+ normally.
99
+
100
+ Choose the simplest root shape that fits the component:
101
+
102
+ - column: `--display: flex; flex-direction: column`
103
+ - row: `--display: flex; flex-direction: row`
104
+ - split layout: `--display: grid; grid-template-columns: 1fr 1fr`
105
+ - responsive collection: `--display: grid; grid-template-columns: repeat(auto-fit, minmax(...))`
152
106
 
153
- Every element between the platform-sized root and the leaf content
154
- must explicitly participate in the sizing chain — one unsized
155
- wrapper collapses the entire subtree to intrinsic size.
107
+ Do not hardcode the root's pixel dimensions. Installation defaults belong in
108
+ the extension file.
156
109
 
157
- Use `flex: 1; min-width: 0` (or `min-height: 0` on the block axis)
158
- on children that should grow, and `flex: 0 0 auto` on children that
159
- should stay fixed-size.
110
+ ## Sizing Through the Tree
160
111
 
161
- **Why:** flex/grid children default to `auto` sizing and shrink to
162
- content. A wrapper `<div>` without explicit sizing breaks the chain
163
- even when the root fills its slot correctly.
112
+ - Put `box-sizing: border-box` on every component selector.
113
+ - In a bounded axis, use `flex: 1` with `min-width: 0` or `min-height: 0` for
114
+ children that grow.
115
+ - Use `flex: 0 0 auto` for controls that retain intrinsic size.
116
+ - Ensure every wrapper between the root and bounded growing content
117
+ participates in the sizing chain. Do not create a block-axis sizing chain for
118
+ a content-height component.
164
119
 
165
120
  ```css
166
- /* ✅ Do: grower fills remaining space */
167
- .wrapper {
121
+ .content {
122
+ box-sizing: border-box;
168
123
  display: flex;
169
124
  flex: 1;
170
125
  min-width: 0;
171
126
  }
172
127
 
173
- /* ✅ Do: fixed child keeps intrinsic size */
174
128
  .control {
175
- flex: 0 0 auto;
176
- }
177
- ```
178
-
179
- ### Set `box-sizing: border-box` on every selector
180
-
181
- Apply `box-sizing: border-box` to every class in component CSS, not
182
- just the root. The default `content-box` is never wanted in this
183
- codebase.
184
-
185
- **Why:** the editor exposes padding and border-width as live
186
- controls. With `content-box`, increasing either grows the element's
187
- outer box, which makes neighbouring elements visibly shift while the
188
- user is dragging a slider — the component "shakes" in the editor.
189
- `border-box` keeps the outer dimension stable; padding and border
190
- eat into the existing box instead, so the layout stays still while
191
- the user tunes values.
192
-
193
- ```css
194
- /* ✅ Do: border-box — outer size stays stable while the editor tunes padding and border */
195
- .profile-card,
196
- .title,
197
- .button {
198
129
  box-sizing: border-box;
199
- }
200
-
201
- /* ❌ content-box — outer size grows when the editor adjusts padding or border */
202
- .profile-card {
203
- box-sizing: content-box; /* the default — don't rely on it */
130
+ flex: 0 0 auto;
204
131
  }
205
132
  ```
206
133
 
207
- ### Adapt to container size, not viewport
208
-
209
- Layout responds to the size of the component's parent, not to the
210
- browser viewport. Use intrinsic flex/grid sizing (`auto-fit`,
211
- `minmax(...)`, `1fr`) and `clamp()` for fluid scaling. `@media`
212
- queries keyed on viewport dimensions (`width`, `height`,
213
- `orientation`) are not permitted in component CSS.
214
-
215
- **Why:** the Wix editor owns viewport-level breakpoints. A component
216
- that branches on viewport width competes with the editor's
217
- responsiveness model and renders the same container size differently
218
- across viewports, breaking the editor's WYSIWYG contract.
219
-
220
- ```css
221
- /* ✅ Do: Container-driven sizing — adapts to the slot, not the viewport */
222
- .card-grid {
223
- display: grid;
224
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
225
- gap: clamp(1rem, 2.5vw, 2rem);
226
- }
134
+ ## Responsiveness and Direction
227
135
 
228
- /* ❌ Viewport breakpoint — fights the editor's responsiveness model */
229
- @media (max-width: 768px) {
230
- .card-grid {
231
- grid-template-columns: 1fr;
232
- }
233
- }
234
- ```
136
+ Respond to the component container, not the browser viewport. Prefer intrinsic
137
+ flex/grid sizing, `minmax()`, `auto-fit`, `1fr`, and `clamp()`. Do not add
138
+ viewport `@media` rules; Wix owns page breakpoints.
235
139
 
236
- ### Use logical properties on the inline axis
237
-
238
- For any property that should flip between LTR and RTL — horizontal
239
- margin, padding, border, positional offset — use logical properties
240
- keyed on the inline axis: `margin-inline`, `margin-inline-start`,
241
- `margin-inline-end`, `padding-inline`, `padding-inline-start`,
242
- `padding-inline-end`, `border-inline-start`, `border-inline-end`,
243
- `inset-inline-start`, `inset-inline-end`. Do not use `margin-left` /
244
- `margin-right`, `padding-left` / `padding-right`, `border-left` /
245
- `border-right`, `left`, or `right`.
246
-
247
- Block-axis properties (`margin-top`, `margin-bottom`, `padding-top`,
248
- `padding-bottom`, `border-top`, `border-bottom`, `top`, `bottom`)
249
- stay as physical properties — they don't flip with text direction
250
- in horizontal writing modes, which is what site components ship in.
251
-
252
- **Why:** the Wix editor lets the site owner switch a site's text
253
- direction between LTR and RTL. Logical inline properties flip
254
- automatically with `direction: rtl` set by an ancestor, so one CSS
255
- file produces correct layouts in both directions. Physical
256
- left/right properties stay locked regardless of direction, which
257
- breaks RTL layouts (icons end up on the wrong side of text, padding
258
- piles up on the wrong edge, sticky offsets point the wrong way).
140
+ Use logical inline-axis properties so layout flips automatically in RTL:
259
141
 
260
142
  ```css
261
- /* ✅ Do: Inline logical properties — flip automatically in RTL */
262
- .profile-card {
143
+ .content {
263
144
  padding-inline: 24px;
264
145
  margin-inline-start: 8px;
265
- border-inline-start: 4px solid currentColor;
266
- }
267
-
268
- /* ❌ Don't: Physical left/right — stays locked in RTL and breaks the layout */
269
- .profile-card {
270
- padding-left: 24px;
271
- padding-right: 24px;
272
- margin-left: 8px;
273
- border-left: 4px solid currentColor;
274
- }
275
-
276
- /* ✅ Do: Block axis stays physical — top/bottom don't flip with direction */
277
- .banner {
278
- position: sticky;
279
- top: 0;
280
- padding-block: 12px;
281
- }
282
- ```
283
-
284
- ### Set the root layout via `--display`, never `display`
285
-
286
- The root rule declares `--display: <value>` and does not set
287
- `display` itself. The platform reads `--display` and applies the
288
- resolved `display` value at runtime. This rule applies to the root
289
- selector only — inner element classes set `display` directly as
290
- normal.
291
-
292
- **Why:** the editor toggles a component's visibility (and other
293
- display modes) by overriding the `--display` custom property on the
294
- root. If the root rule also sets `display` directly, that
295
- declaration wins over the platform's override and the editor has to
296
- rewrite the rule to take effect, which is fragile. Inner elements
297
- aren't toggled this way, so they use `display` normally.
298
-
299
- ```css
300
- /* ✅ Do: Root declares --display only — platform applies it, editor can override */
301
- .profile-card {
302
- --display: flex;
303
- }
304
-
305
- /* ❌ Don't: Root sets display directly — competes with the platform override */
306
- .profile-card {
307
- --display: flex;
308
- display: var(--display);
309
- }
310
-
311
- /* ✅ Do: Inner elements set display normally — the --display rule is root-only */
312
- .header {
313
- display: flex;
314
- align-items: center;
315
- }
316
- ```
317
-
318
- ### Choose one of four layout shapes for the component root
319
-
320
- A component's root layout typically fits one of four shapes — reach
321
- for the simplest one that satisfies the design.
322
-
323
- **Why:** a small, shared vocabulary of layouts produces predictable
324
- manifests and predictable editor behavior. The editor's
325
- auto-generated controls (gap, padding, alignment) are tuned for
326
- these shapes.
327
-
328
- ```css
329
- /* ✅ Do: Single column — stacked content (profile card, pricing card, CTA block) */
330
- .profile-card {
331
- --display: flex;
332
- flex-direction: column;
333
- align-items: center;
334
- text-align: center;
335
- gap: 1rem;
336
- padding: clamp(1rem, 3vw, 2rem);
337
- }
338
-
339
- /* ✅ Do: Two-column split — media + text pair (testimonial, feature row, media card) */
340
- .media-card {
341
- --display: grid;
342
- grid-template-columns: 1fr 1fr;
343
- gap: clamp(1rem, 3vw, 2rem);
344
- align-items: center;
345
- }
346
-
347
- /* ✅ Do: Multi-column grid — list of children (product list, testimonial list, gallery) */
348
- .testimonial-list {
349
- --display: grid;
350
- grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
351
- gap: clamp(1rem, 2.5vw, 2rem);
352
- }
353
-
354
- /* ✅ Do: Inline row — fixed controls on edges, growing center
355
- (numeric stepper, search bar, toolbar, split button, pagination).
356
- Pair with stretch-chain rules: controls flex: 0 0 auto,
357
- center area flex: 1; min-width: 0. */
358
- .numeric-stepper {
359
- --display: flex;
360
- flex-direction: row;
361
- align-items: center;
146
+ border-inline-start: 1px solid currentColor;
147
+ inset-inline-end: 0;
362
148
  }
363
149
  ```
364
150
 
365
- ## CSS variables and props
151
+ Avoid `left`, `right`, `margin-left`, `padding-right`, and similar physical
152
+ inline-axis properties. Physical block-axis properties such as `top` and
153
+ `margin-bottom` are fine.
366
154
 
367
- ### Use literal CSS values; introduce a variable only when interpolation requires it
155
+ ## Editable Values
368
156
 
369
- Write CSS values as literals. Introduce a CSS custom property _only_
370
- when the value is consumed inside a CSS function or compound
371
- expression that cannot be written as a plain value — for example
372
- inside `repeat()`, `calc()`, `min()`, `max()`, or `clamp()`. Do not
373
- add a React prop for a value the user wouldn't meaningfully tune.
157
+ Keep static styling in the CSS Module, not JSX `style` objects. Use literal CSS
158
+ values when no interpolation is needed; do not create a React prop or CSS custom
159
+ property for routine values that zero config already surfaces.
374
160
 
375
- **Why:** every CSS variable that crosses into a React prop becomes a
376
- control in the editor. Exposing routine values like `gap` or
377
- `padding` as props clutters the editor UI, and the editor already
378
- auto-surfaces those properties from the CSS rule itself —
379
- duplicating them as props gives the user two competing controls for
380
- the same thing.
161
+ Use this pattern:
381
162
 
382
163
  ```css
383
- /* ❌ Don't: Unnecessary variable — value isn't interpolated anywhere */
384
- .profile-card {
385
- --gap: 16px;
386
- gap: var(--gap);
387
- }
388
-
389
- /* ✅ Do: Literal value — nothing to interpolate */
390
- .profile-card {
164
+ .root {
391
165
  gap: 16px;
166
+ padding: 24px;
167
+ background: #ffffff;
392
168
  }
393
169
 
394
- /* ✅ Do: Variable required — value is consumed inside repeat() */
395
- .card-grid {
170
+ .grid {
396
171
  --columns: 3;
397
172
  grid-template-columns: repeat(var(--columns), 1fr);
398
173
  }
399
174
  ```
400
175
 
401
- ## Other rules
402
-
403
- ### Keep all styling in CSS
404
-
405
- Static styling lives in the component's CSS. Do not use the JSX
406
- `style={{ ... }}` attribute on rendered elements. Dynamic values
407
- that genuinely vary per instance go through CSS custom properties
408
- (see the rule above), still set in CSS.
409
-
410
- **Why:** zeroConfig reads CSS rules to derive the editor's control
411
- surface. An inline `style` attribute is invisible to the extractor,
412
- so any value baked into JSX cannot be edited in the visual editor —
413
- the user sees no control for it.
176
+ A dynamic runtime value that cannot be represented statically may use a narrowly
177
+ scoped CSS custom property set from JSX, but keep the actual style rule in CSS
178
+ and do not expose a visual prop solely for that purpose.
414
179
 
415
- ```tsx
416
- // ❌ Inline style — invisible to zeroConfig, no editor control
417
- <div className="profile-card" style={{ padding: 20, borderRadius: 8 }} />
418
-
419
- // ✅ Do: Defaults in CSS — surfaced to the editor as controls
420
- <div className="profile-card" />
421
- ```
422
-
423
- ```css
424
- /* ✅ Do: Defaults belong in CSS so the editor can surface them */
425
- .profile-card {
426
- padding: 20px;
427
- border-radius: 8px;
428
- background: #ffffff; /* Use `background`, never `background-color` — the schema key is "background"; zeroConfig can't match "background-color" so the default is lost in the design panel */
429
- }
430
- ```
180
+ ## Interaction and Motion
431
181
 
432
- ### Default aesthetic: polished and generous
433
-
434
- When the user does not specify a visual style, default to a polished,
435
- modern look. The editor lets the user override every value, so a
436
- refined default costs nothing.
437
-
438
- | Property | Guidance |
439
- |---|---|
440
- | `border-radius` | 8–12 px containers, `50%` for controls and interactive groups (buttons, pills, input rows) |
441
- | `box-shadow` | Prefer soft, diffused shadows over hard borders (e.g. `0 2px 8px rgba(0,0,0,0.06), 0 0 1px rgba(0,0,0,0.08)`) |
442
- | Spacing | 8–16 px inside controls, 16–32 px for containers. Avoid cramped layouts |
443
- | Typography | Body ≥ 16 px, labels ≥ 14 px, headings larger. `font-weight: 500`–`600` |
444
- | Palette | Root background transparent (blends with page). Use subtle fills (`#f1f5f9`/`#e2e8f0`) on *inner controls* only (buttons, input areas, pill containers). Text `#1e293b`/`#334155`, borders `#e2e8f0`. `#475569` for large/secondary text only |
445
- | Accent | Use a muted accent color (e.g. `#6366f1`, `#7c83db`) sparingly on interactive icons, active indicators, and primary actions — just enough to signal interactivity without dominating |
446
- | Contrast | WCAG AA minimum: 4.5:1 body text, 3:1 large text / UI controls |
447
- | Hierarchy | Interactive elements visually distinct from static via weight, fill, or elevation |
448
- | Touch targets | Interactive elements ≥ 44×44 px |
449
-
450
- ### Design states
451
-
452
- Style interaction and selection states (`hover`, `focus`, `disabled`,
453
- `selected`, …) per [`DESIGN-STATES.md`](DESIGN-STATES.md).
454
-
455
- ### Don't add transitions or animations unless functionally required
456
-
457
- Component CSS does not declare `transition` or `animation` for
458
- decorative purposes. Use them only when the motion is part of the
459
- component's behavior (e.g. an accordion panel sliding open, a
460
- carousel translating between slides). When transitions are required,
461
- list the specific properties — never `transition: all`,
462
- `transition-property: all`, or the implicit `all` of a duration-only
463
- shorthand (`transition: 0.2s ease`).
464
-
465
- **Why:** the editor mutates many CSS properties live as the user
466
- configures the component — colors, font, padding, border width,
467
- even layout properties on parent classes. Animating those mutations
468
- makes the editor visibly laggy: values meant to update instantly
469
- slide instead.
182
+ - Set `pointer-events: auto` on the root and each interactive element.
183
+ - Pair native interaction selectors with the matching editor-injected global
184
+ state modifier. Toggle custom state modifiers from component data.
185
+ - Do not add decorative transitions or animations.
186
+ - When motion is functionally required, list the exact transition properties;
187
+ never use `transition: all` or an implicit `all` shorthand.
470
188
 
471
189
  ```css
472
- /* ❌ Don't: decorative transition with no functional reason */
473
- .button {
474
- transition: background-color 0.2s ease;
475
- }
476
-
477
- /* ❌ Don't: transition: all — animates every property the editor touches */
478
- .button {
479
- transition: all 0.2s ease;
480
- }
481
-
482
- /* ❌ Don't: implicit all — duration-only shorthand resolves to transition-property: all */
483
- .button {
484
- transition: 0.2s ease;
485
- }
486
-
487
- /* ✅ Do: Functional transition with specific properties named (e.g. accordion expand) */
488
190
  .panel {
489
191
  transition: height 0.2s ease;
490
192
  }
491
193
  ```
492
194
 
493
- **Media playback is functional, not decorative.** When the component's content
494
- *is* a playing animation (Lottie/JSON, animated GIF/SVG, canvas/WebGL, video),
495
- letting it play is allowed — the motion is the content. Such components get a
496
- play/pause control positioned in CSS. See
497
- [`ANIMATED-COMPONENTS.md`](ANIMATED-COMPONENTS.md).
498
-
499
- ### Set `pointer-events: auto` on the root and every interactive element
500
-
501
- The root selector and every nested class that the user can click,
502
- hover, or focus (links, buttons, controls) explicitly set
503
- `pointer-events: auto`.
504
-
505
- **Why:** the editor renders components inside wrappers that disable
506
- pointer events at the wrapper level so the editor itself can capture
507
- clicks for selection. Explicit `auto` on the component's own
508
- elements ensures interaction reaches them at runtime on the
509
- published site, where the wrapper is gone.
510
-
511
- ```css
512
- /* ✅ Do: pointer-events: auto — interaction reaches component elements through the editor wrapper */
513
- .profile-card,
514
- .title,
515
- .button {
516
- pointer-events: auto;
517
- }
518
- ```
519
-
195
+ ## Default Visual Quality
196
+
197
+ When creating a component and the request has no visual direction, use a
198
+ restrained accessible default. When editing an existing component, preserve its
199
+ visual language unless the request changes it.
200
+
201
+ - body text at least 16px and labels at least 14px
202
+ - WCAG AA contrast (4.5:1 body text, 3:1 large text and UI controls)
203
+ - touch targets at least 44 by 44px
204
+ - clear hierarchy and visible focus states
205
+ - generous but consistent spacing
206
+ - transparent root backgrounds unless the design requires a surface
207
+
208
+ Avoid prescribing a brand palette in a generic component. Only when the prompt
209
+ explicitly requests branded or themed output, use its named brand tokens rather
210
+ than hardcoded generic color choices.
211
+
212
+ ## Checklist
213
+
214
+ - [ ] The scaffolded component and each extracted internal sub-component own
215
+ their styles through colocated CSS Modules.
216
+ - [ ] Global classes exist only for the root and named inner parts.
217
+ - [ ] Selectors are flat except for a documented behavior-only exception.
218
+ - [ ] The root uses `--display`, fills the applicable configured axes, and uses
219
+ border-box sizing.
220
+ - [ ] A sizing chain exists only on bounded growing axes.
221
+ - [ ] Layout is container-driven and uses logical inline properties.
222
+ - [ ] Static styling stays in CSS; custom properties exist only when needed.
223
+ - [ ] Interactive elements expose pointer events and accessible design states.