@bridgeline-digital/hawksearch-handlebars-ui 1.0.0-beta.0

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.
Files changed (118) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.json +153 -0
  3. package/.husky/pre-commit +5 -0
  4. package/.lintstagedrc.json +4 -0
  5. package/.prettierignore +7 -0
  6. package/.prettierrc.json +19 -0
  7. package/.vscode/launch.json +15 -0
  8. package/custom1.html +52 -0
  9. package/custom2.html +44 -0
  10. package/gulpfile.js +73 -0
  11. package/index.html +39 -0
  12. package/package.json +57 -0
  13. package/src/assets/icons/chevron-back.svg +4 -0
  14. package/src/assets/icons/chevron-down.svg +3 -0
  15. package/src/assets/icons/chevron-forward.svg +4 -0
  16. package/src/assets/icons/chevron-left.svg +3 -0
  17. package/src/assets/icons/chevron-right.svg +3 -0
  18. package/src/assets/icons/chevron-up.svg +3 -0
  19. package/src/assets/icons/cross.svg +3 -0
  20. package/src/assets/icons/help.svg +4 -0
  21. package/src/assets/icons/minus.svg +3 -0
  22. package/src/assets/icons/plus.svg +7 -0
  23. package/src/assets/images/icons.svg +1 -0
  24. package/src/assets/images/placeholder.png +0 -0
  25. package/src/components/autocomplete/autocomplete.component.hbs +60 -0
  26. package/src/components/autocomplete/autocomplete.component.ts +124 -0
  27. package/src/components/base.component.ts +120 -0
  28. package/src/components/facet-types/base-facet.component.ts +114 -0
  29. package/src/components/facet-types/checkbox-list-facet/checkbox-list-facet.component.hbs +6 -0
  30. package/src/components/facet-types/checkbox-list-facet/checkbox-list-facet.component.ts +73 -0
  31. package/src/components/facet-types/checkbox-list-facet/checkbox-list.partial.hbs +42 -0
  32. package/src/components/facet-types/color-facet/color-facet.component.hbs +29 -0
  33. package/src/components/facet-types/color-facet/color-facet.component.ts +26 -0
  34. package/src/components/facet-types/index.ts +6 -0
  35. package/src/components/facet-types/linked-list-facet/link-list-facet.component.hbs +17 -0
  36. package/src/components/facet-types/linked-list-facet/link-list-facet.component.ts +32 -0
  37. package/src/components/facet-types/range-slider-facet/range-slider-facet.component.hbs +11 -0
  38. package/src/components/facet-types/range-slider-facet/range-slider-facet.component.ts +107 -0
  39. package/src/components/facet-types/search-within-facet/search-within-facet.component.hbs +3 -0
  40. package/src/components/facet-types/search-within-facet/search-within-facet.component.ts +33 -0
  41. package/src/components/facet-types/size-facet/size-facet.component.hbs +29 -0
  42. package/src/components/facet-types/size-facet/size-facet.component.ts +30 -0
  43. package/src/components/facet-wrapper/facet-wrapper.component.hbs +36 -0
  44. package/src/components/facet-wrapper/facet-wrapper.component.ts +62 -0
  45. package/src/components/facets-list/facets-list.component.hbs +11 -0
  46. package/src/components/facets-list/facets-list.component.ts +92 -0
  47. package/src/components/icon/icon.component.hbs +3 -0
  48. package/src/components/icon/icon.component.ts +40 -0
  49. package/src/components/index.ts +18 -0
  50. package/src/components/modified-query/modified-query.component.hbs +7 -0
  51. package/src/components/modified-query/modified-query.component.ts +38 -0
  52. package/src/components/page-size/page-size.component.hbs +7 -0
  53. package/src/components/page-size/page-size.component.ts +35 -0
  54. package/src/components/pagination/pagination.component.hbs +34 -0
  55. package/src/components/pagination/pagination.component.ts +85 -0
  56. package/src/components/query-suggestions/query-suggestions.component.hbs +3 -0
  57. package/src/components/query-suggestions/query-suggestions.component.ts +66 -0
  58. package/src/components/range-slider/range-slider.component.hbs +9 -0
  59. package/src/components/range-slider/range-slider.component.ts +190 -0
  60. package/src/components/search/search.component.hbs +4 -0
  61. package/src/components/search/search.component.ts +93 -0
  62. package/src/components/search-results/search-results.component.hbs +29 -0
  63. package/src/components/search-results/search-results.component.ts +17 -0
  64. package/src/components/search-results-item/search-results-item.component.hbs +23 -0
  65. package/src/components/search-results-item/search-results-item.component.ts +99 -0
  66. package/src/components/search-results-list/search-results-list.component.hbs +15 -0
  67. package/src/components/search-results-list/search-results-list.component.ts +24 -0
  68. package/src/components/selected-facets/selected-facets.component.hbs +11 -0
  69. package/src/components/selected-facets/selected-facets.component.ts +81 -0
  70. package/src/components/sorting/sorting.component.hbs +7 -0
  71. package/src/components/sorting/sorting.component.ts +33 -0
  72. package/src/components/tabs/tabs.component.hbs +7 -0
  73. package/src/components/tabs/tabs.component.ts +35 -0
  74. package/src/components/tooltip/tooltip.component.hbs +6 -0
  75. package/src/components/tooltip/tooltip.component.ts +48 -0
  76. package/src/helpers/formatters.ts +15 -0
  77. package/src/helpers/index.ts +1 -0
  78. package/src/index.ts +125 -0
  79. package/src/models/autocomplete.models.ts +71 -0
  80. package/src/models/component.models.ts +27 -0
  81. package/src/models/global.models.ts +78 -0
  82. package/src/models/index.ts +7 -0
  83. package/src/models/raw-autocomplete.models.ts +46 -0
  84. package/src/models/raw-search.models.ts +130 -0
  85. package/src/models/search.models.ts +144 -0
  86. package/src/models/tracking.models.ts +33 -0
  87. package/src/scss/components/_autocomplete.scss +55 -0
  88. package/src/scss/components/_facets.scss +287 -0
  89. package/src/scss/components/_icons.scss +17 -0
  90. package/src/scss/components/_modified-query.scss +11 -0
  91. package/src/scss/components/_page-size.scss +2 -0
  92. package/src/scss/components/_pagination.scss +23 -0
  93. package/src/scss/components/_query-suggestions.scss +7 -0
  94. package/src/scss/components/_range-slider.scss +50 -0
  95. package/src/scss/components/_search-results-item.scss +64 -0
  96. package/src/scss/components/_search.scss +4 -0
  97. package/src/scss/components/_selected-facets.scss +24 -0
  98. package/src/scss/components/_sorting.scss +2 -0
  99. package/src/scss/components/_tabs.scss +51 -0
  100. package/src/scss/components/_tooltips.scss +29 -0
  101. package/src/scss/general/_forms.scss +82 -0
  102. package/src/scss/general/_grid-layout.scss +44 -0
  103. package/src/scss/general/_images.scss +3 -0
  104. package/src/scss/general/_typography.scss +15 -0
  105. package/src/scss/hawksearch.scss +35 -0
  106. package/src/scss/includes/_breakpoints.scss +51 -0
  107. package/src/scss/includes/_components.scss +14 -0
  108. package/src/scss/includes/_general.scss +4 -0
  109. package/src/scss/includes/_reset.scss +203 -0
  110. package/src/scss/includes/_utility-classes.scss +85 -0
  111. package/src/services/autocomplete.service.ts +104 -0
  112. package/src/services/base.service.ts +93 -0
  113. package/src/services/index.ts +3 -0
  114. package/src/services/search.service.ts +754 -0
  115. package/src/services/tracking.service.ts +136 -0
  116. package/tsconfig.json +22 -0
  117. package/typings.d.ts +21 -0
  118. package/webpack.config.js +75 -0
