# Changelog: @cludosearch/cludo-search-components 1.0.149

This changelog covers the changes between `@cludo/cludo-search-components` 1.0.63, published to GitHub Packages, and `@cludosearch/cludo-search-components` 1.0.149, published to npmjs. It starts with the migration steps for self-hosting customers, followed by what was added, changed and fixed, and the known issues in 1.0.149.

## Migrating from @cludo/cludo-search-components 1.0.63

The steps are ordered from the changes that affect every customer to those that affect only specific setups.

### 1. Package and registry

#### 1.1 The package has a new name and registry

- What changed: the package was renamed from `@cludo/cludo-search-components` to `@cludosearch/cludo-search-components` and is now published to the public npm registry (`https://registry.npmjs.org`) instead of GitHub Packages (#112).
- Who is affected: everyone.
- What to do: remove the old package, install the new one and rename every import. Installing no longer needs a GitHub login or token, so you can remove any `.npmrc` scope mapping for `@cludo` that you only needed for this package. Pin the version this changelog covers, because later releases contain changes that are not described here.

```sh
npm uninstall @cludo/cludo-search-components
npm install @cludosearch/cludo-search-components@1.0.149
```

```ts
// before
import { CludoWrapper } from "@cludo/cludo-search-components";
// after
import { CludoWrapper } from "@cludosearch/cludo-search-components";
```

#### 1.2 The API client types moved to `@cludosearch/cludo-api-client`

- What changed: the type declarations now reference `@cludosearch/cludo-api-client` instead of `@cludo/cludo-api-client` (#112). It is still only a development dependency of the library, and its interfaces are identical to the old package at 0.9.16.
- Who is affected: projects that installed `@cludo/cludo-api-client` to get full types.
- What to do: install `@cludosearch/cludo-api-client` instead.

```sh
npm uninstall @cludo/cludo-api-client
npm install --save-dev @cludosearch/cludo-api-client
```

### 2. Imports and require

#### 2.1 Load the package with `import`, not `require()`

- What changed: the package now declares an `exports` map with the entries `.`, `./ssr` and `./styles`, and the main entry moved from `dist/main.js` to `dist/csr/main.csr.js` (#143). The root entry defines only an `import` condition, so `require("@cludosearch/cludo-search-components")` fails in Node (`ERR_PACKAGE_PATH_NOT_EXPORTED`) and in webpack 5 ("Package path . is not exported"). See [Known issues in 1.0.149](#known-issues-in-10149).
- Who is affected: code that loads the package with `require()`, or that a bundler compiles to CommonJS `require`.
- What to do: switch to ESM `import`.

```ts
// before
const { initCludo } = require("@cludo/cludo-search-components");
// after
import { initCludo } from "@cludosearch/cludo-search-components";
```

#### 2.2 Paths inside `dist/` no longer resolve

- What changed: with the `exports` map in place, every `…/dist/…` path and `…/package.json` fail to resolve in both Node and webpack 5 (#143).
- Who is affected: anyone who deep-imported from `dist/`, for example `…/dist/main.js`, `…/dist/components/types/types` or `…/dist/types/theme-types`.
- What to do: import only from the root, `/ssr` or `/styles`. Types that were only reachable through `dist/` paths are not re-exported, so derive them from exported types instead, for example `React.ComponentProps<typeof ResultTitle>`.

```ts
// before
import { CludoSearchTheme } from "@cludo/cludo-search-components/dist/types/theme-types";
// after
import type { CludoSearchOptions } from "@cludosearch/cludo-search-components";
type Theme = NonNullable<CludoSearchOptions["theme"]>;
```

### 3. Styles

#### 3.1 Import the global stylesheet yourself

- What changed: importing the package no longer injects the global stylesheet (#126, #143). The stylesheet is injected at runtime only when `initCludo()` from the root entry is called with `cssTheme` set. `initCludo()` from the `/ssr` entry never injects it, even with `cssTheme` set. `initCludoWithPublicSettings()` never injects it either, so `CludoWrapper` with `publicSettings` gets no global CSS even when `cssTheme` is set. The stylesheet now ships as a file at `@cludosearch/cludo-search-components/styles`.
- Who is affected: everyone who does not call `initCludo` with `cssTheme`, everyone who imports from `@cludosearch/cludo-search-components/ssr`, everyone who uses `CludoWrapper` with `publicSettings`, and everyone who builds their own markup with the hooks and relies on the `.cludo-*` utility classes. Several of these classes are hard-coded in component markup, for example on the pagination list and the results wrapper, and have no effect without the stylesheet. The stylesheet also hides the CoreJs "back to top" button, so that button reappears without it.
- What to do: import the stylesheet once in your app, and make sure your bundler keeps the import (3.2).

```ts
// before: nothing needed, the styles came with the JS import
import { CludoWrapper } from "@cludo/cludo-search-components";
// after
import { CludoWrapper } from "@cludosearch/cludo-search-components";
import "@cludosearch/cludo-search-components/styles";
```

#### 3.2 Mark CSS as a side effect in webpack

- What changed: the package declares `"sideEffects": false`, which also covers the stylesheet. A webpack 5 production build drops `import "@cludosearch/cludo-search-components/styles"` unless the CSS rule marks CSS as a side effect. See [Known issues in 1.0.149](#known-issues-in-10149).
- Who is affected: webpack consumers whose CSS rule does not set `sideEffects: true`.
- What to do: add `sideEffects: true` to your CSS rule, or load a copy of `dist/ssr/styles.css` with a `<link>` tag.

```js
// webpack.config.js
{ test: /\.css$/i, use: ["style-loader", "css-loader"], sideEffects: true }
```

### 4. Removed or renamed props and changed types

#### 4.1 `ResultLink.autofocus` is now `shouldBeFocused`

- What changed: the prop was renamed (#149). The old prop focused the link once on mount. The new one refocuses whenever it is true and the query or page changes.
- Who is affected: custom templates that pass `autofocus` to `ResultLink`.
- What to do: rename the prop.

```tsx
// before
<ResultLink autofocus />
// after
<ResultLink shouldBeFocused />
```

#### 4.2 `ResultBreadcrumbs.breadcrumbDelimiter` is now `separator`

- What changed: the prop was renamed, and the default changed from `" > "` to a `/` in a `<span className="cludo-px-1">`.
- Who is affected: anyone who passes `breadcrumbDelimiter`, or who wants to keep the old `" > "` look.
- What to do: rename the prop, and pass `separator=" > "` to keep the old look.

```tsx
// before
<ResultBreadcrumbs breadcrumbDelimiter=" › " />
// after
<ResultBreadcrumbs separator=" › " />
```

#### 4.3 `SearchInput.ariaLabel` was removed

- What changed: the `aria-label` of `SearchInput` now defaults to the `search_input_label` translation string.
- Who is affected: anyone who passes `ariaLabel` to `SearchInput`. In JavaScript the prop is silently ignored, and in TypeScript it no longer type-checks.
- What to do: remove the prop. To change the label everywhere, override the `search_input_label` translation string. To change it for one instance, set it through `attributes.input`, which is applied after the default.

```tsx
// before
<SearchInput ariaLabel="Search the site" />
// after
<SearchInput attributes={{ input: { "aria-label": "Search the site" } }} />
```

#### 4.4 `theme.loadingImagePath` was removed

- What changed: `CludoSearchOptions.theme.loadingImagePath`, which set the CoreJs loading image, was removed. `ResultsList` now shows its own `StandardLoader` while loading.
- Who is affected: anyone who sets `loadingImagePath`.
- What to do: remove the option, and style the CoreJs loading state yourself or render your own loader.

#### 4.5 `ResultItemBaseProps` no longer includes the theme props

- What changed: `ResultItemBaseProps` changed from `ThemeBaseProps & { result: TypedDocument }` to `{ result: TypedDocument, shouldBeFocused?: boolean }`.
- Who is affected: custom result templates typed with `ResultItemBaseProps` that read `props.className` or `props.disableTheme`.
- What to do: add those fields to your own props type.

```ts
// after
type MyResultProps = ResultItemBaseProps & { className?: string; disableTheme?: boolean };
```

#### 4.6 Result helpers return `undefined` for missing fields

- What changed: `getFieldValue`, `getFieldValues` and `getHighlightsOrValues` now return `undefined` for a missing field instead of the text `'MISSING FIELD'` (`['MISSING FIELD']` for `getFieldValues`), and their return types include `undefined`. `getHighlightsOrValuesArray` returns `['']` for a missing field. With `maxWords` and no `wordDelim`, `getFieldValue` now splits on any run of whitespace (#147). With `maxWords` on highlighted fields, `getHighlightsOrValues` and `getHighlightsOrValuesArray` now cut the fragment that crosses the limit at the exact word count instead of dropping it, and collapse whitespace in the fragments they keep (#147). The built-in `ResultUrl`, `ResultDescription` and `ResultTitle` render nothing when their field is missing, where they previously rendered the text "MISSING FIELD". `ResultBadge` and `ResultImage` already rendered nothing.
- Who is affected: custom templates that compare against `'MISSING FIELD'`, that assume a string is always returned, or that index or iterate the result of `getFieldValues`, which now throws for a missing field.
- What to do: check for a falsy value instead.

```ts
// before
if (getFieldValue(result, "Category") !== "MISSING FIELD") { … }
const firstTag = getFieldValues(result, "Tags")[0];
// after
const category = getFieldValue(result, "Category");
if (category) { … }
const firstTag = (getFieldValues(result, "Tags") ?? [])[0];
```

#### 4.7 Some types widened or gained required fields

- What changed: the items below.
  - `CludoSearchOptions.components.results`, `.controls` and `.autocomplete` widened from `React.ComponentType` to `React.ComponentType | CustomComponentConfig` (#136).
  - `ExternalFacet`, the type of `CludoFacetBaseProps.facet` and `CludoControlsBaseProps.facets`, gained the required field `selectedValues: string[]`.
  - `AutocompleteDispatchers` gained the required `restoreInstantSuggestions`, and `autocompleteSelect` changed from `() => void` to `(e?) => void`.
  - `injectCoreScript` changed from `()` to `(overrideCoreScriptUrl?: string)`, which is source-compatible.
- Who is affected: TypeScript code that reads the `components` fields back as a component type, hand-built facet objects in tests or fixtures, and hand-built dispatcher objects passed to `autocompleteHandleInputBlur`, `autocompleteHandleInputChange` or `autocompleteHandleInputKeyDown`.
- What to do: add a narrowing check where you read the `components` fields, add `selectedValues` to hand-built facets, and implement `restoreInstantSuggestions` on hand-built dispatchers.

### 5. Markup and CSS

#### 5.1 Theme variable values changed

- What changed: in `.cludo-theme-basic`, the font sizes moved from `px` to `rem`, and two colours changed. The font sizes now scale with the host page's root font size.
- Who is affected: sites whose `html { font-size }` is not 16px, and sites that match the old colours.
- What to do: to keep the old sizes, redefine the variables. The library injects its theme rules at runtime, after your own styles, so use a more specific selector than `.cludo-theme-basic`.

| Variable | 1.0.63 | 1.0.149 |
|---|---|---|
| `--font-size-xs` | 10px | .6rem |
| `--font-size-sm` | 12px | .7rem |
| `--font-size-md` | 14px | .85rem |
| `--font-size-lg` | 16px | 1rem |
| `--font-size-xl` | 20px | 1.2rem |
| `--font-color-highlight` | #9E77ED | #6941C6 |
| `--bg-color-accent-primary-light` | #D0C3F1 | #e9e3f6 |

```css
html .cludo-theme-basic {
  --font-size-xs: 10px;
  --font-size-sm: 12px;
  --font-size-md: 14px;
  --font-size-lg: 16px;
  --font-size-xl: 20px;
}
```

#### 5.2 Theme composite rules changed

- What changed: no selectors were removed or renamed, but several composite rules have new values.
  - `.cludo-theme-result-title` is no longer bold, and its bottom margin changed from `--spacer-4` to `--spacer-3`.
  - `.cludo-theme-result-url` changed from bold to weight 500 and gained ellipsis and `nowrap`.
  - `.cludo-theme-result-badge` changed from `--font-size-xs` to `--font-size-sm`, from bold to weight 500, and has smaller padding.
  - `.cludo-theme-icon-btn-secondary` is no longer bold.
  - `.cludo-theme-facet-option` padding changed from `--spacer-1` to `--spacer-2`.
  - `.cludo-theme-current-facets` changed from `gray-medium` to `gray-light`, and its button hover from `gray-dark` to `gray-medium`.
  - `.cludo-theme-result-link` gained `padding-bottom` and `outline-offset: -1px`.
  - `.cludo-theme-results-list` gained a white background.
  - `.cludo-theme-searchbar` gained a font family.
- Who is affected: sites that use `cssTheme` or import the stylesheet and rely on the old look.
- What to do: review these components visually and override the rules you want to keep.

#### 5.3 Result titles show highlights by default

- What changed: `ResultTitle` now renders search-term highlights with `<b>` elements, uses normal font weight with only the highlighted words in bold, and adds the `cludo-font-weight-normal` theme class (#109).
- Who is affected: sites with custom CSS or tests for the result title text.
- What to do: pass `showRawText` to `ResultTitle` to get the old plain, bold title.

```tsx
<ResultTitle showRawText />
```

#### 5.4 Highlights render as `<b>`, and indexed HTML is no longer injected

- What changed: result titles, descriptions and fragment highlights no longer use `dangerouslySetInnerHTML` (#145). Only plain `<b>` highlight tags from the API are kept, and they render as `<b role="presentation none">`. Any other HTML in indexed fields, `<strong>` included, shows as visible text. In search-as-you-type items, highlights render as `<b role="presentation none">` instead of `<strong role="presentation none">`.
- Who is affected: CSS that targets `strong` inside autocomplete, and sites that relied on HTML in indexed fields being rendered.
- What to do: update the selectors.

```css
/* before */
.search_autocomplete li strong { color: #0a58ca; }
/* after */
.search_autocomplete li b { color: #0a58ca; }
```

#### 5.5 `ResultsList` has a new structure

- What changed: `ResultsList` now renders banners above the list by default, where in 1.0.63 it did not render banners at all (#135). The theme class `cludo-theme-results-list` moved from the wrapper `<div>` to the `<ul>`, which also carries `role="list"` (#204, #218). The wrapper is now `div.cludo-position-relative` with your `className` and `classNames.root`, it has a visually hidden `aria-live` region before it, and a `.cludo-loader` overlay while loading.
- Who is affected: sites that render banners themselves, for example with `BannerGroup`, which now show them twice, and CSS that uses selectors such as `.cludo-theme-results-list > ul`.
- What to do: if you render banners yourself, pass `hideBanners` to `ResultsList`. Update the selectors.

```css
/* before */
.cludo-theme-results-list > ul > li { … }
/* after */
ul.cludo-theme-results-list > li { … }
```

#### 5.6 Other markup changes that can break custom selectors

- What changed: the elements below have new structure, classes, attributes or ids.
- Who is affected: sites with custom CSS, scripts or tests that target them.
- What to do: search your CSS and scripts for these hooks, especially `#search_autocomplete`, `.cludo-display-none` and `[aria-label="status"]`, and update them.

| Component | Before | After |
|---|---|---|
| `ResultBreadcrumbs` | `<div>` with inline `<a>` and `" > "` text. | `<nav aria-label="breadcrumb">` with an `<ol>`, one `<li>` per link and `<li aria-hidden="true">` separators. |
| `Pagination` `className` | On the `<ul>`. | On the `<nav>`, and the `<ul>` also gets `cludo-mt-3`. |
| `LoadMoreResults` and `LoadMore` `className` | On the `<button>`. | On the wrapper `div#cludo-load-more`, with button classes from `classNames.loadMoreButton`. |
| `ResultsPerPage` `className` | On both the label and the select. | On the select only, through `classNames.dropdown`. |
| Hidden facet items | `li.cludo-display-none`. | `li` with an inline `display: none` (#147). |
| `FacetHeader` and `CurrentFacets` layout classes | Always applied. | Theme-gated, and dropped when `disableTheme` is set. |
| `ResultCount` | `span[aria-label="status"]`. | `span[role="status"]`. |
| `CludoSearchInput` | `aria-autocomplete="list"`, `aria-controls="search_autocomplete"` and `aria-describedby="autocomplete_hint"`. | `role="searchbox"` and `aria-describedby="autocomplete_hint[-suffix]"`, without `aria-autocomplete` and `aria-controls` (#175). |
| Autocomplete container and hint ids | `#search_autocomplete` and `#autocomplete_hint`. | `#search_autocomplete-{suffix}` and `#autocomplete_hint-{suffix}` when `CludoSearchForm` has a `uniqueFormId`. The class `search_autocomplete` is unchanged, and the hint gains the class `cludo-autocomplete-hint` (#175, #242). |
| Search-as-you-type suggestion ids | `cludo-suggestion-item-{i}`. | Unchanged for the primary input, and `cludo-suggestion-item-{containerId}-{i}` for other inputs (#242). |
| Search-as-you-type `<ul>` | No role. | `role="listbox"` (#175). |
| AI Summary citations | Every `<a>` in the answer had the class `cludo-generative-ai__answer-citation`. | Only numeric citations keep it, with their content in `span[aria-hidden]` plus `span.cludo-sr-only`, and other links use `cludo-generative-ai__answer-link` (#182, #190). |
| AI Summary feedback follow-up | Answer buttons were direct children. | Wrapped in `div.cludo-ai-summary-feedback__follow-up-options`, and the comment step always renders a Back button (#208, #237). |
| `SearchInput` form | No background class. | Adds `cludo-bg-color-white`. |
| `Banner` | `cludo-banner {className}`. | Adds the theme classes `cludo-mb-4 cludo-overflow-auto cludo-border-radius-card cludo-p-4 cludo-bg-color-accent-primary-light`. |
| Icon `<svg>` elements | No accessibility attributes. | `aria-hidden="true"`, `focusable="false"` and `className`. |

Class strings now often contain extra spaces. This only matters for exact `[class="…"]` attribute selectors.

#### 5.7 AI Summary has its own background, padding and stylesheets

- What changed: a new rule, `#cludo-generative-ai, .cludo-generative-ai { background-color: var(--general-style-background-color, #f3f3f3); padding: var(--spacer-4, 20px) }`, applies whenever the AI Summary renders, regardless of theme and `disableTheme` (#177). Because it uses an id selector, it beats class-level overrides. The AI Summary and feedback stylesheets are now injected when the component mounts and are not part of `styles.css`.
- Who is affected: sites that render the AI Summary with their own background or padding.
- What to do: override the rule with `#cludo-generative-ai`, or set `--general-style-background-color`.

```css
#cludo-generative-ai { background-color: transparent; padding: 0; }
```

### 6. Defaults and behaviour

#### 6.1 `CludoWrapper` with `publicSettings` defaults to headless mode

- What changed: `CludoWrapper` now applies `headless: true` by default when `publicSettings` are passed as well (#234). Before, `headless` stayed undefined, so CoreJs rendered its classic templates and the default components were registered.
- Who is affected: sites that use `CludoWrapper` with `publicSettings` and depend on classic or registered-template rendering.
- What to do: set `headless: false` explicitly.

```tsx
<CludoWrapper config={{ ...config, headless: false }} publicSettings={publicSettings}>
```

#### 6.2 Range facets now run a search

- What changed: `setDateRangeFacet` and `setNumberRangeFacet` on the event controller, which `useFacet` exposes with the field already bound, now run a search. Before, they only changed the facet parameters. All other facet, filter and sort functions gained an optional last `shouldSearch` argument that defaults to `true`, which matches their old behaviour (#141).
- Who is affected: code that sets a range facet and then calls search itself, which now searches twice.
- What to do: pass `false` as the last argument.

```ts
const [, facetDispatchers] = useFacet("Date");
// before
facetDispatchers.setDateRangeFacet(from, to); search();
// after
facetDispatchers.setDateRangeFacet(from, to, false); search();
```

#### 6.3 Facets follow the CoreJs facet configuration

- What changed: `CludoSearchContext.facets` now returns only the facets configured in the CoreJs instance's `facets`, so facets that the API returns but that are not configured no longer render. Selected values missing from the response are added with a count of 0, and a count of 0 is now displayed instead of hidden (#144).
- Who is affected: sites that rendered facets that were returned by the API but not configured.
- What to do: add those facets to the `facets` configuration.

#### 6.4 Default results and controls re-render only around searches

- What changed: `initCludo` now registers the default results and controls for the `beforesearch` and `aftersearch` render events only. Before, they re-rendered on every event.
- Who is affected: a custom `components.results` or `components.controls` that relied on re-rendering after `error`, `afterautocomplete` or `beforeredirect`.
- What to do: pass a `CustomComponentConfig` with the events you need.

```ts
components: {
  results: {
    component: MyResults,
    containerSelector: ".search-results .search-results-container",
    renderEvents: ["beforesearch", "aftersearch", "error"]
  }
}
```

#### 6.5 AI Summary requests use new defaults and track reference clicks

- What changed: the items below.
  - `sourceCount` defaults to 5 instead of 3 (#158).
  - `sourceFields` is chosen per document instead of `["Title", "Description"]`: `fc_Title`, `fc_Content` and `fc_ResponseFileName` for file documents, and `Title` plus `Content`, or `Description` when there is no content, for pages (#189, #212, #225).
  - When `language` is not set, the site language is no longer sent, so the answer follows the language of the query (#183).
  - The request also sends `customPrompt`.
  - Clicking a citation or a link in the answer sends `POST …/search/summarize/click` to Cludo analytics, and so does clicking a reference when references are shown. There is no opt-out prop (#256).
- Who is affected: sites that render the AI Summary. Answers can change in language, sources and citations.
- What to do: set `language`, `sourceCount` and `sourceFields` explicitly to keep the old request.

```tsx
<GenerativeResponseModule language="en" sourceCount={3} sourceFields={["Title", "Description"]} />
```

#### 6.6 Other rendering changes

- What changed: the items below.
  - `ResultsList` renders banners by default, and `hideBanners` turns them off (#135). While loading, it shows `StandardLoader` unless `disableTheme` is set. A value of `0` for `columns`, `resultSpacing` or `cssUnit` is now honoured.
  - `DidYouMean` without `suggestedQuery` shows only when the result count is between 1 and 9. Before, it showed whenever CoreJs returned a suggestion.
  - `ResultCount` mentions the selected categories, shows the "searched instead" text for auto-corrected queries, uses the translated "and", and keeps its last text while loading instead of hiding (#161).
  - `LoadMoreResults` hides when the result count is 0.
  - `ClearAllFacets` shows when any facet has a selection, so it no longer appears before a search when a facet value is pre-set (#144).
  - The autocomplete hint text is no longer rendered by React. The span is empty and CoreJs fills it (#175, #242).
  - `autocompleteHandleInputKeyDown` no longer prevents the default on Enter when nothing is selected, so in a custom input built with `useAutocomplete` inside a `<form>`, Enter now submits the form natively. The built-in components do not use this helper.
  - `PaginationState.showResultsPerPage` is `false` whenever endless scroll is enabled.
  - An empty-string `searchResultsWrapper` or `controlsWrapperSelector` no longer falls back to the default selector.
  - `initCludo` called outside the browser resolves to `{}` instead of throwing.
- Who is affected: sites that depend on the old rendering or form behaviour of these components.
- What to do: check these components on your search page. If you call `autocompleteHandleInputKeyDown` from your own input and the form has no `onSubmit` handling, check where the native submit goes.

### 7. Runtime

#### 7.1 The components need a recent CoreJs build

- What changed: the components call CoreJs methods that older builds do not have: `setDateRangeFacet`, `setNumberRangeFacet`, `setInstantSuggestions` and `showInstantSuggestions`, the `shouldSearch` argument on facet, filter and sort methods, and the `urlListDelimiter` option. The default CoreJs script URL is unchanged and serves a build with all of them. The URL can now be overridden with `CludoSearchOptions.overrideCoreScriptUrl`, which takes effect only when `headless` is `true`, or by passing a URL to `injectCoreScript`.
- Who is affected: customers who self-host or pin an older CoreJs build, through `overrideCoreScriptUrl` or their own script tag.
- What to do: use a CoreJs build that includes these methods.

#### 7.2 `injectCoreScript` waits for CoreJs to be ready

- What changed: `injectCoreScript` now resolves only once `window.Cludo` is a constructor, and concurrent calls share one load (#249). If a matching script tag is already on the page, it waits for that tag's `load` event and rejects with `Error("Failed to load Cludo core script")` after 10 seconds. A tag the library adds itself has no timeout. A load error rejects with the same `Error`, and a script that loads without defining `window.Cludo` rejects with `Error("Cludo core script loaded but window.Cludo is not a constructor")`. On any failure the script tag is removed, including one that was already on the page, and the next call retries.
- Who is affected: code that handles the promise returned by `injectCoreScript`, which used to reject with no argument.
- What to do: handle the `Error` rejection.

#### 7.3 New dependencies

- What changed: `dompurify` ^3.4.8 (#223) and `framer-motion` (#159, set to ^6.5.1 in #176) were added to `dependencies`. Both are bundled into `main.csr.js`, and `react` and `react-dom` remain the only externals. The UMD global name changed from `@cludo/cludo-search-components` to `CludoSearchComponents`.
- Who is affected: apps that also depend on `framer-motion`, and `<script>`-tag users of the UMD global.
- What to do: check for version conflicts with your own `framer-motion`, and update any reference to the UMD global name.

#### 7.4 React peer range

- What changed: the `react` and `react-dom` peer range changed from `16.8.0 - 18` to `16.8.0 - 19` (#143).
- Who is affected: customers who plan to upgrade to React 19.
- What to do: see [Known issues in 1.0.149](#known-issues-in-10149) before upgrading.

## Added

Each entry below gives its PR numbers, Jira keys and the first npmjs version that contains it. The npmjs package has its own 1.0.32 to 1.0.63 releases, which are unrelated to GitHub Packages 1.0.63, so every entry in Added, Changed and Fixed is new to customers coming from the GitHub Packages release. Version 1.0.149 contains only the revert of #247 (#258), so its code matches 1.0.148.

### Setup and integration

- The library can now be used in server-side rendered apps such as Next.js through the `@cludosearch/cludo-search-components/ssr` entry point, and the React peer range now includes React 19, see [Known issues in 1.0.149](#known-issues-in-10149) (#143, REACT-97; first in 1.0.58).
- In the CludoSearch init `components` option, results, controls and autocomplete can now be passed as a config object with `component`, `containerSelector` and `renderEvents`, and a new `components.custom` array registers extra components on your own selectors and render events, including `afterpageload` (#136, REACT-81; first in 1.0.50).
- A new `behavior.urlListDelimiter` option (`,`, `|`, `~` or `!`) sets the separator used for list values in search URLs, and the default stays `,` (#153, CDT-6920; first in 1.0.68).

### Search and results

- Facet, filter and sort functions on the event controller and hooks take an optional last `shouldSearch` argument, and passing `false` changes the parameters without running a search (#141, no Jira; first in 1.0.57).
- Facet components can show an "All results" option through `includeAllResultsOption` and `allResultsOptionLabel`, and accept `clearLabel` and `showMoreLabel` overrides (#144, no Jira; first in 1.0.59).
- The pagination "First page" and "Last page" aria-labels can now be translated through CoreJs translations or the new `first_page` and `last_page` override strings, and the English default is unchanged (#202, CXPS-1923; first in 1.0.111).

### Styling and theming

- Most components accept a `classNames` prop that adds your own classes to their inner elements, and an `attributes` prop that adds your own HTML attributes, such as `data-*` or `aria-*` (#135, #142, REACT-127; first in 1.0.50, 1.0.57).
- AI Summary colours for the background, header, text, reference chips, avatar and feedback buttons can now be set through CSS custom properties, and `header="mirrorQuery"` shows the searched query as the summary heading (#177, CDT-7615; first in 1.0.97). The new default background and padding rule is covered in [Migrating](#57-ai-summary-has-its-own-background-padding-and-stylesheets).
- The hover background of AI Summary source pills and inline citations can be themed with `--behavior-tab-hover-background-color`, which falls back to the previous grey (#238, CDT-8506; first in 1.0.134).

### AI Summary

- AI Summary can be collapsed to a fixed height with a "show more" button through the `collapseHeight`, `collapseHeightCssUnit`, `collapseBackgroundFadeColor` and `collapseButtonTemplate` props (#152, REACT-158; first in 1.0.66).
- AI Summary accepts a `customPrompt` prop that is sent with the summary request (#154, REACT-161; first in 1.0.69).
- The AI Summary component is also exported as `AiSummary`, with `GenerativeResponseModule` still available, and the `useAiSummary`/`useGenerativeResponse` and `useAiChat` hooks are now exported for custom AI implementations (#156, CDT-6993; first in 1.0.72).
- A new AI Summary `trigger` prop starts generation on the default search results, on the `aftersearch` event, or on any custom window event whose `detail` carries the search response (#165, CDT-7482; first in 1.0.82).
- A new AI Summary `customElement` prop renders your own content, such as a support link, above the references once the answer has finished streaming (#172, CDT-7580; first in 1.0.86).
- A new AI Summary `sourcesContent` prop (`"pageTitle"` or `"pageUrl"`) chooses whether references show the page title or the URL, and the reference label no longer renders as "id | title" (#216, CDT-8236; first in 1.0.115). **[may affect custom styling/integration]**
- `feedbackBackButtonText` sets the label of the AI Summary feedback Back button, which defaults to "Back". The button itself is covered in [Migrating](#56-other-markup-changes-that-can-break-custom-selectors) (#208, #237, CDT-7986, CDT-8499; first in 1.0.119, 1.0.133).
- AI Summary can show an opt-in read-aloud button that uses the browser's built-in speech synthesis, turned on with `allowReadAloud` and configured with `readAloudLabel`, `readAloudPauseLabel`, `readAloudIcon` and `resolveReadAloudLang` for multilingual sites (#227, #233, #235, CDT-8343, CDT-8495; first in 1.0.129 to 1.0.131).
- Citation and reference click tracking in the AI Summary is covered in [Migrating](#65-ai-summary-requests-use-new-defaults-and-track-reference-clicks) (#256, NEX-3007; first in 1.0.148).

### AI Mode (new component)

- A new `AiMode` component adds a slide-out conversational AI panel with a toggle button, and it runs its own search for sources, so asking a question does not re-run the page search, change the URL or fire the page's `aftersearch` event (#159, #160, #162, #163, #210, #215, #222, CDT-6993, CDT-7368, CDT-7469, CDT-8091, CDT-8243, CDT-8329; first in 1.0.77 to 1.0.124).
- AI Mode text is translated into the supported languages, falls back to English, and can be overridden with `titleText`, `headerTitleText`, `introText`, `disclaimerText`, `inputPlaceholder` and `inputPlaceholderFollowUp`, which accept a limited, sanitised set of HTML; `uiLanguage` sets the display language, `language` sets the answer language, and `customPrompt` is sent with each request (#162, #191, #199, #211, #217, #223, CDT-7368, CDT-7649, CDT-7873, CDT-8052, CDT-8285; first in 1.0.80 to 1.0.125).
- AI Mode can carry the visitor's search query into the panel and submit it when the panel opens, reading it from `searchInputSelector` or from the search that triggered it (`trigger="aftersearch"`) (#209, #221, CDT-8053; first in 1.0.113, 1.0.122).
- AI Summary can show an "Explore further in AI Mode" button, turned on with `includeAIMode` and `aiModeButtonText`, that opens AI Mode with the summary as the first exchange and continues the same conversation; the AI Mode texts, language and voice language can be set from the AI Summary with the `aiMode*` props (#176, #178, #193, #214, #228, #241, #244, #250, CDT-7555, CXPS-1953, CDT-8424, CDT-8339, CDT-8726, NEX-2999; first in 1.0.88 to 1.0.144).
- Each completed AI Mode answer has a read-aloud button, which is on by default and can be turned off with `allowReadAloud={false}` (#236, CDT-8537; first in 1.0.136).
- AI Mode shows a microphone button for voice input in browsers that support speech recognition when `voiceSearchLanguage` is set, and it keeps listening through pauses until 3.5 seconds of silence, configurable with `voiceSearchSilenceTimeoutMs` (#240, #248, CDT-7124, CDT-8921; first in 1.0.137, 1.0.142).
- Each completed AI Mode answer has thumbs up and thumbs down feedback with an optional reason and comment, using the same feedback component as the AI Summary; it is on by default, `allowFeedback={false}` turns it off, and `onSubmitFeedback` receives the submission (#254, #255, CDT-8054, CDT-8997; first in 1.0.146, 1.0.147).
- Clicks on citations and reference links in AI Mode answers are now recorded in Cludo analytics (#253, CDT-8975; first in 1.0.145).

## Changed

### Setup and integration

- The new package name and registry, and the move of the API client types to `@cludosearch/cludo-api-client`, are covered in [Migrating](#1-package-and-registry) (#112, no Jira; first in 1.0.32).
- The new `exports` map and main entry are covered in [Migrating](#2-imports-and-require) (#143, REACT-97; first in 1.0.58).
- The global stylesheet no longer loading with the package is covered in [Migrating](#3-styles) (#126, #143, REACT-71, REACT-97; first in 1.0.48, 1.0.58).
- The headless default for `CludoWrapper` with `publicSettings`, which fixes endless loading and duplicated results, is covered in [Migrating](#61-cludowrapper-with-publicsettings-defaults-to-headless-mode) (#234, CDT-8321; first in 1.0.132).
- The new `framer-motion` dependency is covered in [Migrating](#73-new-dependencies) (#159, #176, CDT-6993, CDT-7555; first in 1.0.76, 1.0.88).

### Search and results

- Search-term highlights in result titles and the `showRawText` prop are covered in [Migrating](#53-result-titles-show-highlights-by-default) (#109, REACT-82; first in 1.0.35).
- While results load, facets and banners (`cludo-theme-loading-disable-children`) and result items, `ResultCount`, `DidYouMean`, `Pagination`, `ResultsPerPage` and `CurrentFacets` (`cludo-theme-loading-disable`) are dimmed and not clickable, unless `disableTheme` is set. `ResultsList` rendering banners is covered in [Migrating](#55-resultslist-has-a-new-structure) (#135, REACT-127; first in 1.0.50). **[may affect custom styling/integration]**
- The rename of the `ResultLink` prop `autofocus` to `shouldBeFocused` is covered in [Migrating](#41-resultlinkautofocus-is-now-shouldbefocused) (#149, REACT-152; first in 1.0.64).

### AI Summary

- The new default sources and source fields are covered in [Migrating](#65-ai-summary-requests-use-new-defaults-and-track-reference-clicks) (#158, #189, #212, #225, REACT-162, CDT-7611, CDT-7814, CDT-8358; first in 1.0.74 to 1.0.123).
- The change to the default `language` is covered in [Migrating](#65-ai-summary-requests-use-new-defaults-and-track-reference-clicks) (#183, CDT-7688; first in 1.0.91).
- The new `cludo-generative-ai__answer-link` class for ordinary links in the answer is covered in [Migrating](#56-other-markup-changes-that-can-break-custom-selectors) (#182, CDT-7603; first in 1.0.90).
- AI Summary citation markers now render as small round badges, inline links use #181818, and answer lists show bullets and numbers, with the new classes `cludo-generative-ai__answer-ol`, `cludo-generative-ai__answer-ul` and `cludo-generative-ai__answer-li` and a bottom margin on answer paragraphs (#192, #196, CDT-7261, CDT-7837; first in 1.0.99, 1.0.102). **[may affect custom styling/integration]**
- The AI Summary icon container no longer has a grey background, and the CSS variable `--general-style-avatar-icon-background-color` is no longer read, so the icon uses `--general-style-avatar-background-color` only (#197, CDT-7207; first in 1.0.104). **[may affect custom styling/integration]**
- The AI Summary feedback component is now exported for standalone use and styles itself, it can be themed with `--feedback-tab-*` variables, a new `onSubmitFeedback` prop on the AI Summary replaces the built-in feedback request, and the default thumbs icon colour changed from #181818 to #101828 (#239, CDT-7952; first in 1.0.140). **[may affect custom styling/integration]**

## Fixed

### Search and results

- HTML in indexed content is no longer injected into result titles, descriptions and highlight fragments, as covered in [Migrating](#54-highlights-render-as-b-and-indexed-html-is-no-longer-injected) (#145, no Jira; first in 1.0.62).
- The `maxWords` truncation and whitespace splitting fixes are covered in [Migrating](#46-result-helpers-return-undefined-for-missing-fields) (#147, no Jira; first in 1.0.63).
- The `ClearAllFacets` and zero-count facet fixes are covered in [Migrating](#63-facets-follow-the-corejs-facet-configuration) (#144, no Jira; first in 1.0.59).
- The `ResultCount` category and "searched instead" text is covered in [Migrating](#66-other-rendering-changes) (#161, CDT-7255; first in 1.0.79).
- In projects that use `CludoWrapper`, instant suggestions now come back when the search input is focused again after a blur, instead of disappearing until the page reloads (#180, CDT-7407; first in 1.0.96).
- The more reliable Cludo core script loading is covered in [Migrating](#72-injectcorescript-waits-for-corejs-to-be-ready) (#249, CDT-8924; first in 1.0.143).

### Accessibility

- Pressing Enter on the endless-scroll "Load more" button no longer loses keyboard focus, because focus moves to the next result automatically, and `disableKeyboardFocusHandling` on `LoadMoreResults` opts out (#148, #150, REACT-152; first in 1.0.64, 1.0.65).
- Screen reader support for search-as-you-type suggestions, including unique autocomplete ids for multiple inputs, is covered in [Migrating](#56-other-markup-changes-that-can-break-custom-selectors) (#175, #242, CDT-7380; first in 1.0.110, 1.0.141).
- `focusOnResultsAfterSearch` now moves focus to the first result on every new search and page change, a visually hidden live region announces the result count, and the results list carries `role="list"`, so screen readers such as NVDA keep list semantics and reading order. The markup changes are covered in [Migrating](#55-resultslist-has-a-new-structure) (#204, #218, CXPS-1937, CDT-7498; first in 1.0.112, 1.0.128).
- Screen reader announcements of the referenced page title for AI Summary citation markers are covered in [Migrating](#56-other-markup-changes-that-can-break-custom-selectors) (#190, CDT-7616; first in 1.0.100).

### AI Summary

- AI Summary references to documents such as PDFs now show the document title (`fc_Title`) instead of the raw URL (#205, CDT-7260; first in 1.0.113).
- AI Summary references now show page titles instead of raw URLs, including when search results arrive after the summary finishes streaming and when the summary is rendered without a results list on the page, and inline citation numbers link to the matching reference (#216, #219, #224, #230, CDT-8236; first in 1.0.115 to 1.0.127).
- AI Summary reference and citation links now use the result's correctly cased URL instead of the URL in the model output, so links to case-sensitive pages no longer break (#213, CDT-8031; first in 1.0.120). **[may affect custom styling/integration]**

## Known issues in 1.0.149

- `require()` of the package root fails. The `exports` entry for `.` defines only an `import` condition, with no `require` or `default` condition, so Node reports `ERR_PACKAGE_PATH_NOT_EXPORTED` and webpack 5 reports "Package path . is not exported". Load the package with `import`.
- `import "@cludosearch/cludo-search-components/styles"` can be dropped by webpack. The package declares `"sideEffects": false`, which also covers the stylesheet, so a webpack 5 production build removes the import unless the consumer's CSS rule sets `sideEffects: true`.
- React 19 is in the peer range, but component rendering still uses `ReactDOM.render` (`src/utils/components-controller.tsx:214`), which the `react-dom` 19 build does not export. This path runs whenever `initCludo` registers components, which includes the default non-headless setup and any `components.*` or `components.custom` registration. `CludoWrapper` with the default `headless: true` registers no components.
- Banners may show twice with the default results component (unconfirmed, found by reading the source). `CludoSearchResults`, the default `components.results` when `headless` is not `true`, renders `BannerGroup` and then `ResultsList`, which renders banners as well unless `hideBanners` is passed. If you see duplicated banners, pass your own `components.results` that renders `ResultsList` with `hideBanners`.

<details>
<summary>Internal changes (no consumer effect)</summary>

- #110: Storybook documentation updates (REACT-98).
- #155: adds `customPrompt` to the internal chat request type, groundwork for #162 (CDT-7043).
- #157: replaces a hard-coded token in `.npmrc` with an environment variable (CDT-6993).
- #164, #166, #185, #198, #257: version bumps only.
- #168, #169, #170: npm publish workflows and README updates.
- #181: adds citation fields to the internal chat conversation types (CDT-7121).
- #186, #187, #188, #194: CI (Slack notifications and automatic version bump).
- #195, #200: add `couldAnswer` to the internal chat types, which are not exported from the package entry points (CDT-7773).
- #201: re-adds `sourceFields` to the internal `ChatRequestBody` type, cancelling the type removal in #189; the type is not exported.
- #231: AI Mode requests always ask for citations, with no visible effect until a backend change ships (CDT-8254).

</details>
