Skip to content

Revisit Interact ruels#159

Open
ydaniv wants to merge 18 commits intomasterfrom
interact-revisit-rules
Open

Revisit Interact ruels#159
ydaniv wants to merge 18 commits intomasterfrom
interact-revisit-rules

Conversation

@ydaniv
Copy link
Collaborator

@ydaniv ydaniv commented Mar 15, 2026

Description

  • Refactor hover.md
  • Refactor click.md
  • Refactor viewprogress.md
  • Refactor viewenter.md
  • Refactor pointermove.md
  • Refactor integration.md
  • Removed scroll-list.md
  • Refactor full-lean.md

Copy link
Contributor

@ameerabuf ameerabuf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the direction, and it does seem to be the same information in much less text, but I do not feel comfortable removing so much without first testing to see there is no regression. We can use Monty's QA-flow on this branch or something like this...

Copy link
Contributor

@ameerabuf ameerabuf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

read click and hover. There were already quite a few comments, some are critical IMO, so I submit now and I will continue with the other triggers.

duration: [DURATION_MS],
easing: '[EASING_FUNCTION]',
fill: '[FILL_MODE]',
keyframeEffect: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

namedEffect?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a comment

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the comment is enough' it just creates a contradiction between the template and the text. Why not the same as in the first rule? maybe shorten it something like

// One of:
keyframeEffect: [KEYFRAME_EFFECT_DEF],
// Or
namedEffect: [NAMED_EFFECT_DEF],

- `[SOURCE_KEY]` — same as Rule 1.
- `[POINTER_TYPE]` — same as Rule 1.
- `[OFFSET_MS]` — time offset between each child's animation start, in milliseconds.
- `[OFFSET_EASING]` — easing curve for the stagger distribution (e.g. `'sineOut'`, `'linear'`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comment about the different easing format

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it? there is still does not reference motion like the others

{
key: 'hero',
trigger: 'viewEnter',
params: { type: 'once', threshold: 0.2 },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should keep the properties that are not fixed-value templated like in the rules (like threshold, duration, namedEffect), or with placeholder syntax like threshold: <threshold> instead of fixed values

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that you might not have pushed this fix then

{ opacity: '0', transform: 'translateY(-40px)' }
]
key: '[TARGET_KEY]',
customEffect: (element: Element, progress: number) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's at least make this whole rule match the time-based structure of the customEffect rule

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not following, looks fine

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there it is simply customEffect: [CUSTOM_EFFECT_CALLBACK] and the signature and explanation are in the variables section. There are many such mismatches everywhere since we insist on not pulling/copying it from a single source of truth

- `hitArea` — determines where mouse movement is tracked:
- `'self'` — tracks mouse within the source element's bounds only. Use for local hover effects.
- `'root'` — tracks mouse anywhere in the viewport. Use for global cursor followers, ambient effects.
- `axis` — restricts pointer tracking to a single axis. Only relevant when using `keyframeEffect`:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it really though? Do we know to ignore it with other types of effects?

- For controlling ongoing animations
- When users should be able to interrupt and resume animations
- For interactive media controls
**CRITICAL:** Always include `fill: 'both'` for `type: 'alternate'` or `'repeat'` — keeps the effect applied while finished and prevents garbage-collection, allowing efficient toggling. For `type: 'once'`, use `fill: 'backwards'` or `fill: 'none'`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For type: 'once', use fill: 'backwards' or fill: 'none' - could create bugs. Directing AI to use fill: 'none' on such animation could cause flickering. Also why not use fill: 'both'?
I think a sentence about the initial styling of the target element and how it corresponds to what fill-value to use might be more accurate here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use fill: both you prevent the animation from being GC'd.
Maybe we should set it to backwards for now

**CRITICAL:** Always include `fill: 'both'` for `type: 'alternate'` or `'repeat'` — keeps the effect applied while finished and prevents garbage-collection, allowing efficient toggling. For `type: 'once'`, use `fill: 'backwards'` or `fill: 'none'`.

**Pattern**:
**Multiple effects:** The `effects` array can contain multiple effects — all share the same click trigger and fire together. Use this to animate different targets from a single click event.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another example of something that is true for all trigger-types

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this was added later when I thought that the model isn't using this feature. Let's remove and keep the comment below

}
```
- `[SOURCE_KEY]` — identifier matching the element's key (`data-interact-key` for web, `interactKey` for React). The element that listens for clicks.
- `[TARGET_KEY]` — identifier matching the element's key on the element that animates. Same as `[SOURCE_KEY]` for self-targeting, or different for cross-targeting.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the second sentence is unnecessary. A more informative sentence for usage would be empty (undefined) to target the same element as the source or a different key for targeting another element.
Currently it just states something trivial, while in my suggestion it at least gives information about the syntax.

- `[SOURCE_KEY]` — identifier matching the element's key (`data-interact-key` for web, `interactKey` for React). The element that listens for clicks.
- `[TARGET_KEY]` — identifier matching the element's key on the element that animates. Same as `[SOURCE_KEY]` for self-targeting, or different for cross-targeting.
- `[EVENT_TRIGGER_TYPE]` — `PointerTriggerParams.type`. One of:
- `'alternate'` — plays forward on first click, reverses on next click. Most common for toggles.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

plays backwards on next click, and so on? Just a suggestion, maybe not that important

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's intentional. First trigger is play() and then it's reverse(). Think reversing a reversed animation.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's correct

- `'alternate'` — plays forward on first click, reverses on next click. Most common for toggles.
- `'repeat'` — restarts the animation from the beginning on each click.
- `'once'` — plays once on the first click and never again.
- `'state'` — resumes/pauses the animation on each click. Useful for continuous loops (`iterations: Infinity`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

another non-critical suggestion - plays/resumes on first click, pauses on the next click, and so on?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was corrected once by Claude, I think it's ok this way.

Comment on lines +186 to +198
// can be `selector` or `listContainer` for multiple effects, or a separate effect definitions with
{
// can be an inline Effect, or a reference to an effect defined in top level `effects` map
effectId: '[EFFECT_ID]',
listContainer: '[LIST_CONTAINER_SELECTOR]'
}
]
}
]
}
```