@@ -0,0 +1,107 @@
1
+ import { RangeSliderEventData } from '@models';
2
+ import { searchService } from '@services';
3
+ import { BaseFacetComponent } from '../base-facet.component';
4
+ import defaultHtml from './range-slider-facet.component.hbs';
5
+
6
+ export class RangeSliderFacetComponent extends BaseFacetComponent {
7
+ protected customTemplatePropertyName = 'rangeSliderFacet';
8
+ protected defaultHtml = defaultHtml;
9
+
10
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
11
+ if (!this.data || this.data.rangeMin === undefined || this.data.rangeMax === undefined) {
12
+ return '';
13
+ }
14
+
15
+ const range = this.data.rangeMax - this.data.rangeMin;
16
+ const minValue = Math.floor(this.data.rangeStart || this.data.rangeMin || 0);
17
+ const maxValue = Math.ceil(this.data.rangeEnd || this.data.rangeMax || 0);
18
+
19
+ const html = template({
20
+ id: this.data.id,
21
+ field: this.data.field,
22
+ minValue: minValue,
23
+ maxValue: maxValue,
24
+ sliderMin: Math.floor(((minValue - this.data.rangeMin ?? 0) / range) * 100),
25
+ sliderMax: Math.ceil((maxValue / range) * 100)
26
+ });
27
+
28
+ return html;
29
+ }
30
+
31
+ protected bindChildElements(): void {
32
+ this.shadowRoot?.querySelectorAll('[hawksearch-min]').forEach((e) => {
33
+ e.addEventListener('blur', (event: Event) => {
34
+ const element = event.currentTarget as HTMLInputElement;
35
+ let value = parseFloat(element.value);
36
+
37
+ if (isNaN(value)) {
38
+ value = 0;
39
+ }
40
+
41
+ if (value != this.data!.rangeStart && value <= this.data!.rangeEnd!) {
42
+ this.setFacetValue(value, this.data!.rangeEnd!);
43
+ }
44
+ });
45
+ });
46
+
47
+ this.shadowRoot?.querySelectorAll('[hawksearch-max]').forEach((e) => {
48
+ e.addEventListener('blur', (event: Event) => {
49
+ const element = event.currentTarget as HTMLInputElement;
50
+ let value = parseFloat(element.value);
51
+
52
+ if (isNaN(value)) {
53
+ value = 0;
54
+ }
55
+
56
+ if (value != this.data!.rangeEnd && value >= this.data!.rangeStart!) {
57
+ this.setFacetValue(this.data!.rangeStart!, value);
58
+ }
59
+ });
60
+ });
61
+
62
+ this.shadowRoot?.querySelectorAll('hawksearch-range-slider').forEach((e) => {
63
+ e.addEventListener('hawksearch:range-slider-dragging', ((event: CustomEvent): void => {
64
+ const data: RangeSliderEventData = event.detail;
65
+ const range = this.getRange(data.min, data.max);
66
+
67
+ this.updateInputElements(range.min, range.max);
68
+ }) as EventListener);
69
+
70
+ e.addEventListener('hawksearch:range-slider-changed', ((event: CustomEvent): void => {
71
+ const data: RangeSliderEventData = event.detail;
72
+ const range = this.getRange(data.min, data.max);
73
+
74
+ this.setFacetValue(range.min, range.max);
75
+ }) as EventListener);
76
+ });
77
+ }
78
+
79
+ private getRange(sliderMin: number, sliderMax: number): { min: number; max: number } {
80
+ const rangeMin = Math.floor(this.data?.rangeMin ?? 0);
81
+ const rangeMax = Math.ceil(this.data?.rangeMax ?? 0);
82
+ const range = rangeMax - rangeMin;
83
+ const min = Math.floor((range * sliderMin) / 100 + rangeMin);
84
+ const max = Math.ceil((rangeMax * sliderMax) / 100);
85
+
86
+ return { min: min, max: max };
87
+ }
88
+
89
+ private updateInputElements(min: number, max: number): void {
90
+ const minElement = this.shadowRoot?.querySelector('[hawksearch-min]') as HTMLInputElement | null;
91
+ const maxElement = this.shadowRoot?.querySelector('[hawksearch-max]') as HTMLInputElement | null;
92
+
93
+ if (minElement) {
94
+ minElement.value = min.toString();
95
+ }
96
+
97
+ if (maxElement) {
98
+ maxElement.value = max.toString();
99
+ }
100
+ }
101
+
102
+ private setFacetValue(min: number, max: number): void {
103
+ this.updateInputElements(min, max);
104
+
105
+ searchService.setFacetValue(this.data!.field!, `${min.toFixed(2)},${max.toFixed(2)}`);
106
+ }
107
+ }
@@ -0,0 +1,3 @@
1
+ <div class='search-within-facet'>
2
+ <input type='text' hawksearch-input value='{{value}}' class='search-within-facet__input' />
3
+ </div>
@@ -0,0 +1,33 @@
1
+ import { searchService } from '@services';
2
+ import { BaseFacetComponent } from '../base-facet.component';
3
+ import defaultHtml from './search-within-facet.component.hbs';
4
+
5
+ export class SearchWithinFacetComponent extends BaseFacetComponent {
6
+ protected customTemplatePropertyName = 'searchWithinFacet';
7
+ protected defaultHtml = defaultHtml;
8
+
9
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
10
+ if (!this.data) {
11
+ return '';
12
+ }
13
+
14
+ const html = template({
15
+ value: this.data.searchWithin ?? ''
16
+ });
17
+
18
+ return html;
19
+ }
20
+
21
+ protected bindChildElements(): void {
22
+ this.shadowRoot?.querySelectorAll('[hawksearch-input]').forEach((e) => {
23
+ e.addEventListener('change', (event: Event) => {
24
+ event.preventDefault();
25
+
26
+ const element = event.currentTarget as HTMLInputElement;
27
+ const value = element.value.trim();
28
+
29
+ searchService.searchWithin(value);
30
+ });
31
+ });
32
+ }
33
+ }
@@ -0,0 +1,29 @@
1
+ <div class='size-facet'>
2
+ <div class='row row--tight size-facet__items'>
3
+ {{#each values}}
4
+ {{#if visible}}
5
+ <div class='column column--3 size-facet__item{{attribute ' size-facet__item--selected' selected}}'>
6
+ <div hawksearch-facet-value='{{value}}' class='size-facet__item__outer'>
7
+ <div hawksearch-facet-value='{{value}}' class='size-facet__item__inner'>
8
+ {{title}}
9
+ </div>
10
+ </div>
11
+ <span class='size-facet__item__actions'>
12
+ {{#if excluded}}
13
+ <span hawksearch-facet-value-include='{{value}}' class='size-facet__item__actions__item' title='Include'>
14
+ <hawksearch-icon name='plus'></hawksearch-icon>
15
+ </span>
16
+ {{else}}
17
+ <span hawksearch-facet-value-exclude='{{value}}' class='size-facet__item__actions__item' title='Exclude'>
18
+ <hawksearch-icon name='minus'></hawksearch-icon>
19
+ </span>
20
+ {{/if}}
21
+ </span>
22
+ </div>
23
+ {{/if}}
24
+ {{/each}}
25
+ </div>
26
+ {{#if showToggle}}
27
+ <a hawksearch-facet-toggle class='facet__toggle'>{{toggleText}}</a>
28
+ {{/if}}
29
+ </div>
@@ -0,0 +1,30 @@
1
+ import { BaseFacetComponent } from '../base-facet.component';
2
+ import defaultHtml from './size-facet.component.hbs';
3
+
4
+ export class SizeFacetComponent extends BaseFacetComponent {
5
+ protected customTemplatePropertyName = 'colorFacet';
6
+ protected defaultHtml = defaultHtml;
7
+
8
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
9
+ if (!this.data) {
10
+ return '';
11
+ }
12
+
13
+ const filterRegex = this.state.filter ? new RegExp(this.state.filter, 'i') : undefined;
14
+
15
+ const html = template({
16
+ values:
17
+ this.data.values?.map((v, i) => ({
18
+ ...v,
19
+ visible:
20
+ (!filterRegex && (this.state.toggled || !this.data!.truncateThreshold || i < this.data!.truncateThreshold!)) ||
21
+ (!!filterRegex && filterRegex.test(v.title ?? ''))
22
+ })) ?? [],
23
+ showToggle: !!this.data.truncateThreshold && (this.data.values?.length ?? 0) > this.data.truncateThreshold,
24
+ toggleText: this.state.toggled ? 'Show fewer' : 'Show more',
25
+ expanded: this.state.toggled
26
+ });
27
+
28
+ return html;
29
+ }
30
+ }
@@ -0,0 +1,36 @@
1
+ <div class='facet'>
2
+ <div hawksearch-facet-heading class='facet__heading{{attribute " facet__heading--collapsible" collapsible}}'>
3
+ {{title}}
4
+ {{#if tooltip}}
5
+ <hawksearch-tooltip text='{{tooltip}}'></hawksearch-tooltip>
6
+ {{/if}}
7
+ {{#if collapsible}}
8
+ <hawksearch-icon name='{{if-else collapsed "chevron-right" "chevron-down"}}' size='1.5em' class='facet__heading__toggle'></hawksearch-icon>
9
+ {{/if}}
10
+ </div>
11
+ {{#unless collapsed}}
12
+ <div class='facet__content'>
13
+ {{#if searchable}}
14
+ <input type='text' placeholder='Quick Lookup' hawksearch-facet-search value='{{filter}}' class='facet__search' />
15
+ {{/if}}
16
+ {{#if (eq type 'checkbox')}}
17
+ <hawksearch-checkbox-list-facet hawksearch-facet></hawksearch-checkbox-list-facet>
18
+ {{/if}}
19
+ {{#if (eq type 'color')}}
20
+ <hawksearch-color-facet hawksearch-facet></hawksearch-color-facet>
21
+ {{/if}}
22
+ {{#if (eq type 'link')}}
23
+ <hawksearch-link-list-facet hawksearch-facet></hawksearch-link-list-facet>
24
+ {{/if}}
25
+ {{#if (eq type 'range-slider')}}
26
+ <hawksearch-range-slider-facet hawksearch-facet></hawksearch-range-slider-facet>
27
+ {{/if}}
28
+ {{#if (eq type 'search')}}
29
+ <hawksearch-search-within-facet hawksearch-facet></hawksearch-search-within-facet>
30
+ {{/if}}
31
+ {{#if (eq type 'size')}}
32
+ <hawksearch-size-facet hawksearch-facet></hawksearch-size-facet>
33
+ {{/if}}
34
+ </div>
35
+ {{/unless}}
36
+ </div>
@@ -0,0 +1,62 @@
1
+ import { Facet, FacetState } from '@models';
2
+ import { BaseComponent } from '../base.component';
3
+ import { BaseFacetComponent } from '../facet-types/base-facet.component';
4
+ import defaultHtml from './facet-wrapper.component.hbs';
5
+
6
+ export class FacetWrapperComponent extends BaseComponent<Facet> {
7
+ protected bindEvent = undefined;
8
+ protected customTemplatePropertyName = 'facetWrapper';
9
+ protected defaultHtml = defaultHtml;
10
+
11
+ state!: FacetState;
12
+
13
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
14
+ if (!this.data) {
15
+ return '';
16
+ }
17
+
18
+ const html = template({
19
+ ...this.data,
20
+ collapsed: this.state.collapsed ?? this.data.collapsed ?? false,
21
+ filter: this.state.filter ?? ''
22
+ });
23
+
24
+ return html;
25
+ }
26
+
27
+ protected bindChildElements(): void {
28
+ this.shadowRoot?.querySelectorAll('[hawksearch-facet-heading]').forEach((e) => {
29
+ e.addEventListener('click', (event: Event) => {
30
+ event.preventDefault();
31
+
32
+ if (this.data?.collapsible) {
33
+ this.state.collapsed = !this.state.collapsed;
34
+
35
+ this.renderContent();
36
+ }
37
+ });
38
+ });
39
+
40
+ this.shadowRoot?.querySelectorAll('[hawksearch-facet-search]').forEach((e) => {
41
+ e.addEventListener('keyup', (event: Event) => {
42
+ const element = event.currentTarget as HTMLInputElement;
43
+ const value = element.value?.trim();
44
+
45
+ this.state.filter = value ? value : undefined;
46
+
47
+ this.rebindChildElements();
48
+ });
49
+ });
50
+
51
+ this.shadowRoot?.querySelectorAll<BaseFacetComponent>('[hawksearch-facet]').forEach((component) => {
52
+ component.data = this.data;
53
+ component.state = this.state;
54
+ });
55
+ }
56
+
57
+ private rebindChildElements(): void {
58
+ this.shadowRoot?.querySelectorAll<BaseFacetComponent>('[hawksearch-facet]').forEach((component) => {
59
+ component.renderContent();
60
+ });
61
+ }
62
+ }
@@ -0,0 +1,11 @@
1
+ <div class='facets{{attribute " facets--expanded" expanded}}'>
2
+ <div hawksearch-mobile-toggle class='facets__heading'>
3
+ Narrow Results
4
+ <hawksearch-icon name='{{if-else expanded "chevron-down" "chevron-right"}}' size='1.5rem' class='facets__heading__mobile-toggle'></hawksearch-icon>
5
+ </div>
6
+ <div class='facets__content'>
7
+ {{#each facets}}
8
+ <hawksearch-facet-wrapper hawksearch-facet-id='{{id}}'></hawksearch-facet-wrapper>
9
+ {{/each}}
10
+ </div>
11
+ </div>
@@ -0,0 +1,92 @@
1
+ import { Facet, FacetState, FacetType, FacetValue } from '@models';
2
+ import { BaseComponent } from '../base.component';
3
+ import { FacetWrapperComponent } from '../facet-wrapper/facet-wrapper.component';
4
+ import defaultHtml from './facets-list.component.hbs';
5
+
6
+ export class FacetsListComponent extends BaseComponent<Array<Facet>> {
7
+ protected bindEvent = 'hawksearch:bind-facets-list';
8
+ protected customTemplatePropertyName = 'facetsList';
9
+ protected defaultHtml = defaultHtml;
10
+
11
+ private readonly state: {
12
+ [key: number]: FacetState;
13
+ expanded: boolean;
14
+ } = {
15
+ expanded: false
16
+ };
17
+
18
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
19
+ if (!this.data) {
20
+ return '';
21
+ }
22
+
23
+ const supportedTypes: Array<FacetType> = ['checkbox', 'color', 'link', 'range-slider', 'search', 'size'];
24
+
25
+ const html = template({
26
+ facets: this.data.filter((f) => supportedTypes.includes(f.type)),
27
+ expanded: this.state.expanded
28
+ });
29
+
30
+ return html;
31
+ }
32
+
33
+ protected bindChildElements(): void {
34
+ this.shadowRoot?.querySelectorAll('[hawksearch-mobile-toggle]').forEach((e) => {
35
+ e.addEventListener('click', (event: Event) => {
36
+ event.preventDefault();
37
+
38
+ this.state.expanded = !this.state.expanded;
39
+
40
+ this.renderContent();
41
+ });
42
+ });
43
+
44
+ this.shadowRoot?.querySelectorAll<FacetWrapperComponent>('hawksearch-facet-wrapper[hawksearch-facet-id]').forEach((component) => {
45
+ const id = parseInt(component.getAttribute('hawksearch-facet-id') ?? '');
46
+ const facet = this.data?.find((f) => f.id === id);
47
+
48
+ let facetValues: Array<string> | undefined;
49
+
50
+ if (facet?.values) {
51
+ facetValues = [];
52
+
53
+ const addValues = (values: Array<FacetValue> | undefined): void => {
54
+ values?.forEach((v) => {
55
+ if (v.value) {
56
+ facetValues!.push(v.value);
57
+ }
58
+
59
+ addValues(v.children);
60
+ });
61
+ };
62
+
63
+ addValues(facet.values);
64
+ }
65
+
66
+ let facetState = this.state[id];
67
+
68
+ if (!facetState) {
69
+ facetState = {
70
+ id: id,
71
+ toggled: false,
72
+ values: {}
73
+ };
74
+
75
+ this.state[id] = facetState;
76
+ }
77
+
78
+ facetValues?.forEach((v) => {
79
+ const state = facetState.values![v];
80
+
81
+ if (!state) {
82
+ facetState.values![v] = {
83
+ toggled: false
84
+ };
85
+ }
86
+ });
87
+
88
+ component.data = facet;
89
+ component.state = facetState;
90
+ });
91
+ }
92
+ }
@@ -0,0 +1,3 @@
1
+ <svg height='{{height}}' width='{{width}}' focusable='false' aria-hidden='true' class='icon'>
2
+ <use href='{{url}}'></use>
3
+ </svg>
@@ -0,0 +1,40 @@
1
+ import iconsUrl from '@assets/images/icons.svg';
2
+ import { IconName } from '@models';
3
+ import { BaseComponent } from '../base.component';
4
+ import defaultHtml from './icon.component.hbs';
5
+
6
+ export class IconComponent extends BaseComponent<never> {
7
+ protected bindEvent = undefined;
8
+ protected customTemplatePropertyName = 'icon';
9
+ protected defaultHtml = defaultHtml;
10
+
11
+ private get size(): string {
12
+ const size = this.getAttribute('size');
13
+
14
+ if (!size) {
15
+ return '1em';
16
+ }
17
+
18
+ if (isNaN(Number(size))) {
19
+ return size;
20
+ }
21
+
22
+ return `${size}px`;
23
+ }
24
+
25
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
26
+ const name = this.getAttribute('name') as IconName | null;
27
+
28
+ if (!name) {
29
+ return '';
30
+ }
31
+
32
+ const html = template({
33
+ url: `${iconsUrl}#${name}`,
34
+ height: this.size,
35
+ width: this.size
36
+ });
37
+
38
+ return html;
39
+ }
40
+ }
@@ -0,0 +1,18 @@
1
+ export * from './autocomplete/autocomplete.component';
2
+ export * from './facet-types';
3
+ export * from './facet-wrapper/facet-wrapper.component';
4
+ export * from './facets-list/facets-list.component';
5
+ export * from './icon/icon.component';
6
+ export * from './modified-query/modified-query.component';
7
+ export * from './page-size/page-size.component';
8
+ export * from './pagination/pagination.component';
9
+ export * from './query-suggestions/query-suggestions.component';
10
+ export * from './range-slider/range-slider.component';
11
+ export * from './search/search.component';
12
+ export * from './search-results-item/search-results-item.component';
13
+ export * from './search-results-list/search-results-list.component';
14
+ export * from './search-results/search-results.component';
15
+ export * from './selected-facets/selected-facets.component';
16
+ export * from './sorting/sorting.component';
17
+ export * from './tabs/tabs.component';
18
+ export * from './tooltip/tooltip.component';
@@ -0,0 +1,7 @@
1
+ <div class='modified-query'>
2
+ <p>
3
+ Showing results for
4
+ <span class='modified-query__modified'>{{modifiedQuery}}</span>. Search instead for
5
+ <a class='modified-query__original' hawksearch-query='{{query}}'>{{query}}</a>.
6
+ </p>
7
+ </div>
@@ -0,0 +1,38 @@
1
+ import { ModifiedQueryData } from '@models';
2
+ import { searchService } from '@services';
3
+ import { BaseComponent } from '../base.component';
4
+ import defaultHtml from './modified-query.component.hbs';
5
+
6
+ export class ModifiedQueryComponent extends BaseComponent<ModifiedQueryData> {
7
+ protected bindEvent = 'hawksearch:bind-modified-query';
8
+ protected customTemplatePropertyName = 'modifiedQuery';
9
+ protected defaultHtml = defaultHtml;
10
+
11
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
12
+ if (!this.data || !this.data.display || !this.data.query || !this.data.modifiedQuery) {
13
+ return '';
14
+ }
15
+
16
+ const html = template({
17
+ query: this.data.query,
18
+ modifiedQuery: this.data.modifiedQuery
19
+ });
20
+
21
+ return html;
22
+ }
23
+
24
+ protected bindChildElements(): void {
25
+ this.shadowRoot?.querySelectorAll('[hawksearch-query]').forEach((e) => {
26
+ e.addEventListener('click', (event: Event) => {
27
+ event.preventDefault();
28
+
29
+ const element = event.currentTarget as HTMLElement;
30
+ const query = element.getAttribute('hawksearch-query');
31
+
32
+ if (query) {
33
+ searchService.query(query, true);
34
+ }
35
+ });
36
+ });
37
+ }
38
+ }
@@ -0,0 +1,7 @@
1
+ <div class='page-size'>
2
+ <select hawksearch-page-size>
3
+ {{#each options}}
4
+ <option value='{{pageSize}}' {{attribute 'selected' selected}}>{{title}}</option>
5
+ {{/each}}
6
+ </select>
7
+ </div>
@@ -0,0 +1,35 @@
1
+ import { PaginationOption } from '@models';
2
+ import { searchService } from '@services';
3
+ import { BaseComponent } from '../base.component';
4
+ import defaultHtml from './page-size.component.hbs';
5
+
6
+ export class PageSizeComponent extends BaseComponent<Array<PaginationOption>> {
7
+ protected bindEvent = 'hawksearch:bind-page-size';
8
+ protected customTemplatePropertyName = 'pageSize';
9
+ protected defaultHtml = defaultHtml;
10
+
11
+ protected getContentHtml(template: HandlebarsTemplateDelegate): string {
12
+ if (!this.data?.length) {
13
+ return '';
14
+ }
15
+
16
+ const html = template({
17
+ options: this.data
18
+ });
19
+
20
+ return html;
21
+ }
22
+
23
+ protected bindChildElements(): void {
24
+ this.shadowRoot?.querySelectorAll('[hawksearch-page-size]').forEach((e) => {
25
+ e.addEventListener('change', (event: Event) => {
26
+ event.preventDefault();
27
+
28
+ const element = event.currentTarget as HTMLSelectElement;
29
+ const pageSize = parseInt(element.value);
30
+
31
+ searchService.setPageSize(pageSize);
32
+ });
33
+ });
34
+ }
35
+ }
@@ -0,0 +1,34 @@
1
+ <div class='pagination'>
2
+ {{#if summary}}
3
+ <div class='pagination__summary'>{{summary}}</div>
4
+ {{/if}}
5
+ <div class='pagination__pages'>
6
+ {{#if displayFirstLink}}
7
+ <a hawksearch-page='1' class='pagination__page pagination__page--first' title='First'>
8
+ <hawksearch-icon name='chevron-back' size='1.2em'></hawksearch-icon>
9
+ </a>
10
+ {{/if}}
11
+ {{#if displayPreviousLink}}
12
+ <a hawksearch-page='{{subtract page 1}}' class='pagination__page pagination__page--previous' title='Previous'>
13
+ <hawksearch-icon name='chevron-left' size='1.2em'></hawksearch-icon>
14
+ </a>
15
+ {{/if}}
16
+ {{#each pages}}
17
+ {{#if (eq this @root.page)}}
18
+ <span class='pagination__page pagination__page--selected'>{{this}}</span>
19
+ {{else}}
20
+ <a hawksearch-page='{{this}}' class='pagination__page'>{{this}}</a>
21
+ {{/if}}
22
+ {{/each}}
23
+ {{#if displayNextLink}}
24
+ <a hawksearch-page='{{add page 1}}' class='pagination__page pagination__page--next' title='Next'>
25
+ <hawksearch-icon name='chevron-right' size='1.2em'></hawksearch-icon>
26
+ </a>
27
+ {{/if}}
28
+ {{#if displayLastLink}}
29
+ <a hawksearch-page='{{totalPages}}' class='pagination__page pagination__page--last' title='Last'>
30
+ <hawksearch-icon name='chevron-forward' size='1.2em'></hawksearch-icon>
31
+ </a>
32
+ {{/if}}
33
+ </div>
34
+ </div>