@nu-art/search 0.400.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_core/SearchAddOn.d.ts +27 -0
- package/_core/SearchAddOn.js +1 -0
- package/_core/SearchContext.d.ts +58 -0
- package/_core/SearchContext.js +147 -0
- package/_core/SearchItem.d.ts +26 -0
- package/_core/SearchItem.js +1 -0
- package/_core/SearchSorter.d.ts +5 -0
- package/_core/SearchSorter.js +1 -0
- package/_core/index.d.ts +3 -0
- package/_core/index.js +3 -0
- package/_ui/add-ons/entity-filter/Component_AddOn_EntityFilter.d.ts +22 -0
- package/_ui/add-ons/entity-filter/Component_AddOn_EntityFilter.js +41 -0
- package/_ui/add-ons/entity-filter/Component_AddOn_EntityFilter.scss +14 -0
- package/_ui/add-ons/entity-filter/index.d.ts +2 -0
- package/_ui/add-ons/entity-filter/index.js +2 -0
- package/_ui/add-ons/entity-filter/types.d.ts +3 -0
- package/_ui/add-ons/entity-filter/types.js +8 -0
- package/_ui/add-ons/index.d.ts +3 -0
- package/_ui/add-ons/index.js +3 -0
- package/_ui/add-ons/search-term/Component_AddOn_SearchTerm.d.ts +17 -0
- package/_ui/add-ons/search-term/Component_AddOn_SearchTerm.js +16 -0
- package/_ui/add-ons/search-term/Component_AddOn_SearchTerm.scss +21 -0
- package/_ui/add-ons/search-term/index.d.ts +2 -0
- package/_ui/add-ons/search-term/index.js +2 -0
- package/_ui/add-ons/search-term/types.d.ts +3 -0
- package/_ui/add-ons/search-term/types.js +21 -0
- package/_ui/add-ons/search-terms/Component_AddOn_SearchTerms.d.ts +17 -0
- package/_ui/add-ons/search-terms/Component_AddOn_SearchTerms.js +16 -0
- package/_ui/add-ons/search-terms/Component_AddOn_SearchTerms.scss +21 -0
- package/_ui/add-ons/search-terms/index.d.ts +2 -0
- package/_ui/add-ons/search-terms/index.js +2 -0
- package/_ui/add-ons/search-terms/types.d.ts +3 -0
- package/_ui/add-ons/search-terms/types.js +31 -0
- package/_ui/components/Component_SearchAddOn.d.ts +16 -0
- package/_ui/components/Component_SearchAddOn.js +20 -0
- package/_ui/components/Component_SearchMeta/Component_SearchMeta.d.ts +16 -0
- package/_ui/components/Component_SearchMeta/Component_SearchMeta.js +66 -0
- package/_ui/components/Component_SearchMeta/Component_SearchMeta.scss +17 -0
- package/_ui/components/Component_SearchMeta/index.d.ts +1 -0
- package/_ui/components/Component_SearchMeta/index.js +1 -0
- package/_ui/components/Component_SearchResults/Component_SearchResults.d.ts +22 -0
- package/_ui/components/Component_SearchResults/Component_SearchResults.js +46 -0
- package/_ui/components/Component_SearchResults/Component_SearchResults.scss +10 -0
- package/_ui/components/Component_SearchResults/index.d.ts +1 -0
- package/_ui/components/Component_SearchResults/index.js +1 -0
- package/_ui/components/index.d.ts +3 -0
- package/_ui/components/index.js +3 -0
- package/_ui/index.d.ts +3 -0
- package/_ui/index.js +3 -0
- package/_ui/sorters/index.d.ts +2 -0
- package/_ui/sorters/index.js +2 -0
- package/_ui/sorters/search-term/SearchSorter_SearchTerm.d.ts +3 -0
- package/_ui/sorters/search-term/SearchSorter_SearchTerm.js +8 -0
- package/_ui/sorters/search-terms/SearchSorter_SearchTerms.d.ts +3 -0
- package/_ui/sorters/search-terms/SearchSorter_SearchTerms.js +8 -0
- package/index.d.ts +2 -0
- package/index.js +2 -0
- package/package.json +62 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { DBPointer } from '@nu-art/ts-common';
|
|
2
|
+
export type SearchResult = DBPointer & {
|
|
3
|
+
filterResults: {
|
|
4
|
+
[k: string]: {
|
|
5
|
+
value: any;
|
|
6
|
+
score?: number;
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export type SearchAddOnDef<Key extends string, //The addon key
|
|
11
|
+
ValueType extends any, //The type of the value held in the filter dictionary
|
|
12
|
+
MethodName extends string, //The name of the method that the search item needs to implement
|
|
13
|
+
ItemValueType extends any> = {
|
|
14
|
+
key: Key;
|
|
15
|
+
valueType: ValueType;
|
|
16
|
+
methodName: MethodName;
|
|
17
|
+
itemValueType: ItemValueType;
|
|
18
|
+
};
|
|
19
|
+
export type SearchAddOn<Def extends SearchAddOnDef<any, any, any, any>> = {
|
|
20
|
+
key: Def['key'];
|
|
21
|
+
methodName: Def['methodName'];
|
|
22
|
+
resultFilter: (value: NonNullable<Def['valueType']>, item: SearchResult) => {
|
|
23
|
+
pass: boolean;
|
|
24
|
+
score?: number;
|
|
25
|
+
};
|
|
26
|
+
isActive: (param: Def['valueType']) => boolean;
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Logger } from '@nu-art/ts-common';
|
|
2
|
+
import { SearchAddOn, SearchAddOnDef, SearchResult } from './SearchAddOn.js';
|
|
3
|
+
import { SearchItem } from './SearchItem.js';
|
|
4
|
+
import { SearchSorter } from './SearchSorter.js';
|
|
5
|
+
export interface SearchAddOnRenderer {
|
|
6
|
+
__onSearchFilterChanged: VoidFunction;
|
|
7
|
+
readonly addOn: SearchAddOn<any>;
|
|
8
|
+
}
|
|
9
|
+
export interface SearchResultsRenderer {
|
|
10
|
+
__onSearchResultsChanged: VoidFunction;
|
|
11
|
+
}
|
|
12
|
+
export declare class SearchContext extends Logger {
|
|
13
|
+
private searchItems;
|
|
14
|
+
private activeSearchItems;
|
|
15
|
+
private addOns;
|
|
16
|
+
private activeAddOns;
|
|
17
|
+
private sorters;
|
|
18
|
+
private minimumRequiredActiveAddons;
|
|
19
|
+
private readonly searchDebouncer;
|
|
20
|
+
private readonly filterDictionary;
|
|
21
|
+
private readonly _filterChangeListeners;
|
|
22
|
+
private searchResults?;
|
|
23
|
+
private searchTime?;
|
|
24
|
+
private readonly _searchResultChangeListeners;
|
|
25
|
+
constructor(key: string);
|
|
26
|
+
setSearchItems: (items: SearchItem<any, any>[]) => this;
|
|
27
|
+
setAddOns: (addOns: SearchAddOn<any>[]) => this;
|
|
28
|
+
setSorters: (sorters: SearchSorter<any>[]) => this;
|
|
29
|
+
setMinimumRequiredActiveAddOns: (num: number) => this;
|
|
30
|
+
private setActiveAddOns;
|
|
31
|
+
private setActiveSearchItems;
|
|
32
|
+
private getInitialSearchResults;
|
|
33
|
+
private search;
|
|
34
|
+
getActiveSearchItems: () => Readonly<{
|
|
35
|
+
module: import("@nu-art/thunderstorm-frontend").ModuleFE_BaseDB<any, import("@nu-art/thunderstorm-frontend/core/db-api-gen/db-def").DBApiFEConfig<any>>;
|
|
36
|
+
entityLabel: string;
|
|
37
|
+
addOnMethods: Readonly<{
|
|
38
|
+
[x: string]: (result: SearchResult) => unknown;
|
|
39
|
+
}>;
|
|
40
|
+
compatibleAddOnKeys: readonly PropertyKey[];
|
|
41
|
+
resultRenderer: (result: SearchResult, style?: import("react").CSSProperties) => import("react").ReactNode;
|
|
42
|
+
labelResolver: (result: SearchResult) => string;
|
|
43
|
+
}>[];
|
|
44
|
+
getSearchResults: () => SearchResult[] | undefined;
|
|
45
|
+
getSearchTime: () => number | undefined;
|
|
46
|
+
filter: {
|
|
47
|
+
set: <AddOn extends SearchAddOnDef<string, any, any, any>>(key: AddOn["key"], value: AddOn["valueType"]) => void;
|
|
48
|
+
get: <AddOn extends SearchAddOnDef<string, any, any, any>>(key: AddOn["key"]) => AddOn["valueType"] | undefined;
|
|
49
|
+
};
|
|
50
|
+
filterChangeListeners: {
|
|
51
|
+
register: (renderer: SearchAddOnRenderer) => void;
|
|
52
|
+
unregister: (renderer: SearchAddOnRenderer) => void;
|
|
53
|
+
};
|
|
54
|
+
searchResultChangeListeners: {
|
|
55
|
+
register: (renderer: SearchResultsRenderer) => void;
|
|
56
|
+
unregister: (renderer: SearchResultsRenderer) => void;
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { arrayIncludesAll, BadImplementationException, Debounce, Logger, removeItemFromArray } from '@nu-art/ts-common';
|
|
2
|
+
export class SearchContext extends Logger {
|
|
3
|
+
searchItems;
|
|
4
|
+
activeSearchItems;
|
|
5
|
+
addOns;
|
|
6
|
+
activeAddOns;
|
|
7
|
+
sorters;
|
|
8
|
+
minimumRequiredActiveAddons = 0;
|
|
9
|
+
searchDebouncer = new Debounce(() => this.search(), 200, 500);
|
|
10
|
+
filterDictionary = {};
|
|
11
|
+
_filterChangeListeners = [];
|
|
12
|
+
searchResults;
|
|
13
|
+
searchTime;
|
|
14
|
+
_searchResultChangeListeners = [];
|
|
15
|
+
constructor(key) {
|
|
16
|
+
super(`SearchContext-${key}`);
|
|
17
|
+
this.searchItems = [];
|
|
18
|
+
this.activeSearchItems = [];
|
|
19
|
+
this.addOns = [];
|
|
20
|
+
this.activeAddOns = [];
|
|
21
|
+
this.sorters = [];
|
|
22
|
+
}
|
|
23
|
+
//######################### Factory Logic #########################
|
|
24
|
+
setSearchItems = (items) => {
|
|
25
|
+
this.searchItems = items;
|
|
26
|
+
this.setActiveSearchItems();
|
|
27
|
+
this.logInfo('Set Search Items', this.searchItems);
|
|
28
|
+
return this;
|
|
29
|
+
};
|
|
30
|
+
setAddOns = (addOns) => {
|
|
31
|
+
this.addOns = addOns;
|
|
32
|
+
this.setActiveAddOns();
|
|
33
|
+
this.setActiveSearchItems();
|
|
34
|
+
return this;
|
|
35
|
+
};
|
|
36
|
+
setSorters = (sorters) => {
|
|
37
|
+
this.sorters = sorters;
|
|
38
|
+
return this;
|
|
39
|
+
};
|
|
40
|
+
setMinimumRequiredActiveAddOns = (num) => {
|
|
41
|
+
this.minimumRequiredActiveAddons = num;
|
|
42
|
+
return this;
|
|
43
|
+
};
|
|
44
|
+
//######################### Internal Logic #########################
|
|
45
|
+
setActiveAddOns = () => {
|
|
46
|
+
this.activeAddOns = this.addOns.filter(addOn => {
|
|
47
|
+
const currentValue = this.filterDictionary[addOn.key];
|
|
48
|
+
return addOn.isActive(currentValue);
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
setActiveSearchItems = () => {
|
|
52
|
+
const activeAddOnKeys = this.activeAddOns.map(addOn => addOn.key);
|
|
53
|
+
if (!activeAddOnKeys.length)
|
|
54
|
+
return this.activeSearchItems = [...this.searchItems];
|
|
55
|
+
this.activeSearchItems = this.searchItems.filter(searchItem => arrayIncludesAll(searchItem.compatibleAddOnKeys, activeAddOnKeys));
|
|
56
|
+
};
|
|
57
|
+
getInitialSearchResults = () => {
|
|
58
|
+
const results = [];
|
|
59
|
+
this.activeSearchItems.forEach(searchItem => {
|
|
60
|
+
const pointers = searchItem.module.cache.all().map(i => ({ dbKey: searchItem.module.dbDef.dbKey, id: i._id, filterResults: {} }));
|
|
61
|
+
results.push(...pointers);
|
|
62
|
+
});
|
|
63
|
+
return results;
|
|
64
|
+
};
|
|
65
|
+
search = () => {
|
|
66
|
+
if (this.activeAddOns.length < this.minimumRequiredActiveAddons) {
|
|
67
|
+
if (this.addOns.length) {
|
|
68
|
+
delete this.searchResults;
|
|
69
|
+
delete this.searchTime;
|
|
70
|
+
this._searchResultChangeListeners.forEach(listener => listener.__onSearchResultsChanged());
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const startTime = Date.now();
|
|
75
|
+
let searchResults = this.getInitialSearchResults();
|
|
76
|
+
//Map active search item to dbKeys for O(1) access
|
|
77
|
+
const searchItemMap = this.activeSearchItems.reduce((map, item) => {
|
|
78
|
+
map[item.module.dbDef.dbKey] = item;
|
|
79
|
+
return map;
|
|
80
|
+
}, {});
|
|
81
|
+
//Cycle filter the results by active add-ons
|
|
82
|
+
this.activeAddOns.forEach(addOn => {
|
|
83
|
+
const filterValue = this.filterDictionary[addOn.key];
|
|
84
|
+
searchResults = searchResults.filter(result => {
|
|
85
|
+
const searchItem = searchItemMap[result.dbKey];
|
|
86
|
+
result.filterResults[addOn.key] = { value: searchItem.addOnMethods[addOn.methodName](result) };
|
|
87
|
+
const filterResult = addOn.resultFilter(filterValue, result);
|
|
88
|
+
result.filterResults[addOn.key].score = filterResult.score;
|
|
89
|
+
return filterResult.pass;
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//Sort results
|
|
93
|
+
this.sorters.forEach(sorter => {
|
|
94
|
+
const addOn = this.activeAddOns.find(addOn => addOn.key === sorter.key);
|
|
95
|
+
if (!addOn) //No connected active addon was found, do not run sorter
|
|
96
|
+
return;
|
|
97
|
+
sorter.sortFunction(searchResults);
|
|
98
|
+
});
|
|
99
|
+
this.searchResults = searchResults;
|
|
100
|
+
this.searchTime = Date.now() - startTime;
|
|
101
|
+
this._searchResultChangeListeners.forEach(listener => listener.__onSearchResultsChanged());
|
|
102
|
+
};
|
|
103
|
+
//######################### Public Logic #########################
|
|
104
|
+
getActiveSearchItems = () => [...this.activeSearchItems];
|
|
105
|
+
getSearchResults = () => this.searchResults;
|
|
106
|
+
getSearchTime = () => this.searchTime;
|
|
107
|
+
filter = {
|
|
108
|
+
set: (key, value) => {
|
|
109
|
+
this.filterDictionary[key] = value;
|
|
110
|
+
//Re-calculate active addons and search items
|
|
111
|
+
this.setActiveAddOns();
|
|
112
|
+
this.setActiveSearchItems();
|
|
113
|
+
//Notify all listeners that filters have changed
|
|
114
|
+
this._filterChangeListeners.forEach(listener => listener.__onSearchFilterChanged());
|
|
115
|
+
//Trigger search
|
|
116
|
+
this.searchDebouncer.trigger();
|
|
117
|
+
},
|
|
118
|
+
get: (key) => {
|
|
119
|
+
return this.filterDictionary[key];
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
filterChangeListeners = {
|
|
123
|
+
register: (renderer) => {
|
|
124
|
+
if (this._filterChangeListeners.includes(renderer))
|
|
125
|
+
return;
|
|
126
|
+
const addOn = this.addOns.find(addOn => addOn.key === renderer.addOn.key);
|
|
127
|
+
if (!addOn) {
|
|
128
|
+
this.logError(renderer, this.addOns);
|
|
129
|
+
throw new BadImplementationException('Trying to register a listener that is not connected to an addon');
|
|
130
|
+
}
|
|
131
|
+
this._filterChangeListeners.push(renderer);
|
|
132
|
+
},
|
|
133
|
+
unregister: (renderer) => {
|
|
134
|
+
removeItemFromArray(this._filterChangeListeners, renderer);
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
searchResultChangeListeners = {
|
|
138
|
+
register: (renderer) => {
|
|
139
|
+
if (this._searchResultChangeListeners.includes(renderer))
|
|
140
|
+
return;
|
|
141
|
+
this._searchResultChangeListeners.push(renderer);
|
|
142
|
+
},
|
|
143
|
+
unregister: (renderer) => {
|
|
144
|
+
removeItemFromArray(this._searchResultChangeListeners, renderer);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { CSSProperties, ReactNode } from 'react';
|
|
2
|
+
import { DBProto } from '@nu-art/ts-common';
|
|
3
|
+
import { SearchAddOnDef, SearchResult } from './SearchAddOn.js';
|
|
4
|
+
import { ModuleFE_BaseDB } from '@nu-art/thunderstorm-frontend';
|
|
5
|
+
type AddOnTuple = readonly SearchAddOnDef<any, any, any, any>[];
|
|
6
|
+
type SearchAddOnsMethodExtractor<A extends AddOnTuple> = {
|
|
7
|
+
[M in A[number]['methodName']]: Extract<A[number], {
|
|
8
|
+
methodName: M;
|
|
9
|
+
}> extends {
|
|
10
|
+
itemValueType: infer IP;
|
|
11
|
+
} ? (result: SearchResult) => IP : never;
|
|
12
|
+
};
|
|
13
|
+
type SearchAddOnsKeyExtractor<A extends AddOnTuple> = {
|
|
14
|
+
readonly [K in keyof A]: A[K] extends {
|
|
15
|
+
key: infer Key extends PropertyKey;
|
|
16
|
+
} ? Key : never;
|
|
17
|
+
};
|
|
18
|
+
export type SearchItem<Proto extends DBProto<any>, A extends AddOnTuple> = Readonly<{
|
|
19
|
+
module: ModuleFE_BaseDB<Proto>;
|
|
20
|
+
entityLabel: string;
|
|
21
|
+
addOnMethods: Readonly<SearchAddOnsMethodExtractor<A>>;
|
|
22
|
+
compatibleAddOnKeys: Readonly<SearchAddOnsKeyExtractor<A>>;
|
|
23
|
+
resultRenderer: (result: SearchResult, style?: CSSProperties) => ReactNode;
|
|
24
|
+
labelResolver: (result: SearchResult) => string;
|
|
25
|
+
}>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/_core/index.d.ts
ADDED
package/_core/index.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Component_SearchAddOn } from '../../components/Component_SearchAddOn.js';
|
|
2
|
+
import { AddOnDef_EntityFilter } from './types.js';
|
|
3
|
+
import { InferProps, InferState } from '@nu-art/thunderstorm-frontend';
|
|
4
|
+
import './Component_AddOn_EntityFilter.scss';
|
|
5
|
+
import { SearchAddOn, SearchItem } from '../../../_core/index.js';
|
|
6
|
+
type Props = {
|
|
7
|
+
label?: string;
|
|
8
|
+
};
|
|
9
|
+
type State = {
|
|
10
|
+
label: string;
|
|
11
|
+
activeSearchItems: SearchItem<any, any>[];
|
|
12
|
+
};
|
|
13
|
+
export declare class Component_AddOn_EntityFilter extends Component_SearchAddOn<AddOnDef_EntityFilter, Props, State> {
|
|
14
|
+
addOn: SearchAddOn<AddOnDef_EntityFilter>;
|
|
15
|
+
protected deriveStateFromProps(nextProps: InferProps<this>, state: InferState<this>): InferState<this>;
|
|
16
|
+
private onItemSelected;
|
|
17
|
+
private onItemRemoved;
|
|
18
|
+
render(): import("react/jsx-runtime").JSX.Element | undefined;
|
|
19
|
+
private render_SelectedItem;
|
|
20
|
+
private render_ItemSelector;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { Component_SearchAddOn } from '../../components/Component_SearchAddOn.js';
|
|
3
|
+
import { AddOn_EntityFilter } from './types.js';
|
|
4
|
+
import { LL_H_C, SimpleListAdapter, TS_DropDown, TS_PropRenderer } from '@nu-art/thunderstorm-frontend';
|
|
5
|
+
import { TS_Icons } from '@nu-art/ts-styles';
|
|
6
|
+
import './Component_AddOn_EntityFilter.scss';
|
|
7
|
+
export class Component_AddOn_EntityFilter extends Component_SearchAddOn {
|
|
8
|
+
addOn = AddOn_EntityFilter;
|
|
9
|
+
// ######################### Life Cycle #########################
|
|
10
|
+
deriveStateFromProps(nextProps, state) {
|
|
11
|
+
state.label = nextProps.label ?? 'By Entity';
|
|
12
|
+
state.activeSearchItems = nextProps.context.getActiveSearchItems();
|
|
13
|
+
return state;
|
|
14
|
+
}
|
|
15
|
+
// ######################### Logic #########################
|
|
16
|
+
onItemSelected = (searchItem) => {
|
|
17
|
+
const items = this.state.value ? [...this.state.value] : [];
|
|
18
|
+
items.push(searchItem.module.dbDef.dbKey);
|
|
19
|
+
this.setValue(items);
|
|
20
|
+
};
|
|
21
|
+
onItemRemoved = (searchItem) => {
|
|
22
|
+
const items = (this.state.value ?? []).filter(item => item !== searchItem.module.dbDef.dbKey);
|
|
23
|
+
this.setValue(items);
|
|
24
|
+
};
|
|
25
|
+
// ######################### Render #########################
|
|
26
|
+
render() {
|
|
27
|
+
if (!this.state.activeSearchItems)
|
|
28
|
+
return;
|
|
29
|
+
return _jsx(TS_PropRenderer.Vertical, { label: this.state.label, className: 'search-add-on__entity-filter', children: _jsxs(LL_H_C, { className: 'search-add-on__entity-filter__item-list', children: [this.state.value?.map(this.render_SelectedItem), this.render_ItemSelector()] }) });
|
|
30
|
+
}
|
|
31
|
+
render_SelectedItem = (itemKey) => {
|
|
32
|
+
const searchItem = this.state.activeSearchItems.find(item => item.module.dbDef.dbKey === itemKey);
|
|
33
|
+
if (!searchItem)
|
|
34
|
+
return void this.logWarning(`Could not find a search item for key ${itemKey}`);
|
|
35
|
+
return _jsxs(LL_H_C, { className: 'search-add-on__entity-filter__selected-item', children: [searchItem.entityLabel, _jsx(TS_Icons.x.component, { onClick: () => this.onItemRemoved(searchItem) })] }, searchItem.module.dbDef.dbKey);
|
|
36
|
+
};
|
|
37
|
+
render_ItemSelector = () => {
|
|
38
|
+
const adapter = SimpleListAdapter(this.state.activeSearchItems, item => _jsx(_Fragment, { children: item.item.entityLabel }));
|
|
39
|
+
return _jsx(TS_DropDown, { adapter: adapter, selected: undefined, onSelected: this.onItemSelected, placeholder: 'Select an entity', queryFilter: item => !this.state.value?.includes(item.module.dbDef.dbKey) });
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SearchAddOn } from '../../../_core/index.js';
|
|
2
|
+
import { Component_SearchAddOn } from '../../components/Component_SearchAddOn.js';
|
|
3
|
+
import { AddOnDef_SearchTerm } from './types.js';
|
|
4
|
+
import './Component_AddOn_SearchTerm.scss';
|
|
5
|
+
import { InferProps, InferState } from '@nu-art/thunderstorm-frontend';
|
|
6
|
+
type Props = {
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
};
|
|
9
|
+
type State = {
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class Component_AddOn_SearchTerm extends Component_SearchAddOn<AddOnDef_SearchTerm, Props, State> {
|
|
13
|
+
protected deriveStateFromProps(nextProps: InferProps<this>, state: InferState<this>): InferState<this>;
|
|
14
|
+
addOn: SearchAddOn<AddOnDef_SearchTerm>;
|
|
15
|
+
render(): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { LL_H_C, TS_Input } from '@nu-art/thunderstorm-frontend';
|
|
3
|
+
import { Component_SearchAddOn } from '../../components/Component_SearchAddOn.js';
|
|
4
|
+
import { AddOn_SearchTerm } from './types.js';
|
|
5
|
+
import './Component_AddOn_SearchTerm.scss';
|
|
6
|
+
import { TS_Icons } from '@nu-art/ts-styles';
|
|
7
|
+
export class Component_AddOn_SearchTerm extends Component_SearchAddOn {
|
|
8
|
+
deriveStateFromProps(nextProps, state) {
|
|
9
|
+
state.placeholder = nextProps.placeholder;
|
|
10
|
+
return state;
|
|
11
|
+
}
|
|
12
|
+
addOn = AddOn_SearchTerm;
|
|
13
|
+
render() {
|
|
14
|
+
return _jsxs(LL_H_C, { className: 'search-add-on__search-term', children: [_jsx(TS_Input, { type: 'text', value: this.state.value, placeholder: this.state.placeholder, onChange: val => this.setValue(val.trimStart()) }), _jsx(TS_Icons.Search.component, {})] });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.search-add-on__search-term {
|
|
2
|
+
width: 100%;
|
|
3
|
+
min-width: 300px;
|
|
4
|
+
height: 28px;
|
|
5
|
+
gap: 16px;
|
|
6
|
+
background: #fff;
|
|
7
|
+
border-radius: 10px;
|
|
8
|
+
padding: 0 16px;
|
|
9
|
+
|
|
10
|
+
.icon--wrapper {
|
|
11
|
+
flex-shrink: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.ts-input {
|
|
15
|
+
width: 0;
|
|
16
|
+
flex: 1;
|
|
17
|
+
border: none;
|
|
18
|
+
max-width: unset;
|
|
19
|
+
outline: none;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
var SearchTermSortScore;
|
|
2
|
+
(function (SearchTermSortScore) {
|
|
3
|
+
SearchTermSortScore[SearchTermSortScore["ExactMatch"] = 0] = "ExactMatch";
|
|
4
|
+
SearchTermSortScore[SearchTermSortScore["StartsWith"] = 1] = "StartsWith";
|
|
5
|
+
SearchTermSortScore[SearchTermSortScore["Includes"] = 2] = "Includes";
|
|
6
|
+
})(SearchTermSortScore || (SearchTermSortScore = {}));
|
|
7
|
+
export const AddOn_SearchTerm = {
|
|
8
|
+
key: 'searchTerm',
|
|
9
|
+
methodName: 'getSearchTerm',
|
|
10
|
+
resultFilter: (value, result) => {
|
|
11
|
+
const itemValue = result.filterResults[AddOn_SearchTerm.key].value;
|
|
12
|
+
if (itemValue === value)
|
|
13
|
+
return { pass: true, score: SearchTermSortScore.ExactMatch };
|
|
14
|
+
if (itemValue.startsWith(value))
|
|
15
|
+
return { pass: true, score: SearchTermSortScore.StartsWith };
|
|
16
|
+
if (itemValue.includes(value))
|
|
17
|
+
return { pass: true, score: SearchTermSortScore.Includes };
|
|
18
|
+
return { pass: false };
|
|
19
|
+
},
|
|
20
|
+
isActive: (param) => !!param && param.length >= 3,
|
|
21
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SearchAddOn } from '../../../_core/index.js';
|
|
2
|
+
import { Component_SearchAddOn } from '../../components/Component_SearchAddOn.js';
|
|
3
|
+
import { AddOnDef_SearchTerms } from './types.js';
|
|
4
|
+
import './Component_AddOn_SearchTerms.scss';
|
|
5
|
+
import { InferProps, InferState } from '@nu-art/thunderstorm-frontend';
|
|
6
|
+
type Props = {
|
|
7
|
+
placeholder?: string;
|
|
8
|
+
};
|
|
9
|
+
type State = {
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
};
|
|
12
|
+
export declare class Component_AddOn_SearchTerms extends Component_SearchAddOn<AddOnDef_SearchTerms, Props, State> {
|
|
13
|
+
protected deriveStateFromProps(nextProps: InferProps<this>, state: InferState<this>): InferState<this>;
|
|
14
|
+
addOn: SearchAddOn<AddOnDef_SearchTerms>;
|
|
15
|
+
render(): import("react/jsx-runtime").JSX.Element;
|
|
16
|
+
}
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { LL_H_C, TS_Input } from '@nu-art/thunderstorm-frontend';
|
|
3
|
+
import { Component_SearchAddOn } from '../../components/Component_SearchAddOn.js';
|
|
4
|
+
import { AddOn_SearchTerms } from './types.js';
|
|
5
|
+
import './Component_AddOn_SearchTerms.scss';
|
|
6
|
+
import { TS_Icons } from '@nu-art/ts-styles';
|
|
7
|
+
export class Component_AddOn_SearchTerms extends Component_SearchAddOn {
|
|
8
|
+
deriveStateFromProps(nextProps, state) {
|
|
9
|
+
state.placeholder = nextProps.placeholder;
|
|
10
|
+
return state;
|
|
11
|
+
}
|
|
12
|
+
addOn = AddOn_SearchTerms;
|
|
13
|
+
render() {
|
|
14
|
+
return _jsxs(LL_H_C, { className: 'search-add-on__search-terms', children: [_jsx(TS_Input, { type: 'text', value: this.state.value, placeholder: this.state.placeholder, onChange: val => this.setValue(val.trimStart()) }), _jsx(TS_Icons.Search.component, {})] });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
.search-add-on__search-terms {
|
|
2
|
+
width: 100%;
|
|
3
|
+
min-width: 300px;
|
|
4
|
+
height: 28px;
|
|
5
|
+
gap: 16px;
|
|
6
|
+
background: #fff;
|
|
7
|
+
border-radius: 10px;
|
|
8
|
+
padding: 0 16px;
|
|
9
|
+
|
|
10
|
+
.icon--wrapper {
|
|
11
|
+
flex-shrink: 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.ts-input {
|
|
15
|
+
width: 0;
|
|
16
|
+
flex: 1;
|
|
17
|
+
border: none;
|
|
18
|
+
max-width: unset;
|
|
19
|
+
outline: none;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
var BaseScore;
|
|
2
|
+
(function (BaseScore) {
|
|
3
|
+
BaseScore[BaseScore["ExactMatch"] = 1] = "ExactMatch";
|
|
4
|
+
BaseScore[BaseScore["StartsWith"] = 2] = "StartsWith";
|
|
5
|
+
BaseScore[BaseScore["Includes"] = 3] = "Includes";
|
|
6
|
+
})(BaseScore || (BaseScore = {}));
|
|
7
|
+
const calcScore = (base, index) => {
|
|
8
|
+
return base - (1 / Math.pow(2, index));
|
|
9
|
+
};
|
|
10
|
+
export const AddOn_SearchTerms = {
|
|
11
|
+
key: 'searchTerms',
|
|
12
|
+
methodName: 'getSearchTerms',
|
|
13
|
+
isActive: (param) => !!param && param.length >= 3,
|
|
14
|
+
resultFilter: (value, result) => {
|
|
15
|
+
const terms = result.filterResults[AddOn_SearchTerms.key].value;
|
|
16
|
+
let index;
|
|
17
|
+
//Find exact match
|
|
18
|
+
index = terms.findIndex(term => term === value);
|
|
19
|
+
if (index !== -1)
|
|
20
|
+
return { pass: true, score: calcScore(BaseScore.ExactMatch, index) };
|
|
21
|
+
//Find StatsWith
|
|
22
|
+
index = terms.findIndex(term => term.startsWith(value));
|
|
23
|
+
if (index !== -1)
|
|
24
|
+
return { pass: true, score: calcScore(BaseScore.StartsWith, index) };
|
|
25
|
+
//Find Includes
|
|
26
|
+
index = terms.findIndex(term => term.includes(value));
|
|
27
|
+
if (index !== -1)
|
|
28
|
+
return { pass: true, score: calcScore(BaseScore.Includes, index) };
|
|
29
|
+
return { pass: false };
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ComponentSync } from '@nu-art/thunderstorm-frontend';
|
|
2
|
+
import { SearchAddOn, SearchAddOnDef, SearchAddOnRenderer, SearchContext } from '../../_core/index.js';
|
|
3
|
+
type Props = {
|
|
4
|
+
context: SearchContext;
|
|
5
|
+
};
|
|
6
|
+
type State<AddOnDef extends SearchAddOnDef<string, any, any, any>> = {
|
|
7
|
+
value?: AddOnDef['valueType'];
|
|
8
|
+
};
|
|
9
|
+
export declare abstract class Component_SearchAddOn<AddOnDef extends SearchAddOnDef<string, any, any, any>, _Props extends {} = {}, _State extends {} = {}, P extends _Props & Props = _Props & Props, S extends _State & State<AddOnDef> = _State & State<AddOnDef>> extends ComponentSync<P, S> implements SearchAddOnRenderer {
|
|
10
|
+
abstract readonly addOn: SearchAddOn<AddOnDef>;
|
|
11
|
+
__onSearchFilterChanged(): void;
|
|
12
|
+
componentDidMount(): void;
|
|
13
|
+
componentWillUnmount(): void;
|
|
14
|
+
protected setValue: (val?: AddOnDef["valueType"]) => void;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ComponentSync } from '@nu-art/thunderstorm-frontend';
|
|
2
|
+
import { compare } from '@nu-art/ts-common';
|
|
3
|
+
export class Component_SearchAddOn extends ComponentSync {
|
|
4
|
+
//######################### Life Cycle #########################
|
|
5
|
+
__onSearchFilterChanged() {
|
|
6
|
+
const nextValue = this.props.context.filter.get(this.addOn.key);
|
|
7
|
+
if (!compare(this.state.value, nextValue))
|
|
8
|
+
this.setState({ value: nextValue });
|
|
9
|
+
}
|
|
10
|
+
componentDidMount() {
|
|
11
|
+
this.props.context.filterChangeListeners.register(this);
|
|
12
|
+
}
|
|
13
|
+
componentWillUnmount() {
|
|
14
|
+
this.props.context.filterChangeListeners.unregister(this);
|
|
15
|
+
}
|
|
16
|
+
//######################### Logic #########################
|
|
17
|
+
setValue = (val) => {
|
|
18
|
+
this.props.context.filter.set(this.addOn.key, val);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { ComponentSync } from '@nu-art/thunderstorm-frontend';
|
|
2
|
+
import './Component_SearchMeta.scss';
|
|
3
|
+
import { SearchContext, SearchResultsRenderer } from '../../../_core/SearchContext.js';
|
|
4
|
+
type Props = {
|
|
5
|
+
context: SearchContext;
|
|
6
|
+
};
|
|
7
|
+
export declare class Component_SearchMeta extends ComponentSync<Props> implements SearchResultsRenderer {
|
|
8
|
+
__onSearchResultsChanged: () => void;
|
|
9
|
+
componentDidMount(): void;
|
|
10
|
+
componentWillUnmount(): void;
|
|
11
|
+
private printResults;
|
|
12
|
+
private exportResults;
|
|
13
|
+
render(): import("react/jsx-runtime").JSX.Element | undefined;
|
|
14
|
+
private renderTime;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ComponentSync, LL_H_C, ModuleFE_Thunderstorm, stopPropagation } from '@nu-art/thunderstorm-frontend';
|
|
3
|
+
import './Component_SearchMeta.scss';
|
|
4
|
+
import { filterInstances, formatTimestamp } from '@nu-art/ts-common';
|
|
5
|
+
import { ModuleFE_CSVParser } from '@nu-art/thunderstorm-frontend/modules/ModuleFE_CSVParser';
|
|
6
|
+
export class Component_SearchMeta extends ComponentSync {
|
|
7
|
+
//######################### Life Cycle #########################
|
|
8
|
+
__onSearchResultsChanged = () => {
|
|
9
|
+
this.forceUpdate();
|
|
10
|
+
};
|
|
11
|
+
componentDidMount() {
|
|
12
|
+
this.props.context.searchResultChangeListeners.register(this);
|
|
13
|
+
}
|
|
14
|
+
componentWillUnmount() {
|
|
15
|
+
this.props.context.searchResultChangeListeners.unregister(this);
|
|
16
|
+
}
|
|
17
|
+
//######################### Logic #########################
|
|
18
|
+
printResults = (e) => {
|
|
19
|
+
if (!e.metaKey)
|
|
20
|
+
return;
|
|
21
|
+
stopPropagation(e);
|
|
22
|
+
this.logInfo('SearchResults', this.props.context.getSearchResults());
|
|
23
|
+
};
|
|
24
|
+
exportResults = (e) => {
|
|
25
|
+
const results = this.props.context.getSearchResults();
|
|
26
|
+
if (!results?.length)
|
|
27
|
+
return;
|
|
28
|
+
stopPropagation(e);
|
|
29
|
+
const searchItemMap = this.props.context.getActiveSearchItems().reduce((map, searchItem) => {
|
|
30
|
+
map[searchItem.module.dbDef.dbKey] = searchItem;
|
|
31
|
+
return map;
|
|
32
|
+
}, {});
|
|
33
|
+
//Map results csv ready objects
|
|
34
|
+
const objects = filterInstances(results.map(result => {
|
|
35
|
+
const searchItem = searchItemMap[result.dbKey];
|
|
36
|
+
if (!searchItem)
|
|
37
|
+
return;
|
|
38
|
+
return {
|
|
39
|
+
collection: result.dbKey,
|
|
40
|
+
id: result.id,
|
|
41
|
+
label: searchItem.labelResolver(result),
|
|
42
|
+
};
|
|
43
|
+
}));
|
|
44
|
+
const str = ModuleFE_CSVParser.toString(objects);
|
|
45
|
+
const fileName = `Search Results - [${formatTimestamp('DD/MM/YYYY-HH:mm:ss')}]`;
|
|
46
|
+
ModuleFE_Thunderstorm.downloadFile({
|
|
47
|
+
fileName,
|
|
48
|
+
content: str,
|
|
49
|
+
mimeType: 'text/csv',
|
|
50
|
+
});
|
|
51
|
+
};
|
|
52
|
+
//######################### Render #########################
|
|
53
|
+
render() {
|
|
54
|
+
const searchResults = this.props.context.getSearchResults();
|
|
55
|
+
if (!searchResults?.length)
|
|
56
|
+
return;
|
|
57
|
+
return _jsxs(LL_H_C, { className: 'c__search-meta', onClick: this.printResults, children: [_jsxs("div", { className: 'c__search-meta__results', onClick: this.exportResults, children: [searchResults.length, " Results"] }), this.renderTime()] });
|
|
58
|
+
}
|
|
59
|
+
renderTime = () => {
|
|
60
|
+
const searchTime = this.props.context.getSearchTime();
|
|
61
|
+
if (!searchTime)
|
|
62
|
+
return;
|
|
63
|
+
const str = searchTime >= 1000 ? `${searchTime / 1000}s` : `${searchTime}ms`;
|
|
64
|
+
return _jsx("div", { className: 'c__search-meta__time', children: str });
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
@use '@nu-art/ts-styles' as S;
|
|
2
|
+
|
|
3
|
+
.c__search-meta {
|
|
4
|
+
width: 100%;
|
|
5
|
+
height: 28px;
|
|
6
|
+
justify-content: space-between;
|
|
7
|
+
|
|
8
|
+
.c__search-meta__time {
|
|
9
|
+
color: inherit;
|
|
10
|
+
font: inherit;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.c__search-meta__results {
|
|
14
|
+
font: inherit;
|
|
15
|
+
@include S.mouse-interactive-text(inherit, S.dark-blue(4), S.dark-blue(3));
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Component_SearchMeta.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Component_SearchMeta.js';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ComponentSync } from '@nu-art/thunderstorm-frontend';
|
|
2
|
+
import { SearchContext, SearchResult, SearchResultsRenderer } from '../../../_core/index.js';
|
|
3
|
+
import './Component_SearchResults.scss';
|
|
4
|
+
type Props = {
|
|
5
|
+
context: SearchContext;
|
|
6
|
+
itemHeight: number;
|
|
7
|
+
maxItemsOnScreen: number;
|
|
8
|
+
};
|
|
9
|
+
type State = {
|
|
10
|
+
searchResults?: SearchResult[];
|
|
11
|
+
maxHeight: number;
|
|
12
|
+
};
|
|
13
|
+
export declare class Component_SearchResults extends ComponentSync<Props, State> implements SearchResultsRenderer {
|
|
14
|
+
protected deriveStateFromProps(nextProps: Props, state: State): State;
|
|
15
|
+
__onSearchResultsChanged: () => void;
|
|
16
|
+
componentDidMount(): void;
|
|
17
|
+
componentWillUnmount(): void;
|
|
18
|
+
private getList;
|
|
19
|
+
render(): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
private render_NoResults;
|
|
21
|
+
}
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ComponentSync, LL_V_L, VirtualizedList } from '@nu-art/thunderstorm-frontend';
|
|
3
|
+
import './Component_SearchResults.scss';
|
|
4
|
+
import { filterInstances } from '@nu-art/ts-common';
|
|
5
|
+
export class Component_SearchResults extends ComponentSync {
|
|
6
|
+
//######################### Life Cycle #########################
|
|
7
|
+
deriveStateFromProps(nextProps, state) {
|
|
8
|
+
state.maxHeight = nextProps.maxItemsOnScreen * nextProps.itemHeight;
|
|
9
|
+
return state;
|
|
10
|
+
}
|
|
11
|
+
__onSearchResultsChanged = () => {
|
|
12
|
+
this.setState({ searchResults: this.props.context.getSearchResults() });
|
|
13
|
+
};
|
|
14
|
+
componentDidMount() {
|
|
15
|
+
this.props.context.searchResultChangeListeners.register(this);
|
|
16
|
+
}
|
|
17
|
+
componentWillUnmount() {
|
|
18
|
+
this.props.context.searchResultChangeListeners.unregister(this);
|
|
19
|
+
}
|
|
20
|
+
//######################### Render #########################
|
|
21
|
+
getList = () => {
|
|
22
|
+
if (!this.state.searchResults?.length)
|
|
23
|
+
return [];
|
|
24
|
+
const activeSearchItemMap = this.props.context.getActiveSearchItems().reduce((map, item) => {
|
|
25
|
+
map[item.module.dbDef.dbKey] = item;
|
|
26
|
+
return map;
|
|
27
|
+
}, {});
|
|
28
|
+
return filterInstances(this.state.searchResults.map(result => {
|
|
29
|
+
const item = activeSearchItemMap[result.dbKey];
|
|
30
|
+
if (!item)
|
|
31
|
+
return;
|
|
32
|
+
return (style) => item.resultRenderer(result, style);
|
|
33
|
+
}));
|
|
34
|
+
};
|
|
35
|
+
//######################### Render #########################
|
|
36
|
+
render() {
|
|
37
|
+
if (!this.state.searchResults?.length)
|
|
38
|
+
return this.render_NoResults();
|
|
39
|
+
const list = this.getList();
|
|
40
|
+
const height = Math.min(list.length * this.props.itemHeight, this.state.maxHeight);
|
|
41
|
+
return _jsx(VirtualizedList, { className: 'c__search-results', width: 0, height: height, itemHeight: this.props.itemHeight, listToRender: list, omitWrapper: true });
|
|
42
|
+
}
|
|
43
|
+
render_NoResults = () => {
|
|
44
|
+
return _jsx(LL_V_L, { className: 'c__search-results no-results', children: "No results to show" });
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Component_SearchResults.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Component_SearchResults.js';
|
package/_ui/index.d.ts
ADDED
package/_ui/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { sortArray } from '@nu-art/ts-common';
|
|
2
|
+
export const SearchSorter_SearchTerm = {
|
|
3
|
+
key: 'searchTerm',
|
|
4
|
+
sortFunction: (results) => {
|
|
5
|
+
sortArray(results, result => result.filterResults[SearchSorter_SearchTerm.key].value.length);
|
|
6
|
+
sortArray(results, result => result.filterResults[SearchSorter_SearchTerm.key].score);
|
|
7
|
+
}
|
|
8
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { sortArray } from '@nu-art/ts-common';
|
|
2
|
+
export const SearchSorter_SearchTerms = {
|
|
3
|
+
key: 'searchTerms',
|
|
4
|
+
sortFunction: (results) => {
|
|
5
|
+
sortArray(results, result => result.filterResults[SearchSorter_SearchTerms.key].value.length);
|
|
6
|
+
sortArray(results, result => result.filterResults[SearchSorter_SearchTerms.key].score);
|
|
7
|
+
}
|
|
8
|
+
};
|
package/index.d.ts
ADDED
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nu-art/search",
|
|
3
|
+
"version": "0.400.7",
|
|
4
|
+
"description": "Search",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"TacB0sS",
|
|
7
|
+
"express",
|
|
8
|
+
"infra",
|
|
9
|
+
"nu-art",
|
|
10
|
+
"thunderstorm",
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/nu-art-js/thunderstorm",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/nu-art-js/thunderstorm/issues"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+ssh://git@github.com:nu-art-js/thunderstorm.git"
|
|
20
|
+
},
|
|
21
|
+
"license": "Apache-2.0",
|
|
22
|
+
"author": "TacB0sS",
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc"
|
|
25
|
+
},
|
|
26
|
+
"contributors": [
|
|
27
|
+
{
|
|
28
|
+
"name": "TacB0sS"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "Cipher",
|
|
32
|
+
"url": "https://www.linkedin.com/in/itay-leybovich-470b87229/"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"directory": "dist",
|
|
37
|
+
"linkDirectory": true
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@nu-art/ts-common": "0.400.7",
|
|
41
|
+
"@nu-art/ts-styles": "0.400.7",
|
|
42
|
+
"@nu-art/thunderstorm-frontend": "0.400.7",
|
|
43
|
+
"react": "^18.0.0"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/react": "^18.0.0"
|
|
47
|
+
},
|
|
48
|
+
"unitConfig": {
|
|
49
|
+
"type": "typescript-lib"
|
|
50
|
+
},
|
|
51
|
+
"type": "module",
|
|
52
|
+
"exports": {
|
|
53
|
+
".": {
|
|
54
|
+
"types": "./index.d.ts",
|
|
55
|
+
"import": "./index.js"
|
|
56
|
+
},
|
|
57
|
+
"./*": {
|
|
58
|
+
"types": "./*.d.ts",
|
|
59
|
+
"import": "./*.js"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|