**Variables**:

- `[OFFSET_MS]`: Stagger offset in ms between consecutive effects (typically 100-200ms)
- `[OFFSET_EASING]`: Easing for stagger distribution — `'linear'`, `'quadIn'`, `'sineOut'`, etc.
- `[EFFECT_ID_N]`: Effect id from the effects registry for each element
- `[TARGET_KEY_N]`: Element key for each target
- Other variables same as Rule 1

**Example - Orchestrated Content Reveal**:

```typescript
{
key: 'reveal-button',
trigger: 'click',
params: {
type: 'alternate'
},
sequences: [
{
offset: 150,
offsetEasing: 'sineOut',
effects: [
{ effectId: 'heading-entrance', key: 'content-heading' },
{ effectId: 'body-entrance', key: 'content-body' },
{ effectId: 'image-entrance', key: 'content-image' }
]
}
]
}
```
Each `[EFFECT_ID]` must be defined in the top-level `effects` map of the `InteractConfig`:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is still very confusing and contradicting - I believe we can allow 2 templates for this rule to be more clear. A template using inline effects, and another using ids. I am not sure what to do about the confusion of the selectors, it might require another template.
I think that there is nothing that is click-specific here, and the better solution is to have sequences.md (possibly sequences-and-lists.md) and define the rules of usage with sequences there. It is not trigger-specific, and could get complicated and breaks because we are trying to minimize the context that explains it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is not to have in these rules ONLY stuff for this trigger. There is some expected overlap so that each rules file can also be used standalone

duration: [DURATION_MS],
easing: '[EASING_FUNCTION]',
fill: 'both',
// keyframeEffect or namedEffect
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comment do not match the object underneath and these kind of things are what confuses the LLM. We can change the object to be more general somehow or include both options with OR like in the first rule.

- Simple state toggles
- CSS custom property updates
- `[SOURCE_KEY]` / `[EVENT_TRIGGER_TYPE]` — same as Rule 1.
- `[OFFSET_MS]` — time offset between each child's animation start, in milliseconds.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mention 'stagger' as the LLM seemed to not do that connection by itself.

Comment on lines +218 to +219
- `[OFFSET_MS]` — time offset between each child's animation start, in milliseconds.
- `[OFFSET_EASING]` — easing curve for the stagger distribution.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a standard interface. I think a few words about how the delay is calculated should be here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's standard in other animation libraries, but improved a bit

- `[OFFSET_MS]` — time offset between each child's animation start, in milliseconds.
- `[OFFSET_EASING]` — easing curve for the stagger distribution.
- `[EFFECT_ID]` — string key referencing an entry in the top-level `effects` map. Same concept as `[UNIQUE_EFFECT_ID]` in Rule 1.
- `[LIST_CONTAINER_SELECTOR]` — CSS selector for the container whose direct children will be staggered.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here is our problem - not given as optional.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should just replace the whole object with a single placeholder that implies to just use an effect


