Skip to content

feat(relatedProducts): add RelatedProducts to Vue + hook-based UI infra - #7127

Draft
Haroenv wants to merge 3 commits into
masterfrom
feat/vue-related-products
Draft

feat(relatedProducts): add RelatedProducts to Vue + hook-based UI infra#7127
Haroenv wants to merge 3 commits into
masterfrom
feat/vue-related-products

Conversation

@Haroenv

@Haroenv Haroenv commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What & why

This is a pilot that ports the RelatedProducts widget to vue-instantsearch and, in doing so, builds the shared vue-compat infrastructure required to consume hook-driven instantsearch-ui-components factories 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 — a createElement mapping React-style props (className, onClick/onKeyDown, ref={mutableRef}) onto Vue's h, for Vue 2 (vnode insert/destroy hooks) and Vue 3 (function refs).
  • A plain-function Fragment shared by both versions.

Widgets:

  • AisRelatedProducts — wraps connectRelatedProducts, renders the shared UI component. Default list layout passes the existing common suite; opt-in layout="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.md section documenting how to consume hook-based shared components.

Test plan

  • RelatedProducts common suite unskipped and passing (Vue 2 and Vue 3).
  • New tests: 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 exercises useState + refs + events together).
  • Full vue-instantsearch suite green on both Vue versions; oxlint + prettier clean.

Notes / open questions for review

  • AisCarousel is intentionally not exported as a public Ais* widget (it's an internal layout, like the React components/Carousel). Happy to expose it if preferred.
  • autocompletePropGetters.poc.test.js is kept as infra-validation coverage — it proves the shared Autocomplete controller runs under Vue. Can be removed if it reads as premature.
  • Next step (separate PR): the full Autocomplete port, which reuses this infra.

Draft: opening early to align on the infra approach before the Autocomplete port.

🤖 Generated with Claude Code

… 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>
@codacy-production

codacy-production Bot commented Jul 22, 2026

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues 0 issues

Results:
0 new issues

View in Codacy

🟢 Metrics 116 complexity

Metric Results
Complexity 116

View in Codacy

TIP This summary will be updated as you push new changes.

@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown
More templates

algoliasearch-helper

npm i https://pkg.pr.new/algolia/instantsearch/algoliasearch-helper@7127

instantsearch-ui-components

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch-ui-components@7127

instantsearch.css

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch.css@7127

instantsearch.js

npm i https://pkg.pr.new/algolia/instantsearch/instantsearch.js@7127

react-instantsearch

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch@7127

react-instantsearch-core

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-core@7127

react-instantsearch-nextjs

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-nextjs@7127

react-instantsearch-router-nextjs

npm i https://pkg.pr.new/algolia/instantsearch/react-instantsearch-router-nextjs@7127

vue-instantsearch

npm i https://pkg.pr.new/algolia/instantsearch/vue-instantsearch@7127

commit: 99c6f31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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 bridge className, onX events, and MutableRef-style ref.
  • Implemented AisRelatedProducts + internal AisCarousel, 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.

Comment thread packages/vue-instantsearch/src/util/vue-compat/index-vue2.js
- 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>
@Haroenv

Haroenv commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Pushed abd94cc addressing the CI + review feedback:

  • lint (CircleCI): fixed an import-order violation in hooks.test.js (oxlint import-js/order). yarn lint is now clean (0 errors).
  • Codacy: the flagged /^on[A-Z]/ "ReDoS" was a false positive (constant, anchored pattern over prop names), but I replaced it with a charCode check in isEventProp so the analyser is happy and the intent is clearer.
  • bundlesize: bumped the Vue 2/3 UMD and Vue 3 CJS thresholds — the increase is the new widget + the hook-based UI infrastructure (which the Autocomplete/Chat ports will reuse). Vue 2 CJS still fits the existing limit.
  • Copilot: routed value/checked to domProps in the Vue 2 adapter for controlled inputs (replied inline).

All vue-instantsearch suites remain green on Vue 2 and Vue 3.

🤖 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>
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