sliderpro-agentic-skills-etch 0.1.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 +60 -0
- package/bin/cli.js +107 -0
- package/package.json +35 -0
- package/skills-package/components/dwc-slide.md +35 -0
- package/skills-package/components/dwc-slider-nav-button.md +56 -0
- package/skills-package/components/dwc-slider-pagination.md +60 -0
- package/skills-package/components/dwc-slider-play-pause.md +25 -0
- package/skills-package/components/dwc-slider-progress.md +70 -0
- package/skills-package/components/dwc-slider-wrapper.md +69 -0
- package/skills-package/components/dwc-slider.md +326 -0
- package/skills-package/slider-skills/slider-pro-skills-reference.md +491 -0
- package/skills-package/slider-skills/slider-pro-skills.md +492 -0
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
---
|
|
2
|
+
icon: robot
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# AI Skills Reference
|
|
6
|
+
|
|
7
|
+
Everything an agent needs to build and configure **Slider Pro for Etch** through the Etch AI
|
|
8
|
+
Connector. Read this file in full at session start. Its companion,
|
|
9
|
+
`slider-pro-skills-reference.md`, is lookup-only: Grep into it, never read it whole.
|
|
10
|
+
|
|
11
|
+
### When to consult the reference file
|
|
12
|
+
|
|
13
|
+
| You need | Section to Grep |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| A prop's exact key, path, attribute or default | `## 1. Prop reference` |
|
|
16
|
+
| A CSS variable name for arrows, dots, progress or the lightbox | `## 2. CSS variables` |
|
|
17
|
+
| Sync Custom Element details, multiple selectors, the overlap caveat | `## 3. Sync Custom Element` |
|
|
18
|
+
| Custom Options or the JavaScript API | `## 4. Escape hatches` |
|
|
19
|
+
| Whether an existing build is a premade template | `## 5. Recognising an existing setup` |
|
|
20
|
+
| Site-wide plugin settings | `## 6. Admin settings` |
|
|
21
|
+
|
|
22
|
+
Everything else lives here.
|
|
23
|
+
|
|
24
|
+
***
|
|
25
|
+
|
|
26
|
+
## START HERE: mandatory workflow
|
|
27
|
+
|
|
28
|
+
Do these in order. Skipping a step is how sessions go wrong.
|
|
29
|
+
|
|
30
|
+
### 0. Skill file first
|
|
31
|
+
|
|
32
|
+
Read this file before touching the connector. If the user asks for something and you have not read
|
|
33
|
+
it this session, read it now.
|
|
34
|
+
|
|
35
|
+
### 1. Connect and preflight
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @digital-gravy/etch-connector serve # once; leave running
|
|
39
|
+
npx @digital-gravy/etch-connector tabs # confirm exactly one tab for this site
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The tab name printed as `+ tab "..."` is the `-t` value for every `eval`. Use **one connected tab
|
|
43
|
+
per site**. Never two tabs on the same site.
|
|
44
|
+
|
|
45
|
+
Then confirm the plugin is actually there before planning anything:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
const comps = etch.components.list();
|
|
49
|
+
return comps.filter(c => c.name.startsWith('DWC Slider') || c.name === 'DWC Slide')
|
|
50
|
+
.map(c => c.name + ' = ' + c.id);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If that returns fewer than seven, stop and tell the user the components are not installed or are
|
|
54
|
+
out of date. Do not improvise replacements.
|
|
55
|
+
|
|
56
|
+
### 2. Scope clarification and user confirmation gate
|
|
57
|
+
|
|
58
|
+
Before building, state back in one short paragraph: what you will create, where it will go, and
|
|
59
|
+
what you will change on anything that already exists. Wait for confirmation. Never restructure an
|
|
60
|
+
existing page as a side effect of adding a slider.
|
|
61
|
+
|
|
62
|
+
### 3. Resolve component IDs by name, every session
|
|
63
|
+
|
|
64
|
+
**Component IDs are site-specific. Never hardcode them.** Resolve all seven by name at the start of
|
|
65
|
+
every session and keep the map for the rest of it.
|
|
66
|
+
|
|
67
|
+
```js
|
|
68
|
+
const byName = {};
|
|
69
|
+
for (const c of etch.components.list()) byName[c.name] = c.id;
|
|
70
|
+
// byName['DWC Slider Wrapper'], byName['DWC Slider'], byName['DWC Slide'], ...
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### 4. The native-first gate
|
|
74
|
+
|
|
75
|
+
**Slider Pro is props and CSS. It is almost never JavaScript.**
|
|
76
|
+
|
|
77
|
+
Before you write a single line of script, you must be able to say which of these two cases you are
|
|
78
|
+
in. If neither applies, you are about to do something the plugin already does:
|
|
79
|
+
|
|
80
|
+
1. **A per-element index or distance beyond plus or minus 1.** The plugin gives you exactly three
|
|
81
|
+
state classes: `is-active`, `is-prev`, `is-next`. That is distance 0 and plus or minus 1.
|
|
82
|
+
A design needing "the third card back sits lower and darker", a z-index ladder, or hit-testing
|
|
83
|
+
past the immediate neighbours cannot be expressed from those classes, because nothing in the
|
|
84
|
+
DOM says how far a given element is from the active one.
|
|
85
|
+
2. **An interpolable custom property.** `CSS.registerProperty({ name: '--x', syntax: '<number>' })`
|
|
86
|
+
so a number can animate. A plain custom property does not interpolate.
|
|
87
|
+
|
|
88
|
+
Everything else is a prop or a CSS rule. In particular, **do not write script for**: per-slide
|
|
89
|
+
transforms, tilts, scaling, fading or perspective (the `slides.*` group does all of it), responsive
|
|
90
|
+
behaviour (the shorthand does it), autoplay, looping, marquees, syncing elements to a slider, or
|
|
91
|
+
turning a carousel into a grid.
|
|
92
|
+
|
|
93
|
+
### 5. Declare before you script
|
|
94
|
+
|
|
95
|
+
State the method before writing the code: which blocks you will touch, which props you will set,
|
|
96
|
+
and, if you are writing script, which of the two cases above applies. One sentence each.
|
|
97
|
+
|
|
98
|
+
***
|
|
99
|
+
|
|
100
|
+
## Connector contract
|
|
101
|
+
|
|
102
|
+
### Running scripts
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
npx @digital-gravy/etch-connector eval "return etch.blocks.getTree().length" -t "<tab>"
|
|
106
|
+
npx @digital-gravy/etch-connector eval -f ./script.js -t "<tab>" --timeout 30000
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Anything longer than one expression goes in a file with `-f`. Inline multi-line quoting breaks in
|
|
110
|
+
every shell eventually.
|
|
111
|
+
|
|
112
|
+
### Safe mode
|
|
113
|
+
|
|
114
|
+
Scripts see `etch` and standard JavaScript built-ins. **`window`, `document`, all browser globals,
|
|
115
|
+
network and storage are blocked.**
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
ReferenceError: "window" is not available in safe mode
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
This matters constantly here: you cannot query the DOM to check what a slider rendered. Use
|
|
122
|
+
`etch.blocks.*` to inspect the document, and the CDP commands below to see the result.
|
|
123
|
+
|
|
124
|
+
### The `etch` API surface
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
Object.keys(etch)
|
|
128
|
+
// ["blocks", "loops", "styles", "stylesheets", "components",
|
|
129
|
+
// "navigation", "fields", "ui", "history",
|
|
130
|
+
// "saveAsync", "connectAs", "apiVersion", "version"]
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The ones this work uses:
|
|
134
|
+
|
|
135
|
+
```js
|
|
136
|
+
etch.blocks.getTree() // whole document
|
|
137
|
+
etch.blocks.getJson(blockId) // one block + subtree
|
|
138
|
+
etch.blocks.find({ type, class, attribute }) // ids of matching blocks
|
|
139
|
+
etch.blocks.getAttribute(blockId, key)
|
|
140
|
+
etch.blocks.setAttribute(blockId, key, value)
|
|
141
|
+
etch.blocks.create(json, parentId?, index?) // returns new id
|
|
142
|
+
etch.components.list() // [{ id, name }, ...]
|
|
143
|
+
etch.components.getJson(id) // .properties and .blocks
|
|
144
|
+
etch.styles.list() // [{ id, selector, type, collection, css }]
|
|
145
|
+
await etch.saveAsync()
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Component instances are the unit of work
|
|
149
|
+
|
|
150
|
+
A Slider Pro build is a tree of `etch/component` blocks, each carrying `ref` (the component id) and
|
|
151
|
+
a flat `attributes` map of prop values:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"blockName": "etch/component",
|
|
156
|
+
"attrs": {
|
|
157
|
+
"metadata": { "name": "- Flow" },
|
|
158
|
+
"ref": 6455,
|
|
159
|
+
"attributes": { "wrapperHeight": "350px", "spaceBetweenSliders": "50px" }
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Group props and the one-extra-brace rule
|
|
165
|
+
|
|
166
|
+
Most Slider props live in groups (`layout`, `motion`, `slides`, `autoplay`, ...). A group is stored
|
|
167
|
+
as JSON wrapped in **one extra layer of braces**:
|
|
168
|
+
|
|
169
|
+
```js
|
|
170
|
+
function getGroup(blockId, key) {
|
|
171
|
+
const raw = etch.blocks.getAttribute(blockId, key);
|
|
172
|
+
return raw ? JSON.parse(raw.slice(1, -1)) : {}; // strip one { and one }
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function setGroup(blockId, key, obj) {
|
|
176
|
+
etch.blocks.setAttribute(blockId, key, '{' + JSON.stringify(obj) + '}');
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Read, modify, write back. Never assemble a group from scratch unless you intend to drop every
|
|
181
|
+
value already in it.
|
|
182
|
+
|
|
183
|
+
**Booleans inside groups are strings**, not JS booleans:
|
|
184
|
+
|
|
185
|
+
```js
|
|
186
|
+
motion.loop = '{true}'; // correct
|
|
187
|
+
motion.loop = true; // wrong, silently useless
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**`setAttribute` validates the key** against the component's registered properties. You cannot set
|
|
191
|
+
an arbitrary `data-*` on a component instance. If a key is rejected, you have the wrong key: check
|
|
192
|
+
the prop reference.
|
|
193
|
+
|
|
194
|
+
### Visual verification
|
|
195
|
+
|
|
196
|
+
You cannot see the page from inside safe mode. After any visual change:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npx @digital-gravy/etch-connector shot -t "<tab>" -s ".my-slider" -o ./out.png
|
|
200
|
+
npx @digital-gravy/etch-connector html ".my-slider" -t "<tab>"
|
|
201
|
+
npx @digital-gravy/etch-connector computed ".my-slider .splide__slide" -t "<tab>" --props transform,opacity
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Then actually look at the screenshot. A slider that mounted is not the same as a slider that looks
|
|
205
|
+
right.
|
|
206
|
+
|
|
207
|
+
### Saving
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
await etch.saveAsync();
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Save once at the end of a coherent change, not after every attribute. Use `--timeout 30000` or
|
|
214
|
+
more for scripts that save.
|
|
215
|
+
|
|
216
|
+
***
|
|
217
|
+
|
|
218
|
+
## The structural contract
|
|
219
|
+
|
|
220
|
+
Get this right and most things work by themselves.
|
|
221
|
+
|
|
222
|
+
```
|
|
223
|
+
DWC Slider Wrapper [data-slider-wrapper]
|
|
224
|
+
DWC Slider [data-slider-role="main"] .splide
|
|
225
|
+
DWC Slide .splide__slide
|
|
226
|
+
DWC Slide
|
|
227
|
+
DWC Slider Nav Button (arrows)
|
|
228
|
+
DWC Slider Pagination (dots)
|
|
229
|
+
DWC Slider Progress (bar / circular / counter)
|
|
230
|
+
DWC Slider Play-Pause
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
Four rules follow from it:
|
|
234
|
+
|
|
235
|
+
1. **Controls find their own slider.** Every control searches the Slider first, then the Wrapper.
|
|
236
|
+
Put arrows above the track and a counter below it and both connect. There are no IDs to wire.
|
|
237
|
+
2. **A Wrapper can hold more than one Slider.** Set `sliderSetup.sliderRole` to `main` on one and
|
|
238
|
+
`thumbnails` on the other and they sync automatically. No Sync Group needed.
|
|
239
|
+
3. **Across separate Wrappers**, a main and thumbnail pair needs a matching
|
|
240
|
+
`sliderSetup.mainThumbnailSyncGroup` on both.
|
|
241
|
+
4. **A Wrapper with `sliderlessSync.customElement` set and no Slider inside** switches into Sync
|
|
242
|
+
Without Slider. That combination alone is the trigger.
|
|
243
|
+
|
|
244
|
+
***
|
|
245
|
+
|
|
246
|
+
## Decision tree
|
|
247
|
+
|
|
248
|
+
**Build from scratch:** components and props first, then CSS.
|
|
249
|
+
|
|
250
|
+
Reach for a premade template only when the user names one ("use Deck Featured"). Then paste its
|
|
251
|
+
JSON and customise, and read `https://design-with-cracka.gitbook.io/etchsliderpro/card-stack-templates` or `https://design-with-cracka.gitbook.io/etchsliderpro/premade-templates` for
|
|
252
|
+
its knobs.
|
|
253
|
+
|
|
254
|
+
**If the user points at an existing slider**, first check whether it is a premade template. Grep
|
|
255
|
+
`## 5. Recognising an existing setup` in the reference for the signature classes, and if it matches,
|
|
256
|
+
configure it the way its documentation describes instead of inventing new CSS over the top.
|
|
257
|
+
|
|
258
|
+
***
|
|
259
|
+
|
|
260
|
+
## Design recipes
|
|
261
|
+
|
|
262
|
+
Each of these is a shipped template reduced to the settings that produce it.
|
|
263
|
+
|
|
264
|
+
### Cover-flow carousel (Slider Flow): no script, no CSS
|
|
265
|
+
|
|
266
|
+
The whole effect is the `slides.*` group, which applies transforms to inactive slides and separate
|
|
267
|
+
`-Active` values to the current one.
|
|
268
|
+
|
|
269
|
+
```js
|
|
270
|
+
setGroup(sliderId, 'layout', { slidesPerPage: '3 lg:1', gapBetweenSlides: '20px',
|
|
271
|
+
sliderEdgeOffset: 'lg:20% md:18%' });
|
|
272
|
+
setGroup(sliderId, 'motion', { focus: 'center', loop: '{true}', speed: '800',
|
|
273
|
+
updateOnMove: '{true}' });
|
|
274
|
+
setGroup(sliderId, 'slides', { perspective: '950px', opacity: '0.3', scale: '0.9',
|
|
275
|
+
borderRadius: '1rem',
|
|
276
|
+
transition: 'transform 0.5s ease, opacity 0.5s ease' });
|
|
277
|
+
setGroup(sliderId, 'dimensions', { sliderHeight: '350px md:300px sm:180px' });
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
`motion.focus: 'center'` is what puts the active slide in the middle. The neighbours are dimmed and
|
|
281
|
+
shrunk purely by `slides.opacity` and `slides.scale`, which apply to inactive slides only.
|
|
282
|
+
|
|
283
|
+
For an angled flip, add `slides.rotateY` and turn on `slides.flipNextRotateY` so the slide on the
|
|
284
|
+
other side mirrors the angle instead of repeating it. Same for `translateX` with
|
|
285
|
+
`flipNextTranslateX`.
|
|
286
|
+
|
|
287
|
+
### Logo marquee (Slider Marquee): no script
|
|
288
|
+
|
|
289
|
+
Two Sliders in one Wrapper, running in opposite directions.
|
|
290
|
+
|
|
291
|
+
```js
|
|
292
|
+
// both rows
|
|
293
|
+
setGroup(sliderId, 'dimensions', { slideAutoWidth: '{true}' }); // slides size to content
|
|
294
|
+
setGroup(sliderId, 'motion', { loop: '{true}' });
|
|
295
|
+
setGroup(sliderId, 'autoscroll', { infiniteScroll: '{true}', scrollSpeed: '1',
|
|
296
|
+
pauseOnHover: '{false}', pauseOnFocus: '{false}' });
|
|
297
|
+
setGroup(sliderId, 'layout', { gapBetweenSlides: '2.4rem' });
|
|
298
|
+
|
|
299
|
+
// second row only
|
|
300
|
+
setGroup(secondId, 'sliderSetup', { slldeDirection: 'rtl' }); // note the spelling
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Edge Fade goes on the **Wrapper** (`props.edgeFade`), not the sliders, so both rows fade as one
|
|
304
|
+
unit. `props.pauseSlidersOnHover` on the Wrapper pauses both rows together.
|
|
305
|
+
|
|
306
|
+
Infinite Scroll needs the Auto-Scroll extension enabled in admin settings, which is the default.
|
|
307
|
+
|
|
308
|
+
### Synced elements (Zeon, Chronos, Team)
|
|
309
|
+
|
|
310
|
+
The pattern behind the full-bleed hero, the timeline and the staff showcase is one prop.
|
|
311
|
+
|
|
312
|
+
```js
|
|
313
|
+
setGroup(sliderId, 'sliderSetup', { syncCustomElement: '.timeline-node',
|
|
314
|
+
syncCustomElementNav: '{true}' });
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
The plugin then moves `is-active`, `is-prev` and `is-next` across those elements as the slider
|
|
318
|
+
moves, and with nav on, clicking one jumps the slider to it. **You write the CSS for the three
|
|
319
|
+
states.** The elements do not need to be inside the slider and do not need to match the slide
|
|
320
|
+
count.
|
|
321
|
+
|
|
322
|
+
Grep `## 3. Sync Custom Element` in the reference for multiple selectors and the overlap caveat.
|
|
323
|
+
|
|
324
|
+
### Carousel on mobile, grid on desktop
|
|
325
|
+
|
|
326
|
+
```js
|
|
327
|
+
setGroup(sliderId, 'layout', { layoutMode: 'static md:slider', gridColumns: '3 sm:1' });
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
Above `md` it is a plain CSS grid; at `md` and below it is a real carousel. The slider is built and
|
|
331
|
+
torn down live as the viewport crosses the breakpoint. **Controls are hidden in static mode**,
|
|
332
|
+
because there is no live slider to drive.
|
|
333
|
+
|
|
334
|
+
### Card decks with no slider (Deck, Fall): the one place script is allowed
|
|
335
|
+
|
|
336
|
+
Structure: a Wrapper with `sliderlessSync.customElement` pointing at your cards, no Slider inside,
|
|
337
|
+
cards nested three deep as `card > lift > content` so the 3-D survives.
|
|
338
|
+
|
|
339
|
+
```js
|
|
340
|
+
setGroup(wrapperId, 'sliderlessSync', {
|
|
341
|
+
customElement: '.deck-card', customElementNav: '{true}',
|
|
342
|
+
loop: '{true}', autoplay: '{true}', autoplayInterval: '4000'
|
|
343
|
+
});
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
CSS handles the front card and its two neighbours from `is-active` / `is-prev` / `is-next`. What
|
|
347
|
+
CSS cannot do is know that a given card is *three* back, so the rows behind, the z-index ladder and
|
|
348
|
+
the click targets need a script. That is case 1 of the native-first gate. The shipped script does
|
|
349
|
+
exactly three things:
|
|
350
|
+
|
|
351
|
+
```js
|
|
352
|
+
// 1. make a custom property interpolable, so a blur can animate (case 2)
|
|
353
|
+
CSS.registerProperty({ name: '--stack-focus', syntax: '<number>',
|
|
354
|
+
inherits: true, initialValue: '0' });
|
|
355
|
+
|
|
356
|
+
// 2. per card: distance from the active one, capped at the deepest tier the CSS defines
|
|
357
|
+
var rank = Math.abs(distanceFromActive);
|
|
358
|
+
card.setAttribute('data-tier', Math.min(rank, MAX_TIERS));
|
|
359
|
+
|
|
360
|
+
// 3. hit-testing: stack order by rank, and clicks off beyond the clickable rings
|
|
361
|
+
card.style.zIndex = String(total - rank);
|
|
362
|
+
lift.style.pointerEvents = rank <= NAV_RINGS ? 'auto' : 'none';
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Step 3 is not optional. Stacked cards are coplanar, so the browser hit-tests them by DOM order and
|
|
366
|
+
a click near the front card can land on one three positions away.
|
|
367
|
+
|
|
368
|
+
Card counts for a looping deck: three are always visible (front plus two), and a loop needs a
|
|
369
|
+
hidden slot at each end, so **five is the minimum** and nine gives the full three-row fan. Fall
|
|
370
|
+
never loops, so it has no minimum.
|
|
371
|
+
|
|
372
|
+
***
|
|
373
|
+
|
|
374
|
+
## Script library
|
|
375
|
+
|
|
376
|
+
Include these at the top of any script.
|
|
377
|
+
|
|
378
|
+
```js
|
|
379
|
+
function comps() {
|
|
380
|
+
const m = {};
|
|
381
|
+
for (const c of etch.components.list()) m[c.name] = c.id;
|
|
382
|
+
return m;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
function getGroup(id, key) {
|
|
386
|
+
const raw = etch.blocks.getAttribute(id, key);
|
|
387
|
+
return raw ? JSON.parse(raw.slice(1, -1)) : {};
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function setGroup(id, key, patch) {
|
|
391
|
+
const next = Object.assign(getGroup(id, key), patch);
|
|
392
|
+
etch.blocks.setAttribute(id, key, '{' + JSON.stringify(next) + '}');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function component(ref, attributes, children) {
|
|
396
|
+
return {
|
|
397
|
+
blockName: 'etch/component',
|
|
398
|
+
attrs: { ref: ref, attributes: attributes || {} },
|
|
399
|
+
innerBlocks: children || []
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function findByRef(nodes, ref, out) {
|
|
404
|
+
out = out || [];
|
|
405
|
+
for (const n of nodes || []) {
|
|
406
|
+
if (n.componentId === ref || (n.attrs && n.attrs.ref === ref)) out.push(n);
|
|
407
|
+
findByRef(n.children || n.innerBlocks || [], ref, out);
|
|
408
|
+
}
|
|
409
|
+
return out;
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Build a wrapper with N slides
|
|
414
|
+
|
|
415
|
+
```js
|
|
416
|
+
const C = comps();
|
|
417
|
+
const slides = [];
|
|
418
|
+
for (let i = 0; i < 5; i++) slides.push(component(C['DWC Slide'], {}));
|
|
419
|
+
|
|
420
|
+
const id = etch.blocks.create(
|
|
421
|
+
component(C['DWC Slider Wrapper'], {}, [
|
|
422
|
+
component(C['DWC Slider'], {}, slides),
|
|
423
|
+
component(C['DWC Slider Nav Button'], {}),
|
|
424
|
+
component(C['DWC Slider Pagination'], {})
|
|
425
|
+
])
|
|
426
|
+
);
|
|
427
|
+
return id;
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Build **one** first, screenshot it, then scale to the full count. Do not generate twenty slides
|
|
431
|
+
before you have seen one render.
|
|
432
|
+
|
|
433
|
+
### Read the current state of a slider
|
|
434
|
+
|
|
435
|
+
```js
|
|
436
|
+
const C = comps();
|
|
437
|
+
const slider = findByRef(etch.blocks.getTree(), C['DWC Slider'])[0];
|
|
438
|
+
const out = {};
|
|
439
|
+
for (const k of ['sliderSetup', 'layout', 'dimensions', 'motion', 'autoplay',
|
|
440
|
+
'navigation', 'slides', 'autoscroll', 'lightbox', 'breakpoints']) {
|
|
441
|
+
out[k] = getGroup(slider.id, k);
|
|
442
|
+
}
|
|
443
|
+
return JSON.stringify(out, null, 1);
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Do this before changing anything on a slider you did not build.
|
|
447
|
+
|
|
448
|
+
***
|
|
449
|
+
|
|
450
|
+
## Rules and gotchas
|
|
451
|
+
|
|
452
|
+
Each of these is a real failure, not a style preference.
|
|
453
|
+
|
|
454
|
+
**The responsive shorthand is desktop-first.** `3 md:2 sm:1` means 3 on the widest screens, 2 at
|
|
455
|
+
`md` and below, 1 at `sm` and below. The bare value is the **largest** screen. Breakpoints are
|
|
456
|
+
max-widths (default SM 640, MD 1024, LG 1120). Writing it mobile-first is the single most common
|
|
457
|
+
mistake, and `ltr sm:ttb` does the opposite of what it looks like.
|
|
458
|
+
|
|
459
|
+
**Never set a prop to its default.** It adds noise to the markup and hides real intent.
|
|
460
|
+
|
|
461
|
+
**A nested inner slider must be Slide or Fade, never Loop or Infinite Scroll.** A looping slider
|
|
462
|
+
makes hidden copies of its slides, and copying a slider that contains a slider breaks both. To wrap
|
|
463
|
+
around, use Fade, or Slide with Rewind.
|
|
464
|
+
|
|
465
|
+
**Do not put `overflow`, `opacity`, `filter`, `clip-path`, `mask`, `mix-blend-mode`, `isolation` or
|
|
466
|
+
`contain` on a 3-D stack, its cards, or the lifts.** Any one of them flattens the 3-D into a single
|
|
467
|
+
pile. If you need to clip or tint, add a separate wrapper outside the stack and put it there.
|
|
468
|
+
|
|
469
|
+
**Static layout mode hides the controls**, because there is no live slider to drive. Do not add
|
|
470
|
+
arrows to a slider that is static at every breakpoint.
|
|
471
|
+
|
|
472
|
+
**Slide Auto Width disables Slides Per Page.** Each slide takes its content's width, so the slides
|
|
473
|
+
need their own sizing.
|
|
474
|
+
|
|
475
|
+
**A vertical slider needs a height.** `slldeDirection: 'ttb'` cannot derive height from width, so
|
|
476
|
+
set `dimensions.sliderHeight` or `aspectRatio`. Both take the shorthand.
|
|
477
|
+
|
|
478
|
+
**Splide is a hard dependency for anything with a track.** Card stacks keep working without it,
|
|
479
|
+
sliders and the lightbox do not. If the site has When to Load Slider Assets on "Never", say so
|
|
480
|
+
rather than debugging a slider that will never start.
|
|
481
|
+
|
|
482
|
+
**Do not touch the plugin's own stylesheet.** Style through the Slider Class and CSS variables.
|
|
483
|
+
|
|
484
|
+
### Do not
|
|
485
|
+
|
|
486
|
+
* Hardcode component IDs.
|
|
487
|
+
* Set an arbitrary `data-*` on a component instance. `setAttribute` will reject it.
|
|
488
|
+
* Write script for anything the `slides.*` group, the shorthand, or Sync Custom Element already
|
|
489
|
+
does.
|
|
490
|
+
* Rebuild a premade template's CSS from scratch when the user is asking you to adjust one.
|
|
491
|
+
* Save after every attribute. Batch the change, then save once.
|
|
492
|
+
* Report success without a screenshot.
|