**Pattern**:
- `[SOURCE_KEY]` (interaction `key`) — a stable wrapper element that receives the mouse events.
- `[TARGET_KEY]` (effect `key` or `selector`) — the inner element that actually animates.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or selector?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I understand what you mean but that is not so clear from the sentence. You mean that targeting a different element could be used be either giving a different key to the effect or no key and a selector that target an inner element. This is not clear from that sentence and rather seems like there is a single variable TARGET_KEY that could either be a key or a selector and that does not work with the templates below.
I can imagine a scenario of an agent just placing selectors in the key field due to that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, rephrased

Use `keyframeEffect` or `namedEffect` when the hover should play an animation (CSS or WAAPI). Pair with `PointerTriggerParams` to control playback behavior.

**Purpose**: Hover interactions that play forward on mouse enter and reverse on mouse leave (`type: 'alternate'`).
**CRITICAL:** Always include `fill: 'both'` for `type: 'alternate'`, `'repeat'` — keeps the effect applied while hovering and prevents garbage-collection. For `type: 'once'`, use `fill: 'backwards'` or `fill: 'none'`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be missing something but - type: 'once'+fill: 'none' can only work if the animation's first and last frames are the same and basically apply no transformations? I cannot see how there is no "jump" in any other case

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

iterations: [ITERATIONS],
alternate: [ALTERNATE_BOOL]
},
// additional effects targeting other elements can be added here
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be a nit-pick for now, but could also be additional effects on the same target for composition, but maybe leave it like that for now

Comment on lines +131 to +132
- `'remove'` — removes a previously applied style state on enter.
- `'clear'` — clears all previously applied style states on enter. Useful for resetting multiple stacked style state changes at once.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also here I think the use-case should be made clear


**Purpose**: Hover interactions that stagger animations across multiple targets using a sequence instead of manual delays.
- `[SOURCE_KEY]` / `[TARGET_KEY]` / `[EVENT_TRIGGER_TYPE]` — same as Rule 1.
- `[CUSTOM_EFFECT_CALLBACK]` — function with signature `(element: HTMLElement, progress: number) => void`. Called on each animation frame with `progress` from 0 to 1.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

target element (not source).
Maybe we could just do (target: HTMLElement, progress: number) => void

duration: [DURATION_MS],
easing: '[EASING_FUNCTION]',
fill: '[FILL_MODE]',
keyframeEffect: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the comment is enough' it just creates a contradiction between the template and the text. Why not the same as in the first rule? maybe shorten it something like

// One of:
keyframeEffect: [KEYFRAME_EFFECT_DEF],
// Or
namedEffect: [NAMED_EFFECT_DEF],

- `[SOURCE_KEY]` — same as Rule 1.
- `[POINTER_TYPE]` — same as Rule 1.
- `[OFFSET_MS]` — time offset between each child's animation start, in milliseconds.
- `[OFFSET_EASING]` — easing curve for the stagger distribution (e.g. `'sineOut'`, `'linear'`).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it? there is still does not reference motion like the others

- `[OFFSET_MS]` — time offset between each child's animation start, in milliseconds.
- `[OFFSET_EASING]` — easing curve for the stagger distribution (e.g. `'sineOut'`, `'linear'`).
- `[EFFECT_ID]` — string key referencing an entry in the top-level `effects` map. Same concept as `[UNIQUE_EFFECT_ID]` in Rule 1.
- `[LIST_CONTAINER_SELECTOR]` — CSS selector for the container whose direct children will be staggered.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again - optional. And the way to use sequence without it is not clear from this rule


### Hit Area Configuration (`hitArea`)
- The source element **MUST NOT** have `pointer-events: none` — it needs to receive pointer events.
- **MUST AVOID** using the same element as both source and target with effects that change size or position (e.g. `transform: translate(…)`, `scale(…)`). The transform shifts the hit area, causing jittery re-entry cycles. Instead, use `selector` to target a child element for the animation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a much more clear explanation of how to use selector maybe copy some of it to hover?

- `axis` — restricts pointer tracking to a single axis. Only relevant when using `keyframeEffect`:
- `'x'` — maps horizontal pointer position to 0–1 progress for keyframe interpolation.
- `'y'` — maps vertical pointer position to 0–1 progress for keyframe interpolation. **Default** when `keyframeEffect` is used.
- When omitted with `namedEffect` or `customEffect`, both axes are available via the 2D progress object.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it have to be ommited? what happens if namedEffect or customEffect are used with axis? is it ignored?

