mirror of
				https://github.com/Redocly/redoc.git
				synced 2025-10-31 15:57:30 +03:00 
			
		
		
		
	fix: various search fixes
This commit is contained in:
		
							parent
							
								
									1ff2bd84cc
								
							
						
					
					
						commit
						b797c965b2
					
				|  | @ -8,3 +8,4 @@ export * from './dropdown'; | ||||||
| export * from './mixins'; | export * from './mixins'; | ||||||
| export * from './tabs'; | export * from './tabs'; | ||||||
| export * from './samples'; | export * from './samples'; | ||||||
|  | export * from './perfect-scrollbar'; | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ import styled, { withProps } from '../../styled-components'; | ||||||
| export const OperationEndpointWrap = styled.div` | export const OperationEndpointWrap = styled.div` | ||||||
|   cursor: pointer; |   cursor: pointer; | ||||||
|   position: relative; |   position: relative; | ||||||
|  |   margin-bottom: 5px; | ||||||
| `;
 | `;
 | ||||||
| 
 | 
 | ||||||
| export const ServerRelativeURL = styled.span` | export const ServerRelativeURL = styled.span` | ||||||
|  |  | ||||||
|  | @ -24,7 +24,7 @@ export class Redoc extends React.Component<RedocProps> { | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   componentDidMount() { |   componentDidMount() { | ||||||
|     this.props.store.menu.updateOnHash(); |     this.props.store.onDidMount(); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   componentWillUnmount() { |   componentWillUnmount() { | ||||||
|  |  | ||||||
|  | @ -82,6 +82,8 @@ export interface SearchBoxProps { | ||||||
|   marker: MarkerService; |   marker: MarkerService; | ||||||
|   getItemById: (id: string) => IMenuItem | undefined; |   getItemById: (id: string) => IMenuItem | undefined; | ||||||
|   onActivate: (item: IMenuItem) => void; |   onActivate: (item: IMenuItem) => void; | ||||||
|  | 
 | ||||||
|  |   className?: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export interface SearchBoxState { | export interface SearchBoxState { | ||||||
|  | @ -89,6 +91,11 @@ export interface SearchBoxState { | ||||||
|   term: string; |   term: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | interface SearchResult { | ||||||
|  |   item: IMenuItem; | ||||||
|  |   score: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxState> { | export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxState> { | ||||||
|   constructor(props) { |   constructor(props) { | ||||||
|     super(props); |     super(props); | ||||||
|  | @ -145,8 +152,14 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   render() { |   render() { | ||||||
|     const items: IMenuItem[] = this.state.results.map(res => this.props.getItemById(res.id)); |     const results: SearchResult[] = this.state.results.map(res => ({ | ||||||
|     items.sort((a, b) => (a.depth > b.depth ? 1 : a.depth < b.depth ? -1 : 0)); |       item: this.props.getItemById(res.id), | ||||||
|  |       score: res.score, | ||||||
|  |     })); | ||||||
|  |     results.sort( | ||||||
|  |       (a, b) => | ||||||
|  |         a.item.depth > b.item.depth ? 1 : a.item.depth < b.item.depth ? -1 : b.score - a.score, | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     return ( |     return ( | ||||||
|       <div> |       <div> | ||||||
|  | @ -158,14 +171,14 @@ export class SearchBox extends React.PureComponent<SearchBoxProps, SearchBoxStat | ||||||
|           type="text" |           type="text" | ||||||
|           onChange={this.search} |           onChange={this.search} | ||||||
|         /> |         /> | ||||||
|         {items.length > 0 && ( |         {results.length > 0 && ( | ||||||
|           <SearchResultsBox> |           <SearchResultsBox> | ||||||
|             {items.map(item => ( |             {results.map(res => ( | ||||||
|               <MenuItem |               <MenuItem | ||||||
|                 item={item} |                 item={res.item} | ||||||
|                 onActivate={this.props.onActivate} |                 onActivate={this.props.onActivate} | ||||||
|                 withoutChildren={true} |                 withoutChildren={true} | ||||||
|                 key={item.id} |                 key={res.item.id} | ||||||
|               /> |               /> | ||||||
|             ))} |             ))} | ||||||
|           </SearchResultsBox> |           </SearchResultsBox> | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ export * from './RedocStandalone'; | ||||||
| export * from './Redoc/Redoc'; | export * from './Redoc/Redoc'; | ||||||
| // export * from './Redoc/elements';
 | // export * from './Redoc/elements';
 | ||||||
| export * from './Schema/'; | export * from './Schema/'; | ||||||
|  | export * from './SearchBox/SearchBox'; | ||||||
| export * from './Operation/Operation'; | export * from './Operation/Operation'; | ||||||
| export * from './RedocStandalone'; | export * from './RedocStandalone'; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -59,15 +59,21 @@ export class AppStore { | ||||||
|     this.spec = new SpecStore(spec, specUrl, this.options); |     this.spec = new SpecStore(spec, specUrl, this.options); | ||||||
|     this.menu = new MenuStore(this.spec, this.scroll); |     this.menu = new MenuStore(this.spec, this.scroll); | ||||||
| 
 | 
 | ||||||
|     this.search = new SearchStore(this.spec); |     this.search = new SearchStore(); | ||||||
|  |     this.search.indexItems(this.menu.items); | ||||||
|  |     this.search.done(); | ||||||
| 
 | 
 | ||||||
|     this.disposer = observe(this.menu, 'activeItemIdx', change => { |     this.disposer = observe(this.menu, 'activeItemIdx', change => { | ||||||
|       this.updateMarkOnMenu(change.newValue as number); |       this.updateMarkOnMenu(change.newValue as number); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   onDidMount() { | ||||||
|  |     this.menu.updateOnHash(); | ||||||
|  |     this.updateMarkOnMenu(this.menu.activeItemIdx); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   updateMarkOnMenu(idx: number) { |   updateMarkOnMenu(idx: number) { | ||||||
|     console.log('update marker'); |  | ||||||
|     const start = Math.max(0, idx); |     const start = Math.max(0, idx); | ||||||
|     const end = Math.min(this.menu.flatItems.length, start + 5); |     const end = Math.min(this.menu.flatItems.length, start + 5); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -34,7 +34,6 @@ export class MarkerService { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   mark(term?: string) { |   mark(term?: string) { | ||||||
|     console.log('mark', term); |  | ||||||
|     if (!term && !this.prevTerm) return; |     if (!term && !this.prevTerm) return; | ||||||
|     this.map.forEach(val => { |     this.map.forEach(val => { | ||||||
|       val.unmark(); |       val.unmark(); | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ export interface IMenuItem { | ||||||
|   id: string; |   id: string; | ||||||
|   absoluteIdx?: number; |   absoluteIdx?: number; | ||||||
|   name: string; |   name: string; | ||||||
|  |   description?: string; | ||||||
|   depth: number; |   depth: number; | ||||||
|   active: boolean; |   active: boolean; | ||||||
|   items: IMenuItem[]; |   items: IMenuItem[]; | ||||||
|  |  | ||||||
|  | @ -1,21 +1,18 @@ | ||||||
| import { SpecStore } from '../index'; | import { OperationModel } from './models'; | ||||||
| import { GroupModel, OperationModel } from './models'; |  | ||||||
| import worker from './SearchWorker.worker'; | import worker from './SearchWorker.worker'; | ||||||
|  | import { IMenuItem } from './MenuStore'; | ||||||
| 
 | 
 | ||||||
| export class SearchStore { | export class SearchStore { | ||||||
|   searchWorker = new worker(); |   searchWorker = new worker(); | ||||||
| 
 | 
 | ||||||
|   constructor(private spec: SpecStore) { |   constructor() {} | ||||||
|     this.indexGroups(this.spec.operationGroups); |  | ||||||
|     this.done(); |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   indexGroups(groups: Array<GroupModel | OperationModel>) { |   indexItems(groups: Array<IMenuItem | OperationModel>) { | ||||||
|     groups.forEach(group => { |     groups.forEach(group => { | ||||||
|       if (group.type !== 'group') { |       if (group.type !== 'group') { | ||||||
|         this.add(group.name, group.description || '', group.id); |         this.add(group.name, group.description || '', group.id); | ||||||
|       } |       } | ||||||
|       this.indexGroups(group.items); |       this.indexItems(group.items); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -13,6 +13,10 @@ export interface SearchDocument { | ||||||
|   id: string; |   id: string; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | export interface SearchResult extends SearchDocument { | ||||||
|  |   score: number; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| const store: { [id: string]: SearchDocument } = {}; | const store: { [id: string]: SearchDocument } = {}; | ||||||
| 
 | 
 | ||||||
| let resolveIndex: (v: lunr.Index) => void; | let resolveIndex: (v: lunr.Index) => void; | ||||||
|  | @ -39,7 +43,7 @@ export async function done() { | ||||||
|   resolveIndex(builder.build()); |   resolveIndex(builder.build()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export async function search(q: string): Promise<SearchDocument[]> { | export async function search(q: string): Promise<SearchResult[]> { | ||||||
|   if (q.trim().length === 0) { |   if (q.trim().length === 0) { | ||||||
|     return []; |     return []; | ||||||
|   } |   } | ||||||
|  | @ -54,5 +58,5 @@ export async function search(q: string): Promise<SearchDocument[]> { | ||||||
|           t.term(exp, {}); |           t.term(exp, {}); | ||||||
|         }); |         }); | ||||||
|     }) |     }) | ||||||
|     .map(res => store[res.ref]); |     .map(res => ({ ...store[res.ref], score: res.score })); | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user