feat(autocomplete): add rich Autocomplete widget to Vue (phase 1)#7131
Draft
Haroenv wants to merge 4 commits into
Draft
feat(autocomplete): add rich Autocomplete widget to Vue (phase 1)#7131Haroenv wants to merge 4 commits into
Haroenv wants to merge 4 commits into
Conversation
Adds an `isolated` prop to `<ais-index>` (AisIndex), threaded through to the index widget's `isolated` option. `indexName` is no longer `required` because isolated indices don't need one — the underlying index widget validates that either `indexName` or `isolated` is provided. Vue never shipped the experimental `EXPERIMENTAL_isolated`, so only the stable `isolated` prop is exposed; no deprecated alias is needed here. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ports the graduated Autocomplete widget to vue-instantsearch, reusing the
hook-based UI infrastructure (createHooksStore + renderReactCompat) and the
already-validated `createAutocompletePropGetters` runtime.
- `AisAutocomplete` is a dispatcher preserving backward compatibility: with a
default slot it renders the (renamed) legacy headless `connectAutocomplete`
slot component unchanged; otherwise it renders the new rich widget.
- `AutocompleteWidget` (rich): registers the searchbox companion, renders the
required isolated `<AisIndex>` subtree (`<AisConfigure>` per source) and the
shared UI (search/panel/indices) via the prop getters. Bootstraps the
isolated index's first search by `setQuery`-ing its helper (mirrors the JS
widget) — the isolated index doesn't search on init by itself. Supports
`indices` + `showQuerySuggestions` in normal mode.
Vue-3 fixes surfaced by this widget (all in shared vue-compat/infra):
- The Vue 3 react-compat adapter dropped `class` when a component rendered
`<el className={..} {...props}>` with `props.class = undefined`; keep the
className-derived value (matches Vue 2).
- Pass stable (cached) `AisConfigure` attrs — a fresh object each render
re-registered the connector under Vue 3's deep watcher (infinite loop / OOM).
- The dispatcher forwards `$scopedSlots || $slots` (Vue 2 vs Vue 3).
- The inner renders its shell unconditionally (don't gate on `this.state`).
Phase 1 scope: indices + query suggestions, normal (non-detached) mode.
Detached mode, feeds, recent-search storage, prompt suggestions, AI mode and
lazy activation are follow-ups. Component tests cover the dispatcher (rich vs
legacy slot), the rich core (render, focus, type-to-results) and the headless
behavior. The shared common suite stays skipped pending an extension of its
`vue` widgetParams variant. Validated on Vue 2 and Vue 3.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Not up to standards ⛔🔴 Issues
|
| Category | Results |
|---|---|
| Security | 1 high |
🟢 Metrics 73 complexity
Metric Results Complexity 73
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: |
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds the graduated Autocomplete widget to vue-instantsearch by introducing a dispatcher-based AisAutocomplete (legacy headless slot API vs new rich widget), plus supporting infrastructure changes needed for Vue 3 compatibility and isolated indices.
Changes:
- Added a rich
AutocompleteWidgetimplementation for Vue, backed byconnectAutocomplete+ sharedinstantsearch-ui-componentsAutocomplete UI factories. - Introduced an
AisAutocompletedispatcher component to preserve the legacy headless slot API while making the rich widget the default. - Updated Vue infra and Index API to support isolated indices and improve Vue 3 react-compat behavior; added/updated component tests and common-widgets wiring.
Reviewed changes
Copilot reviewed 12 out of 14 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/vue-instantsearch/src/widgets.js | Re-points AisAutocomplete export to the new JS dispatcher entrypoint. |
| packages/vue-instantsearch/src/util/vue-compat/index-vue3.js | Fixes Vue 3 react-compat prop mapping for className/class interactions. |
| packages/vue-instantsearch/src/util/tests/createServerRootMixin.test.js | Updates SSR test to use the headless Autocomplete implementation directly. |
| packages/vue-instantsearch/src/components/Index.js | Exposes isolated prop and makes indexName optional to support isolated indices. |
| packages/vue-instantsearch/src/components/AutocompleteWidget.js | New rich Autocomplete widget (isolated <AisIndex> subtree + shared UI via prop getters). |
| packages/vue-instantsearch/src/components/AutocompleteHeadless.vue | New legacy headless Autocomplete component (slot-driven connectAutocomplete). |
| packages/vue-instantsearch/src/components/Autocomplete.js | New dispatcher component selecting headless vs rich implementation based on default slot presence. |
| packages/vue-instantsearch/src/components/tests/Index.js | Adds coverage for the new isolated prop behavior. |
| packages/vue-instantsearch/src/components/tests/AutocompleteWidget.js | Adds component tests for the rich Autocomplete widget. |
| packages/vue-instantsearch/src/components/tests/AutocompleteHeadless.js | Adds tests + snapshot coverage for the legacy headless component. |
| packages/vue-instantsearch/src/components/tests/Autocomplete.js | Adds dispatcher tests (rich default vs legacy slot behavior). |
| packages/vue-instantsearch/src/components/tests/snapshots/AutocompleteHeadless.js.snap | Snapshot for the new headless component output. |
| packages/vue-instantsearch/src/tests/common-widgets.test.js | Enables Autocomplete mount hook for common suite (suite itself remains skipped). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
90
to
+94
| if (name === 'className') { | ||
| data.class = value; | ||
| data.class = value || data.class; | ||
| } else if (name === 'class') { | ||
| // Shared components render `<el className={..} {...props}>` where props | ||
| // can carry a `class: undefined`; keep the className-derived value |
Comment on lines
+229
to
+231
| created() { | ||
| this.instanceKey = `ais-autocomplete-${(autocompleteInstanceId += 1)}`; | ||
| }, |
| this.usePropGetters({ | ||
| indices, | ||
| indicesConfig, | ||
| onRefine: (query) => refineAutocomplete(query), |
Comment on lines
+136
to
+140
| const inputProps = getInputProps(); | ||
| const searchBoxContent = h(AutocompleteSearchUi, { | ||
| inputProps: Object.assign({}, inputProps, { | ||
| onChange: (event) => refineAutocomplete(event.currentTarget.value), | ||
| }), |
Comment on lines
+656
to
+661
| render: renderCompat((h) => | ||
| h(AisInstantSearch, { props: instantSearchOptions }, [ | ||
| h(AisAutocomplete, { props: widgetParams }), | ||
| h(GlobalErrorSwallower), | ||
| ]) | ||
| ), |
Contributor
Author
CI notes
🤖 Generated with Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #7130 (Chat), and merges in #7126 (isolated index) which it hard-depends on. Merge order: #7127 → #7126 → #7130 → this (or retarget once the bases land).
What
Ports the graduated Autocomplete widget to
vue-instantsearch, reusing the hook-based infra (createHooksStore+renderReactCompat) and thecreateAutocompletePropGettersruntime already validated in earlier PRs.AisAutocompleteis a dispatcher that keeps the legacy headless API backward-compatible (per request): with a default slot it renders the renamedAutocompleteHeadless(connectAutocompleteslot component) unchanged; without a slot it renders the new rich widget.AutocompleteWidget(rich): registers the searchbox companion, renders the required isolated<AisIndex>subtree (a<AisConfigure>per source), and renders the shared UI (search / panel / indices) via the prop getters. It bootstraps the isolated index's first search bysetQuery-ing its helper — mirroring the JS widget (autocomplete.tsxL1434-1441); the isolated index doesn't search on init by itself. Supportsindices+showQuerySuggestionsin normal mode.Vue-3 issues this surfaced & fixed (shared infra)
Getting this working on Vue 3 exposed real gaps (the widget stresses the adapter far more than the recommend/chat widgets):
classwhen a component rendered<el className={..} {...props}>withprops.class = undefined— now keeps the className-derived value (Vue 2 already did).AisConfigureattrs must be stable — a fresh object each render re-registered the connector under Vue 3's stricter deep watcher (infinite loop → OOM).$scopedSlots || $slots(Vue 2 vs Vue 3).this.state.Test plan
vue-instantsearchsuite green on Vue 2 (589) and Vue 3 (583); oxlint + prettier clean.Scope / follow-ups (phase 2)
vuewidgetParams variant is extended to carryindices/showQuerySuggestions/templates.Draft, stacked.
🤖 Generated with Claude Code