---

## Rule 9: Multi-Element Custom Parallax with customEffect
For devices with dynamic viewport sizes (e.g. mobile browsers where the address bar collapses), consider using viewport-relative units carefully and prefer `lvh`/`svh` over `dvh` unless dynamic viewport behavior is specifically desired.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess Claude did not entirely understand me there, though this is also not a bad advice for keyframeEffects here. This was meant to be added in viewProgress.md in a section parallel to this one (## Device Conditions).

- `[SOURCE_KEY]` — identifier matching the element's key (`data-interact-key` for web, `interactKey` for React). The element that tracks mouse movement.
- `[TARGET_KEY]` — identifier matching the element's key on the element to animate. Can be the same as source, or different when separating hit area from animation target.
- `[HIT_AREA]` — `'self'` (mouse within source element) or `'root'` (mouse anywhere in viewport).
- `[NAMED_EFFECT_TYPE]` — preset name from `@wix/motion-presets` mouse category:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow this is extensive and unlike the other triggers. I guess Claude misunderstood my comment above too. This seems like an overkill - let's reference to motion-presets if that is what we are intending to go with. If not, let's put such a list for every trigger.

- Refer to motion-presets rules for detailed options of each preset. Do NOT guess preset option names/types; omit unknown options and rely on defaults.
- `[CENTERED_TO_TARGET]` — `true` or `false`. See **Centering with `centeredToTarget`** above.
- `[TRANSITION_DURATION_MS]` — optional. Milliseconds for smoothing between progress updates. Adds inertia to the effect.
- `[TRANSITION_EASING]` — optional. Easing for the smoothing transition (e.g., `'easeOut'`). Adds a natural deceleration feel.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format of the easing should be clear. If it follows some standard easing names, reference this standard.

const visibleText = text.substring(0, visibleLength);
element.textContent = visibleText + (progress < 1 ? '|' : '');
- `[SOURCE_KEY]` — identifier matching the element's key (`data-interact-key` for web, `interactKey` for React). The element whose scroll position drives the animation.
- `[TARGET_KEY]` — identifier matching the element's key on the element to animate (can be same as source or different).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suddenly no word about data-interact-key, interactKey (+1 for single unified variables JSON)

- `'cover'` — full visibility span from first pixel entering to last pixel leaving.
- `'entry'` — the phase while the element is entering the viewport.
- `'exit'` — the phase while the element is exiting the viewport.
- `'contain'` — while the element is fully contained in the viewport. Typically used with a `position: sticky` container.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's leav it like that for now, but unfortunately it is not as simple as that. Things change here for "tall" elements

{ opacity: '0', transform: 'translateY(-40px)' }
]
key: '[TARGET_KEY]',
customEffect: (element: Element, progress: number) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there it is simply customEffect: [CUSTOM_EFFECT_CALLBACK] and the signature and explanation are in the variables section. There are many such mismatches everywhere since we insist on not pulling/copying it from a single source of truth

key: 'orchestrated-section',
key: '[TALL_WRAPPER_KEY]',
trigger: 'viewProgress',
conditions: ['[CONDITION_NAME]'], // optional
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

irrelevant

Comment on lines +123 to +124
// Use keyframeEffect, namedEffect, or customEffect as in Rules 1–2
keyframeEffect: { name: '[EFFECT_NAME]', keyframes: [EFFECT_KEYFRAMES] },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then let's not write a template of a keyframeEffect, it is just confusing

Comment on lines +151 to +152
listContainer?: string; // CSS selector for a list container
listItemSelector?: string; // optional — CSS selector to filter which children of listContainer are selected
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A suggestion for future design change - models might get less confuse if these were separated from the rest - something like

