{"_rev":"9-b6f232aa87978d6be96cb83f4a343458","time":{"created":"2025-11-04T10:03:06.170Z","modified":"2025-11-04T10:03:06.669Z","0.1.0":"2025-11-02T18:51:50.593Z","0.1.1":"2025-11-02T19:32:00.909Z","0.1.2":"2025-11-02T19:37:59.524Z","0.1.3":"2025-11-04T10:03:06.435Z"},"_id":"@chesnokovtony/ng-search","name":"@chesnokovtony/ng-search","dist-tags":{"latest":"0.1.3"},"versions":{"0.1.3":{"name":"@chesnokovtony/ng-search","version":"0.1.3","description":"A modern, performant, and extensible Angular 20+ library for building search applications with signals, SSR support, and plugin-based architecture","keywords":["angular","search","search-ui","autocomplete","facets","faceted-search","typeahead","search-box","angular-signals","standalone"],"author":{"name":"Anton Chesnokov","email":"chesnokov.tony@gmail.com"},"license":"MIT","homepage":"https://github.com/AntonChesnokov/ng-search#readme","repository":{"type":"git","url":"git+https://github.com/AntonChesnokov/ng-search.git"},"bugs":{"url":"https://github.com/AntonChesnokov/ng-search/issues"},"engines":{"node":">=18.0.0","npm":">=9.0.0"},"peerDependencies":{"@angular/common":"^19.2.0 || ^20.0.0","@angular/core":"^19.2.0 || ^20.0.0","@angular/platform-browser":"^19.2.0 || ^20.0.0"},"dependencies":{"tslib":"^2.3.0"},"sideEffects":false,"main":"./bundles/ng-search-core.umd.js","module":"fesm2022/ng-search-core.mjs","typings":"index.d.ts","style":"./styles/index.css","exports":{"./package.json":{"default":"./package.json"},".":{"types":"./index.d.ts","default":"./fesm2022/ng-search-core.mjs"}},"gitHead":"e584f5d86d63c4cada7279bb748506153c7325ae","_id":"@chesnokovtony/ng-search@0.1.3","_nodeVersion":"24.11.0","_npmVersion":"11.6.1","dist":{"integrity":"sha512-Oeas6AOmUaaXZKyHHa6tT66ZCUFLIdrMvKZ+nK52EJbXhm2m+YqQrpsfMTC+da2q2z6DMnwxa087zKOO1NiGTQ==","shasum":"df83d127c853d72ec37a0eb68eae8f18523a1f18","tarball":"https://registry.npmjs.org/@chesnokovtony/ng-search/-/ng-search-0.1.3.tgz","fileCount":15,"unpackedSize":722946,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC2hRn/yiwY7c4d+gIcFOwIP81HeeVfsI+VdN5O/2nHVQIhAP7N4M0RTovEWG6DpB33XaWH289mtSUJtC7RlaV3TS1a"}]},"_npmUser":{"name":"chesnokovtony","email":"chesnokovtony@gmail.com"},"directories":{},"maintainers":[{"name":"chesnokovtony","email":"chesnokovtony@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ng-search_0.1.3_1762250586238_0.5803110857347051"},"_hasShrinkwrap":false}},"maintainers":[{"name":"chesnokovtony","email":"chesnokovtony@gmail.com"}],"description":"A modern, performant, and extensible Angular 20+ library for building search applications with signals, SSR support, and plugin-based architecture","homepage":"https://github.com/AntonChesnokov/ng-search#readme","keywords":["angular","search","search-ui","autocomplete","facets","faceted-search","typeahead","search-box","angular-signals","standalone"],"repository":{"type":"git","url":"git+https://github.com/AntonChesnokov/ng-search.git"},"author":{"name":"Anton Chesnokov","email":"chesnokov.tony@gmail.com"},"bugs":{"url":"https://github.com/AntonChesnokov/ng-search/issues"},"license":"MIT","readme":"# @chesnokovtony/ng-search\n\nA modern Angular library for building search applications with signals, SSR support, and customizable components.\n\n[![npm version](https://img.shields.io/npm/v/@chesnokovtony/ng-search.svg)](https://www.npmjs.com/package/@chesnokovtony/ng-search)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n**[🚀 Live Demo](https://ng-search.vercel.app/)** | [📖 Documentation](https://github.com/AntonChesnokov/ng-search) | [🐛 Issues](https://github.com/AntonChesnokov/ng-search/issues)\n\n## Features\n\n- 🔍 **Complete Search UI** - Search box, autocomplete, results, and faceted filtering\n- 🎯 **Modern Angular** - Built with Angular 19+ signals and standalone components\n- 🔌 **Backend Agnostic** - Works with any search API through adapters\n- 🎨 **Fully Customizable** - Custom templates, theming, and styling\n- ♿ **Accessible** - ARIA support and keyboard navigation\n- 🌐 **SSR Ready** - Full server-side rendering support\n\n## Live Examples\n\nSee the library in action with these interactive demos:\n\n- **[Angular Docs Search](https://ng-search.vercel.app/angular-demo)** - Search Angular documentation with autocomplete\n- **[Rick & Morty Search](https://ng-search.vercel.app/rick-morty)** - Character search with faceted filtering\n- **[World Atlas](https://ng-search.vercel.app/countries)** - Country search with custom templates\n\n## Installation\n\n```bash\nnpm install @chesnokovtony/ng-search\n```\n\n## Quick Start\n\n```typescript\nimport { Component } from '@angular/core';\nimport {\n  SearchBoxComponent,\n  SuggestionsComponent,\n  ResultsComponent,\n  provideSearch,\n  RestApiAdapter,\n} from '@chesnokovtony/ng-search';\n\n@Component({\n  selector: 'app-search',\n  standalone: true,\n  imports: [SearchBoxComponent, SuggestionsComponent, ResultsComponent],\n  providers: [\n    provideSearch({\n      adapter: () => new RestApiAdapter({\n        endpoint: 'https://api.example.com/search'\n      }),\n      config: {\n        debounceTime: 300,\n        pageSize: 20,\n      },\n    }),\n  ],\n  template: `\n    <ng-search-box [placeholder]=\"'Search...'\" />\n    <ng-search-suggestions [maxSuggestions]=\"10\" />\n    <ng-search-results [showPagination]=\"true\" />\n  `,\n})\nexport class SearchComponent {}\n```\n\n## Custom Templates\n\nCustomize how suggestions and results are displayed:\n\n```typescript\n@Component({\n  template: `\n    <ng-search-suggestions>\n      <ng-template #suggestionTemplate let-suggestion>\n        <div class=\"custom-suggestion\">\n          <strong>{{ suggestion.text }}</strong>\n          <span>{{ suggestion.count }} results</span>\n        </div>\n      </ng-template>\n    </ng-search-suggestions>\n\n    <ng-search-results>\n      <ng-template #resultTemplate let-result>\n        <article>\n          <h3>{{ result.data.title }}</h3>\n          <p>{{ result.data.description }}</p>\n        </article>\n      </ng-template>\n    </ng-search-results>\n  `,\n})\nexport class CustomSearchComponent {}\n```\n\n## Programmatic Control\n\nAccess search state and methods directly:\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport { SearchStateService } from '@chesnokovtony/ng-search';\n\n@Component({\n  template: `\n    <button (click)=\"search('angular')\">Search</button>\n    <button (click)=\"clearSearch()\">Clear</button>\n    <div>Results: {{ searchState.total() }}</div>\n  `,\n})\nexport class ProgrammaticSearchComponent {\n  searchState = inject(SearchStateService);\n\n  search(query: string) {\n    this.searchState.setQuery(query);\n  }\n\n  clearSearch() {\n    this.searchState.clear();\n  }\n}\n```\n\n## Faceted Search\n\nAdd filters to refine search results:\n\n```typescript\nimport { Component, inject } from '@angular/core';\nimport {\n  SearchProvider,\n  FacetsContainerComponent,\n  AppliedFiltersComponent\n} from '@chesnokovtony/ng-search';\n\n@Component({\n  standalone: true,\n  imports: [FacetsContainerComponent, AppliedFiltersComponent],\n  template: `\n    <ng-facets-container\n      [facets]=\"searchProvider.facets()\"\n      (facetChange)=\"onFacetChange($event)\"\n    />\n\n    <ng-applied-filters\n      [filters]=\"searchProvider.appliedFilters()\"\n      (removeFilter)=\"onRemoveFilter($event)\"\n    />\n  `,\n})\nexport class FacetedSearchComponent {\n  searchProvider = inject(SearchProvider);\n\n  ngOnInit() {\n    this.searchProvider.addFacets([\n      {\n        id: 'category',\n        field: 'category',\n        label: 'Category',\n        type: 'text',\n        multiSelect: true,\n        options: [\n          { value: 'electronics', label: 'Electronics' },\n          { value: 'books', label: 'Books' },\n        ],\n      },\n      {\n        id: 'price',\n        field: 'price',\n        label: 'Price Range',\n        type: 'number-range',\n        min: 0,\n        max: 1000,\n      },\n    ]);\n  }\n\n  onFacetChange() {\n    this.searchProvider.executeSearch();\n  }\n\n  onRemoveFilter(filter: string) {\n    this.searchProvider.clearFacet(filter);\n    this.searchProvider.executeSearch();\n  }\n}\n```\n\n## Custom Backend Adapter\n\nIntegrate with any search backend:\n\n```typescript\nimport { SearchAdapter, SearchQuery, SearchResponse } from '@chesnokovtony/ng-search';\nimport { HttpClient } from '@angular/common/http';\nimport { inject } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\n\nexport class MySearchAdapter implements SearchAdapter {\n  private http = inject(HttpClient);\n\n  async search<T>(query: SearchQuery): Promise<SearchResponse<T>> {\n    const response = await firstValueFrom(\n      this.http.post<any>('/api/search', query)\n    );\n\n    return {\n      results: response.hits.map(hit => ({\n        id: hit.id,\n        data: hit._source,\n        score: hit._score,\n      })),\n      total: response.total,\n      took: response.took,\n    };\n  }\n\n  async suggest(query: string): Promise<Suggestion[]> {\n    const response = await firstValueFrom(\n      this.http.get<any>(`/api/suggest?q=${query}`)\n    );\n    return response.suggestions;\n  }\n}\n```\n\n## Styling & Theming\n\nImport the default styles in your `angular.json`:\n\n```json\n{\n  \"styles\": [\n    \"node_modules/@chesnokovtony/ng-search/styles/index.css\"\n  ]\n}\n```\n\nOr customize using CSS variables:\n\n```css\nng-search-box {\n  --ng-color-primary: #0066cc;\n  --ng-radius-md: 8px;\n}\n```\n\nDark mode support:\n\n```html\n<div data-theme=\"dark\">\n  <ng-search-box></ng-search-box>\n</div>\n```\n\n## API Reference\n\n### Components\n\n**SearchBox**\n- Search input with debouncing and keyboard navigation\n- Inputs: `placeholder`, `debounceTime`, `disabled`, `showClearButton`\n- Outputs: `queryChange`, `search`, `clear`, `focus`, `blur`\n\n**Suggestions**\n- Autocomplete dropdown\n- Inputs: `maxSuggestions`, `highlightQuery`, `minQueryLength`\n- Outputs: `suggestionSelected`, `visibilityChange`\n\n**Results**\n- Search results display with pagination\n- Inputs: `pageSize`, `showPagination`, `enableVirtualScroll`\n- Outputs: `resultClick`, `pageChange`, `retry`\n\n**FacetsContainer**\n- Container for multiple facets\n- Inputs: `facets`, `title`\n- Outputs: `facetChange`, `clearAll`\n\n**AppliedFilters**\n- Shows active filters as removable chips\n- Inputs: `filters`, `fieldLabels`\n- Outputs: `removeFilter`, `clearAll`\n\n### Services\n\n**SearchStateService**\n- Signals: `query()`, `results()`, `loading()`, `total()`, `suggestions()`\n- Methods: `setQuery()`, `clear()`, `nextPage()`, `previousPage()`\n\n**SearchProvider**\n- Main search orchestration service\n- Methods: `executeSearch()`, `addFacet()`, `clearFacet()`, `clearAllFacets()`\n\n**SearchCoordinatorService**\n- Methods: `search()`, `suggest()`, `cancel()`\n\n## Advanced Configuration\n\nUse DI tokens for fine-grained control:\n\n```typescript\nimport {\n  provideSearch,\n  NG_SEARCH_ADAPTER,\n  NG_SEARCH_INITIAL_CONFIG,\n} from '@chesnokovtony/ng-search';\n\nexport const appConfig = {\n  providers: [\n    { provide: NG_SEARCH_ADAPTER, useClass: MySearchAdapter },\n    {\n      provide: NG_SEARCH_INITIAL_CONFIG,\n      useValue: { debounceTime: 200, pageSize: 15 },\n    },\n    provideSearch(),\n  ],\n};\n```\n\n## Contributing\n\nContributions are welcome! Please see our [contributing guidelines](https://github.com/AntonChesnokov/ng-search/blob/main/CONTRIBUTING.md).\n\n## License\n\nMIT © 2025 ng-search contributors\n\n## Links\n\n- [🚀 Live Demo](https://ng-search.vercel.app/)\n- [📖 GitHub Repository](https://github.com/AntonChesnokov/ng-search)\n- [🐛 Issue Tracker](https://github.com/AntonChesnokov/ng-search/issues)\n- [📋 Changelog](https://github.com/AntonChesnokov/ng-search/blob/main/projects/ng-search-lib/CHANGELOG.md)\n","readmeFilename":"README.md"}