Skip to content

Commit d85c071

Browse files
authored
Interact rules urgent ssot fixes (#293)
* docs + audit * update audit * wip * update audit * update docs, audit , and rules * update rules and fix single wrong check * update rules and fix single wrong check * update rules and fix single wrong check
1 parent e2f2cbf commit d85c071

6 files changed

Lines changed: 40 additions & 38 deletions

File tree

packages/interact-validate/src/semantic/fouc.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ export function checkHitAreaShift(
5353
const isPointer = owner.trigger === 'pointerMove';
5454
if (!isDiscrete && !isPointer) return [];
5555
// `hitArea: 'root'` tracks the viewport, so a transform on the source cannot
56-
// shift the hit area. Default (`'self'`) and explicit `'self'` are at risk.
57-
if (isPointer && owner.params?.hitArea === 'root') return [];
56+
// shift the hit area. Only explicit `'self'` are at risk.
57+
if (isPointer && owner.params?.hitArea !== 'self') return [];
5858
if (!targetsSameElementAsSource(owner, effect)) return [];
5959
const keyframes = effect.keyframeEffect?.keyframes;
6060
if (!Array.isArray(keyframes)) return [];

packages/interact-validate/test/rules/hitAreaShift.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ describe('hitAreaShift — HIT_AREA_SHIFT', () => {
3333
expect(result.valid).toBe(true);
3434
});
3535

36-
it('warns for a pointerMove keyframeEffect with a scale transform (default hitArea: self)', () => {
36+
it('does not warns for a pointerMove keyframeEffect with a scale transform (default hitArea: root)', () => {
3737
const result = validateInteractConfig({
3838
interactions: [
3939
{
@@ -48,7 +48,7 @@ describe('hitAreaShift — HIT_AREA_SHIFT', () => {
4848
},
4949
],
5050
});
51-
expect(result.errors.some((e) => e.code === CODE)).toBe(true);
51+
expect(result.errors.some((e) => e.code === CODE)).toBe(false);
5252
});
5353

5454
describe('no warning for the documented valid patterns', () => {

packages/interact/rules/full-lean.md

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ For most use cases, `key` alone is sufficient for both source and target resolut
237237
- `effectId`: string of the effect to wait for completion
238238
- Usage: Fire when the specified effect (by `effectId`) on the source element finishes, useful for chaining sequences.
239239
- pointerMove: `PointerMoveParams`
240-
- `hitArea?`: `'root' | 'self'` (default `'self'`)
240+
- `hitArea?`: `'root' | 'self'` (default `'root'` — an omitted `hitArea` tracks the viewport)
241241
- `axis?`: `'x' | 'y'` - when using `keyframeEffect` with `pointerMove`, selects which pointer coordinate maps to linear 0-1 progress; defaults to `'y'`. Ignored for `namedEffect` and `customEffect`.
242242
- Usage:
243243
- `'self'`: Track pointer within the source element’s bounds.
@@ -283,15 +283,23 @@ For `TimeEffect` (keyframe/named/custom effects), set `triggerType` on the effec
283283
284284
```ts
285285
params: {
286-
threshold?: number; // 0–1, IntersectionObserver threshold
287-
inset?: string; // like view-timeline-inset, e.g. '-100px' or '-50px 0px'
286+
threshold?: number; // 0–1, IntersectionObserver threshold (default 0.2)
287+
inset?: string; // like view-timeline-inset, e.g. '-100px' or '-50px 0px'
288+
useSafeViewEnter?: boolean; // default false; see below
288289
}
289290
// Playback behavior is set on each effect:
290291
effect.triggerType: 'once' | 'repeat' | 'alternate' | 'state'; // default: 'once'
291292
```
292293
293294
**CRITICAL:** When source and target are the **same element**, MUST use `triggerType: 'once'`. For `'repeat'` / `'alternate'` / `'state'`, ALWAYS use **separate** source and target elements — animating the observed element can cause it to leave/re-enter the viewport, causing rapid re-triggers.
294295
296+
**`useSafeViewEnter`** — guards against a `threshold` that can never be met. A `threshold` is a fraction of the **source's own box**, so when `sourceHeight × threshold` exceeds the viewport height the ratio is unreachable and the animation never fires. With this flag set, the first non-intersecting observer callback measures the source and, if the threshold is unreachable, swaps to a fallback observer (`threshold: 0`, `rootMargin: '0px 0px -10% 0px'`).
297+
298+
Two constraints that follow from the implementation:
299+
300+
- It only helps alongside an **explicit** `threshold`. The check reads the authored value, not the `0.2` default, so `useSafeViewEnter: true` on its own does nothing.
301+
- The fallback observer uses a fixed config, so a configured `inset` is discarded once it kicks in.
302+
295303
### viewProgress
296304
297305
Scroll-driven animations using native `ViewTimeline`, with polyfill where not supported. Progress is driven by scroll position. Control the range via `rangeStart`/`rangeEnd` on the effect (see [Scroll / Pointer-driven Effect](#scroll--pointer-driven-effect)).
@@ -317,7 +325,9 @@ params: {
317325
- For 2D effects, use `namedEffect` mouse presets or `customEffect`. `keyframeEffect` only supports a single axis.
318326
- For independent 2-axis control with keyframes, use two separate interactions (one `axis: 'x'`, one `axis: 'y'`) with `composite: 'add'` or `'accumulate'` on the second effect.
319327
320-
**`centeredToTarget`**set `true` to remap the `0–1` progress range so that `0.5` progress corresponds to the center of the target element. Use when source and target are different elements, or when `hitArea: 'root'` is used, so that the pointer resting over the target center produces 50% progress regardless of position in viewport.
328+
**`centeredToTarget`**set `true` to remap the `0–1` progress range so that `0.5` progress corresponds to the center of the target element. Use when source and target are different elements, or when `hitArea: 'root'` is used, so that the pointer resting over the target center produces 50% progress regardless of position in viewport. Applies to `namedEffect` and `customEffect` only: a `keyframeEffect` scrub scene resolves no target, so centering is silently ignored there.
329+
330+
**`transitionDuration` / `transitionEasing`**progress smoothing. Forwarded **only** when the payload is a `customEffect`; they are dropped for `keyframeEffect` and `namedEffect` on `pointerMove`.
321331
322332
**Progress object** (for `customEffect`):
323333
@@ -406,10 +416,10 @@ Used with `viewProgress` and `pointerMove` triggers.
406416
reversed?: boolean;
407417
fill?: 'none' | 'forwards' | 'backwards' | 'both';
408418
composite?: 'replace' | 'add' | 'accumulate';
409-
centeredToTarget?: boolean;
410-
transitionDuration?: number; // ms, smoothing on progress jumps (primarily for pointerMove)
419+
centeredToTarget?: boolean; // pointerMove; namedEffect / customEffect onlyignored for keyframeEffect
420+
transitionDuration?: number; // ms, smoothing on progress jumps; pointerMove + customEffect only
411421
transitionDelay?: number; // ms (primarily for pointerMove)
412-
transitionEasing?: 'linear' | 'hardBackOut' | 'easeOut' | 'elastic' | 'bounce';
422+
transitionEasing?: 'linear' | 'hardBackOut' | 'easeOut' | 'elastic' | 'bounce'; // pointerMove + customEffect only
413423
// + exactly one animation payload (see below)
414424
}
415425
```
@@ -450,7 +460,7 @@ Used with `hover` / `click` triggers. Set `stateAction` on the effect to control
450460
- `transition?`: `{ duration?: number; delay?: number; easing?: string; styleProperties: { name: string; value: string }[] }`
451461
- Applies a single transition options block to all listed style properties.
452462
- `transitionProperties?`: `Array<{ name: string; value: string; duration?: number; delay?: number; easing?: string }>`
453-
- Allows per-property transition options. If both `transition` and `transitionProperties` are provided, the system SHOULD apply both with per-property entries taking precedence for overlapping properties.
463+
- Allows per-property transition options. Set one or the other: if `transition.styleProperties` is present, `transitionProperties` is ignored **entirely** — it is not merged, and per-property entries do not take precedence for overlapping properties.
454464
455465
```ts
456466
// Shared timing for all properties:

packages/interact/rules/integration.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,5 +360,5 @@ Each `Interact.create(config)` call returns an instance. Keep a reference if you
360360
| `Interact.registerEffects(presets)` | Register named effect presets before `generate()` and `create`. Required for `namedEffect`. |
361361
| `Interact.destroy()` | Tear down all instances. |
362362
| `Interact.forceReducedMotion` | `boolean` — force reduced-motion behavior regardless of OS setting. Default: `false`. |
363-
| `Interact.allowA11yTriggers` | `boolean` — enable accessibility triggers (`interest`, `activate`). Default: `false`. |
363+
| `Interact.allowA11yTriggers` | `boolean` — enable accessibility triggers (`interest`, `activate`). Default: `true`. |
364364
| `Interact.setup(options)` | Configure global defaults for scroll/pointer/viewEnter trigger params. Call before `create`. |

packages/interact/rules/pointermove.md

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ type PointerMoveParams = {
3636

3737
### Properties
3838

39-
- `hitArea` — determines where mouse movement is tracked:
39+
- `hitArea` — determines where mouse movement is tracked. **Omitting it behaves as `'root'`**: only an explicit `'self'` scopes tracking to the source element.
4040
- `'self'` — tracks pointer within the source element's bounds only. Use for local pointer-tracking effects on a specific element.
41-
- `'root'` — tracks pointer anywhere in the viewport. Use for global cursor followers, ambient effects.
41+
- `'root'` (default) — tracks pointer anywhere in the viewport. Use for global cursor followers, ambient effects.
4242
- `axis` — restricts pointer tracking to a single axis. Used with `keyframeEffect` to map one axis to 0–1 progress; ignored by `namedEffect` and `customEffect` which receive the full 2D progress:
4343
- `'x'` — maps horizontal pointer position to 0–1 progress for keyframe interpolation.
4444
- `'y'` — maps vertical pointer position to 0–1 progress for keyframe interpolation. **Default** when `keyframeEffect` is used.
@@ -69,7 +69,9 @@ type Progress = {
6969
Controls which element's bounds define the 0–1 progress range.
7070

7171
- **`false` (default)**: Progress is calculated against the **source element's** (or viewport's) bounds. The `50%` progress of the timeline is at the center of the source element.
72-
- **`true`**: `50%` progress of the timeline is calculated against the **target element's center**. The edges of the timeline are still calculated against the edges of the source element/viewport depending on `hitAea`.
72+
- **`true`**: `50%` progress of the timeline is calculated against the **target element's center**. The edges of the timeline are still calculated against the edges of the source element/viewport depending on `hitArea`.
73+
74+
**Applies to `namedEffect` and `customEffect` only.** Centering needs a resolved target, and a `keyframeEffect` scrub scene resolves none — set it there and it is silently ignored.
7375

7476
---
7577

@@ -118,9 +120,7 @@ Use pre-built mouse presets from `@wix/motion-presets` that handle 2D mouse trac
118120
type: '[NAMED_EFFECT_TYPE]',
119121
[EFFECT_PROPERTIES]
120122
},
121-
centeredToTarget: [CENTERED_TO_TARGET],
122-
transitionDuration: [TRANSITION_DURATION_MS],
123-
transitionEasing: '[TRANSITION_EASING]'
123+
centeredToTarget: [CENTERED_TO_TARGET]
124124
},
125125
// additional effects targeting other elements can be added here
126126
]
@@ -135,8 +135,8 @@ Use pre-built mouse presets from `@wix/motion-presets` that handle 2D mouse trac
135135
- `[NAMED_EFFECT_TYPE]` — a registered effect name, or a preset from `@wix/motion-presets` `mouse` library.
136136
- `[EFFECT_PROPERTIES]` — preset-specific options. Refer to motion-presets rules for each preset's available options and their value types. Do NOT guess preset option names or types; omit unknown options and rely on defaults.
137137
- `[CENTERED_TO_TARGET]``true` or `false`. See **Centering with `centeredToTarget`** above.
138-
- `[TRANSITION_DURATION_MS]` — optional number. Milliseconds for smoothing (interpolating) between progress updates. The animation does not jump to the new progress value instantly; instead it transitions over this duration. Use to add inertia/lag to the effect, making it feel more physical (e.g. `200``600`).
139-
- `[TRANSITION_EASING]` — optional string. CSS easing or named easing from `@wix/motion`. Adds a natural deceleration feel when used with `transitionDuration`.
138+
139+
> `transitionDuration` / `transitionEasing` are **not** available here. They are forwarded only for a `customEffect` payload (see Rule 4).
140140
141141
---
142142
@@ -160,9 +160,6 @@ Use `keyframeEffect` when the pointer position along a single axis should drive
160160
keyframes: [KEYFRAMES]
161161
},
162162
fill: 'both',
163-
centeredToTarget: [CENTERED_TO_TARGET],
164-
transitionDuration: [TRANSITION_DURATION_MS],
165-
transitionEasing: '[TRANSITION_EASING]',
166163
effectId: '[UNIQUE_EFFECT_ID]'
167164
},
168165
// additional effects targeting other elements can be added here
@@ -177,11 +174,10 @@ Use `keyframeEffect` when the pointer position along a single axis should drive
177174
- `[AXIS]``'x'` (horizontal) or `'y'` (vertical). Defaults to `'y'` when omitted.
178175
- `[EFFECT_NAME]` — unique string name for the keyframe effect.
179176
- `[KEYFRAMES]` — array of CSS keyframe objects (e.g. `[{ transform: 'rotate(-10deg)' }, { transform: 'rotate(0)' }, { transform: 'rotate(10deg)' }]`). Distributed evenly across 0–1 progress: first keyframe = progress 0 (left/top edge), last = progress 1 (right/bottom edge). Any number of keyframes is allowed.
180-
- `[CENTERED_TO_TARGET]` — optional. `true` or `false`. See **Centering with `centeredToTarget`** above. Defaults to `false`.
181-
- `[TRANSITION_DURATION_MS]` — optional. Milliseconds for smoothing between progress updates. See Rule 1 for details.
182-
- `[TRANSITION_EASING]` — optional. CSS easing string or named easing from `@wix/motion`. See Rule 1 for supported values.
183177
- `[UNIQUE_EFFECT_ID]` — optional string identifier.
184178
179+
> A `keyframeEffect` scrub scene resolves no target, so `centeredToTarget` is silently ignored here, and `transitionDuration` / `transitionEasing` are not forwarded either. All three apply only to the payloads noted in Rules 1 and 4. For smoothed, centered pointer motion use a mouse `namedEffect` or a `customEffect`.
180+
185181
---
186182
187183
## Rule 3: Two keyframeEffects with Two Axes and `composite`
@@ -211,19 +207,15 @@ Use two separate interactions on the same source/target pair — one for `axis:
211207
keyframes: [X_KEYFRAMES]
212208
},
213209
fill: '[FILL_MODE]', // usually 'both'
214-
composite: '[COMPOSITE_OPERATION]',
215-
transitionDuration: [TRANSITION_DURATION_MS],
216-
transitionEasing: '[TRANSITION_EASING]'
210+
composite: '[COMPOSITE_OPERATION]'
217211
},
218212
'[Y_EFFECT_ID]': {
219213
keyframeEffect: {
220214
name: '[Y_EFFECT_NAME]',
221215
keyframes: [Y_KEYFRAMES]
222216
},
223217
fill: '[FILL_MODE]', // usually 'both'
224-
composite: '[COMPOSITE_OPERATION]',
225-
transitionDuration: [TRANSITION_DURATION_MS],
226-
transitionEasing: '[TRANSITION_EASING]'
218+
composite: '[COMPOSITE_OPERATION]'
227219
}
228220
}
229221
}
@@ -238,8 +230,8 @@ Use two separate interactions on the same source/target pair — one for `axis:
238230
- `[X_KEYFRAMES]` / `[Y_KEYFRAMES]` — arrays of WAAPI keyframe objects for the X-axis and Y-axis effects respectively. Each effect can vary in propertise and keyframes.
239231
- `[COMPOSITE_OPERATION]``'add'` or `'accumulate'`. Required when both effects animate `transform` and/or both animate `filter`, so their values combine rather than override. `'add'`: composited transform functions are appended. `'accumulate'`: matching function arguments are summed.
240232
- `[FILL_MODE]` — typically `'both'` to ensure the effect keeps applying after exiting the effect's active range.
241-
- `[TRANSITION_DURATION_MS]` — optional. Milliseconds for smoothing between progress updates. See Rule 1 for details.
242-
- `[TRANSITION_EASING]` — optional. CSS easing function for the smoothing transition. See Rule 1 for supported values.
233+
234+
> As in Rule 2, `transitionDuration` / `transitionEasing` / `centeredToTarget` do not apply to a `keyframeEffect` payload.
243235
244236
---
245237

packages/interact/rules/viewprogress.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ For static sites, pre-render CSS via `generate()` at build time — see
6060
- `'cover'` — full visibility span from first pixel entering to last pixel leaving.
6161
- `'entry'` — the phase while the element is entering the viewport.
6262
- `'exit'` — the phase while the element is exiting the viewport.
63-
- `'contain'` — while the element is fully contained in the viewport. Typically used with a `position: sticky` container.
64-
- `'entry-crossing'` — from the element's leading edge entering to its leading edge reaching the opposite side.
65-
- `'exit-crossing'` — from the element's trailing edge reaching the start to its trailing edge leaving.
63+
- `'contain'` — while the element is fully contained by the viewport, or — for an element taller than the viewport — while it fully covers it. This is the phase a `position: sticky` child stays pinned, which is why it pairs with a sticky container.
64+
- `'entry-crossing'` — from the element's leading edge entering to its trailing edge entering.
65+
- `'exit-crossing'` — from the element's leading edge exiting to its trailing edge exiting.
6666
- `[START_PERCENTAGE]` — 0–100, starting point within the named range.
6767
- `[END_PERCENTAGE]` — 0–100, end point within the named range.
6868
- `[EASING_FUNCTION]` - CSS easing string or named easing from `@wix/motion`. Typically `'linear'` for scrolling effects.

0 commit comments

Comments
 (0)