listSelectors?: {
   container: string;
   item?: string;
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, I actually wanted to keep it as flat as possible. Also, if it's just 2 properties then not worth it yet. We can consider.

Comment on lines +165 to +167
**Most common**: Omit `selector`/`listContainer`/`listItemSelector` entirely — the element with the matching key is used as both source and target. Use `selector` to target a child element within the keyed element. Use `listContainer` for staggered sequences across list items.

Generates critical CSS styles that prevent flash-of-unstyled-content (FOUC) for elements with `viewEnter` entrance animations.
`listItemSelector` is **optional** — only use it when you need to **filter** which children of `listContainer` participate (e.g. select only `.active` items). When omitted, all immediate children of the `listContainer` are selected.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, I think the rules in the trigger-files that refer to list-selectors should just refer to integration.md instead for context on how it works

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to avoid chaining files

key: string; // REQUIRED — matches data-interact-key / interactKey
trigger: TriggerType; // REQUIRED — trigger type
params?: TriggerParams; // trigger-specific parameters
selector?: string; // CSS selector to refine target within the element
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is confusing - isn't that selector supposed to be on the effect-level? If not, then do all selectors on the interaction-level actually refer to the target and not the source?

Comment on lines +171 to +175
1. **`listContainer` + `listItemSelector`** — matches only the elements matching `listItemSelector` within the container (filtering).
2. **`listContainer` only** — targets all immediate children of the container (common case).
3. **`listContainer` + `selector`** — matches via `querySelector` within each immediate child of the container.
4. **`selector` only** — matches via `querySelectorAll` within the root element.
5. **Fallback** — first child of `<interact-element>` (web) or the root element (react/vanilla).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these on the interaction level used for the target resolving? How does it work with multiple effects on multiple targets?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's missing separate text for source and target that's used in full-lean. I'll copy from there.

| `click` | Mouse click | Same as `hover` | [click.md](./click.md) |
| `interest` | Accessible hover (hover + focus) | Same as `hover` | [hover.md](./hover.md) |
| `activate` | Accessible click (click + Enter/Space) | Same as `click` | [click.md](./click.md) |
| `viewEnter` | Element enters viewport | `type?`: same values as hover; `threshold?`: 0–1; `inset?`: CSS length as strin for viewport margin | [viewenter.md](./viewenter.md) |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| `viewEnter` | Element enters viewport | `type?`: same values as hover; `threshold?`: 0–1; `inset?`: CSS length as strin for viewport margin | [viewenter.md](./viewenter.md) |
| `viewEnter` | Element enters viewport | `type?`: same values as hover; `threshold?`: 0–1; `inset?`: CSS length as string for viewport margin | [viewenter.md](./viewenter.md) |

Comment on lines +584 to +590
The source element is what the trigger attaches to. Resolved in priority order:

1. **`listContainer` + `listItemSelector`** — trigger attaches to each element matching `listItemSelector` within the `listContainer`. Use `listItemSelector` only when you need to **filter** which children participate (e.g. select only `.active` items). If all immediate children should participate, omit `listItemSelector`.
2. **`listContainer` only** — trigger attaches to each immediate child of the container. This is the common case for lists.
3. **`listContainer` + `selector`** — trigger attaches to the element found via `querySelector` within each immediate child of the container.
4. **`selector` only** — trigger attaches to all elements matching `querySelectorAll` within the root `<interact-element>`.
5. **Fallback** — first child of `<interact-element>` (web) or the root element (react/vanilla).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It speaks here about the source-resolution while in other places the same segment talks about target-resolution. It is unclear whether these apply to the trigger or the target

The target element is what the effect animates. Resolved in priority order:

1. **`Effect.key`** — the `<interact-element>` with matching `data-interact-key`.
2. **Registry Effect's `key`** — if the effect is an `EffectRef`, the `key` from the referenced registry entry is used.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion for future design - effects in the registry should not have keys, it makes no sense. If they are reusable effect definitions they should be target-less IMO.


1. **`Effect.key`** — the `<interact-element>` with matching `data-interact-key`.
2. **Registry Effect's `key`** — if the effect is an `EffectRef`, the `key` from the referenced registry entry is used.
3. **Fallback to `Interaction.key`** — the source element acts as the target.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to the key or to the resolved source element? (those are not necessarily the same)

1. **`Effect.key`** — the `<interact-element>` with matching `data-interact-key`.
2. **Registry Effect's `key`** — if the effect is an `EffectRef`, the `key` from the referenced registry entry is used.
3. **Fallback to `Interaction.key`** — the source element acts as the target.
4. After resolving the root target, `selector`, `listContainer`, and `listItemSelector` on the effect further refine which child elements within that target are animated (same priority order as source resolution).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only place it becomes clear that these could exist on both interaction and effect level. We need to find a way to make this general and less confusing

| `Interact.destroy()` | Tear down all instances. Call on unmount or route change to prevent memory leaks. |
| `Interact.forceReducedMotion` | `boolean` (default: `false`) — force reduced-motion behavior regardless of OS setting. |
| `Interact.allowA11yTriggers` | `boolean` (default: `false`) — enable accessibility trigger variants (`interest`, `activate`). |
| `Interact.setup(options)` | Configure global thresholds and observer options for scroll, pointer, and viewEnter systems. Call before `create`. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what are the options? when should one use it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants