feat(relatedProducts): add RelatedProducts to Vue + hook-based UI infra - #7127
feat(relatedProducts): add RelatedProducts to Vue + hook-based UI infra#7127Haroenv wants to merge 3 commits into
Conversation
… UI infra Ports the RelatedProducts widget to vue-instantsearch, and adds the shared vue-compat infrastructure needed to consume hook-driven `instantsearch-ui-components` factories from Vue. Infra (`src/util/vue-compat`, `src/util/hooks.js`): - `createHooksStore`: a React-style hooks runtime (useState/useEffect/useRef/ useMemo/useCallback/useId) driven by a Vue component's render cycle. - `augmentReactCreateElement` + `renderReactCompat`: a createElement that maps React-style props (`className`, `onX` handlers, `ref` MutableRefs) onto Vue's `h`, for both Vue 2 (vnode insert/destroy hooks) and Vue 3 (function refs). - A plain-function `Fragment` shared by both versions (the native Vue 3 Fragment adds whitespace/anchor nodes that break shared snapshots). Widgets: - `AisRelatedProducts` wraps `connectRelatedProducts` and renders the shared component; default list layout passes the common suite, plus an opt-in `layout="carousel"`. - `AisCarousel` (internal) renders the shared Carousel with its own hooks store. This is the pilot proving the approach before porting the hook-heavy Autocomplete widget. Works on Vue 2 and Vue 3. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 116 |
TIP This summary will be updated as you push new changes.
More templates
algoliasearch-helper
instantsearch-ui-components
instantsearch.css
instantsearch.js
react-instantsearch
react-instantsearch-core
react-instantsearch-nextjs
react-instantsearch-router-nextjs
vue-instantsearch
commit: |
There was a problem hiding this comment.
Pull request overview
Ports the RelatedProducts recommend widget into vue-instantsearch and introduces Vue 2/3 “react-compat” infrastructure (hooks runtime + React-style createElement adapter) so Vue can consume hook-driven factories from instantsearch-ui-components (e.g. Carousel now, Autocomplete/Chat next).
Changes:
- Added a minimal React/Preact-style hooks runtime (
createHooksStore) driven by Vue’s render cycle. - Added Vue 2/3 “React-style” renderer helpers (
Fragment,augmentReactCreateElement,renderReactCompat) to bridgeclassName,onXevents, and MutableRef-styleref. - Implemented
AisRelatedProducts+ internalAisCarousel, enabled the RelatedProducts common test suite for Vue, and documented the new infra.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| packages/vue-instantsearch/src/widgets.js | Exposes AisRelatedProducts from the Vue public widgets entrypoint. |
| packages/vue-instantsearch/src/util/vue-compat/index-vue3.js | Adds Vue 3 react-compat helpers: Fragment, React-style createElement, and renderReactCompat. |
| packages/vue-instantsearch/src/util/vue-compat/index-vue2.js | Adds Vue 2 react-compat helpers: Fragment, React-style createElement with vnode-hook ref bridging, and renderReactCompat. |
| packages/vue-instantsearch/src/util/hooks.js | Introduces createHooksStore (useState/useEffect/useRef/useMemo/useCallback/useId) to run hook-driven shared logic under Vue. |
| packages/vue-instantsearch/src/util/tests/hooks.test.js | Unit tests for the hooks runtime behavior (state, effects, memo/ref, cleanup). |
| packages/vue-instantsearch/src/util/tests/autocompletePropGetters.poc.test.js | PoC regression test driving the real createAutocompletePropGetters through the new infra. |
| packages/vue-instantsearch/src/components/RelatedProducts.js | New AisRelatedProducts Vue widget rendering the shared UI component with optional carousel layout. |
| packages/vue-instantsearch/src/components/Carousel.js | New internal Vue wrapper around the shared hook-driven Carousel component (owns its own hooks store). |
| packages/vue-instantsearch/src/components/tests/RelatedProducts.js | New component-level tests for default list layout and carousel (hooks + refs + events). |
| packages/vue-instantsearch/src/tests/index.js | Updates component enumeration test setup to provide required objectIDs prop. |
| packages/vue-instantsearch/src/tests/common-widgets.test.js | Enables RelatedProducts common widget suite in Vue (removes previous “not supported” stub). |
| packages/vue-instantsearch/CLAUDE.md | Documents how to consume hook-based shared components in Vue using the new infra. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- lint: fix import order in hooks.test.js (oxlint import-js/order).
- Codacy: replace the `/^on[A-Z]/` regex in `isEventProp` with a charCode
check to avoid the ReDoS false-positive (the pattern was already constant
and anchored).
- review (Copilot): map `value`/`checked` to `domProps` in the Vue 2
react-compat adapter so controlled form fields from shared TSX (e.g.
`<input value={query} />` in AutocompleteSearch) stay in sync across
rerenders. Vue 3 already handles these as DOM props via flat props.
- bundlesize: bump the Vue 2/3 UMD and Vue 3 CJS thresholds to account for
the new widget + hook-based UI infrastructure.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Pushed abd94cc addressing the CI + review feedback:
All 🤖 Generated with Claude Code |
The connector types `fallbackParameters` as `PlainSearchParameters` (an object), so the Vue prop should be `Object`. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What & why
This is a pilot that ports the RelatedProducts widget to
vue-instantsearchand, in doing so, builds the sharedvue-compatinfrastructure required to consume hook-driveninstantsearch-ui-componentsfactories from Vue.Motivation: the graduated Autocomplete widget (and Chat) don't live in Vue because their interaction logic is a React/Preact-hooks controller (
createAutocompletePropGetters) that Vue can't consume natively — Vue has only ever consumed stateless shared markup. Rather than validate that on the 1,400-line Autocomplete directly, this proves the approach on the smallest shared component that needs the same three pieces (hooks runtime + event forwarding + ref forwarding): the Carousel layout used by the recommend widgets (which are all currently missing from Vue).What's in here
Shared infra (
src/util/hooks.js,src/util/vue-compat/):createHooksStore— a React-style hooks runtime (useState/useEffect/useRef/useMemo/useCallback/useId) driven by a Vue component's render cycle via$forceUpdate.augmentReactCreateElement+renderReactCompat— acreateElementmapping React-style props (className,onClick/onKeyDown,ref={mutableRef}) onto Vue'sh, for Vue 2 (vnodeinsert/destroyhooks) and Vue 3 (function refs).Fragmentshared by both versions.Widgets:
AisRelatedProducts— wrapsconnectRelatedProducts, renders the shared UI component. Default list layout passes the existing common suite; opt-inlayout="carousel".AisCarousel(internal) — renders the shared Carousel with its own hooks store (per-component hook context, safe for conditional mounting).Docs: a
vue-instantsearch/CLAUDE.mdsection documenting how to consume hook-based shared components.Test plan
RelatedProductscommon suite unskipped and passing (Vue 2 and Vue 3).hooks.test.js(runtime),autocompletePropGetters.poc.test.js(drives the real Autocomplete controller through the infra as forward-looking regression coverage),RelatedProducts.js(list + carousel; the carousel test exercisesuseState+ refs + events together).vue-instantsearchsuite green on both Vue versions; oxlint + prettier clean.Notes / open questions for review
AisCarouselis intentionally not exported as a publicAis*widget (it's an internal layout, like the Reactcomponents/Carousel). Happy to expose it if preferred.autocompletePropGetters.poc.test.jsis kept as infra-validation coverage — it proves the shared Autocomplete controller runs under Vue. Can be removed if it reads as premature.Draft: opening early to align on the infra approach before the Autocomplete port.
🤖 Generated with Claude Code