Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit cef0b75

Browse files
authoredAug 12, 2022
feat(search-box): add loading indicator + showLoadingIndicator prop (#962)
* feat(search-box): add loading indicator and `showLoadingIndicator` prop to show/hide it * feat(search-box): always show reset button when showLoadingIndicator is false
1 parent 8440a41 commit cef0b75

File tree

3 files changed

+185
-1
lines changed

3 files changed

+185
-1
lines changed
 

‎src/search-box/__tests__/__snapshots__/search-box.spec.ts.snap

+82
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,47 @@ exports[`SearchBox renders markup with state 1`] = `
5454
/>
5555
</svg>
5656
</button>
57+
<span
58+
class="ais-SearchBox-loadingIndicator"
59+
hidden=""
60+
>
61+
<svg
62+
class="ais-SearchBox-loadingIcon"
63+
height="16"
64+
stroke="#444"
65+
viewBox="0 0 38 38"
66+
width="16"
67+
>
68+
<g
69+
fill="none"
70+
fillRule="evenodd"
71+
>
72+
<g
73+
strokeWidth="2"
74+
transform="translate(1 1)"
75+
>
76+
<circle
77+
cx="18"
78+
cy="18"
79+
r="18"
80+
strokeOpacity=".5"
81+
/>
82+
<path
83+
d="M36 18c0-9.94-8.06-18-18-18"
84+
>
85+
<animatetransform
86+
attributeName="transform"
87+
dur="1s"
88+
from="0 18 18"
89+
repeatCount="indefinite"
90+
to="360 18 18"
91+
type="rotate"
92+
/>
93+
</path>
94+
</g>
95+
</g>
96+
</svg>
97+
</span>
5798
</form>
5899
</div>
59100
</ais-search-box>
@@ -116,6 +157,47 @@ exports[`SearchBox renders markup without state 1`] = `
116157
/>
117158
</svg>
118159
</button>
160+
<span
161+
class="ais-SearchBox-loadingIndicator"
162+
hidden=""
163+
>
164+
<svg
165+
class="ais-SearchBox-loadingIcon"
166+
height="16"
167+
stroke="#444"
168+
viewBox="0 0 38 38"
169+
width="16"
170+
>
171+
<g
172+
fill="none"
173+
fillRule="evenodd"
174+
>
175+
<g
176+
strokeWidth="2"
177+
transform="translate(1 1)"
178+
>
179+
<circle
180+
cx="18"
181+
cy="18"
182+
r="18"
183+
strokeOpacity=".5"
184+
/>
185+
<path
186+
d="M36 18c0-9.94-8.06-18-18-18"
187+
>
188+
<animatetransform
189+
attributeName="transform"
190+
dur="1s"
191+
from="0 18 18"
192+
repeatCount="indefinite"
193+
to="360 18 18"
194+
type="rotate"
195+
/>
196+
</path>
197+
</g>
198+
</g>
199+
</svg>
200+
</span>
119201
</form>
120202
</div>
121203
</ais-search-box>

‎src/search-box/__tests__/search-box.spec.ts

+72
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,78 @@ describe('SearchBox', () => {
123123
});
124124
});
125125

126+
describe('[showLoadingIndicator]', () => {
127+
it('should show a loading indicator by default when search is stalled', () => {
128+
const fixture = createRenderer({
129+
defaultState,
130+
template: '<ais-search-box></ais-search-box>',
131+
TestedWidget: NgAisSearchBox,
132+
})();
133+
const widget = fixture.componentInstance.testedWidget;
134+
widget.state.query = 'iphone';
135+
widget.state.isSearchStalled = true;
136+
fixture.detectChanges();
137+
138+
const loadingIndicator = fixture.debugElement.query(
139+
By.css('.ais-SearchBox-loadingIndicator')
140+
);
141+
expect(loadingIndicator.nativeElement.hidden).toBe(false);
142+
});
143+
144+
it('should hide reset button by default when search is stalled', () => {
145+
const fixture = createRenderer({
146+
defaultState,
147+
template: '<ais-search-box></ais-search-box>',
148+
TestedWidget: NgAisSearchBox,
149+
})();
150+
const widget = fixture.componentInstance.testedWidget;
151+
widget.state.query = 'iphone';
152+
widget.state.isSearchStalled = true;
153+
fixture.detectChanges();
154+
155+
const resetButton = fixture.debugElement.query(
156+
By.css('.ais-SearchBox-reset')
157+
);
158+
expect(resetButton.nativeElement.hidden).toBe(true);
159+
});
160+
161+
it('should not show a loading indicator when property is false', () => {
162+
const fixture = createRenderer({
163+
defaultState,
164+
template:
165+
'<ais-search-box [showLoadingIndicator]="false"></ais-search-box>',
166+
TestedWidget: NgAisSearchBox,
167+
})();
168+
const widget = fixture.componentInstance.testedWidget;
169+
widget.state.query = 'iphone';
170+
widget.state.isSearchStalled = true;
171+
fixture.detectChanges();
172+
173+
const loadingIndicator = fixture.debugElement.query(
174+
By.css('.ais-SearchBox-loadingIndicator')
175+
);
176+
expect(loadingIndicator.nativeElement.hidden).toBe(true);
177+
});
178+
179+
it('should not hide reset button when property is false and search is stalled', () => {
180+
const fixture = createRenderer({
181+
defaultState,
182+
template:
183+
'<ais-search-box [showLoadingIndicator]="false"></ais-search-box>',
184+
TestedWidget: NgAisSearchBox,
185+
})();
186+
const widget = fixture.componentInstance.testedWidget;
187+
widget.state.query = 'iphone';
188+
widget.state.isSearchStalled = true;
189+
fixture.detectChanges();
190+
191+
const resetButton = fixture.debugElement.query(
192+
By.css('.ais-SearchBox-reset')
193+
);
194+
expect(resetButton.nativeElement.hidden).toBe(false);
195+
});
196+
});
197+
126198
it('should create a widget that sets the $$widgetType metadata', () => {
127199
const createWidget = jest.spyOn(NgAisSearchBox.prototype, 'createWidget');
128200

‎src/search-box/search-box.ts

+31-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ import {
6767
type="reset"
6868
title="{{resetTitle}}"
6969
(click)="handleReset($event)"
70-
[hidden]="!state.query || (state.query && !state.query.trim())">
70+
[hidden]="!state.query || (state.query && !state.query.trim()) || (state.isSearchStalled && showLoadingIndicator)">
7171
<svg
7272
[ngClass]="cx('resetIcon')"
7373
viewBox="0 0 20 20"
@@ -77,6 +77,35 @@ import {
7777
<path d="M8.114 10L.944 2.83 0 1.885 1.886 0l.943.943L10 8.113l7.17-7.17.944-.943L20 1.886l-.943.943-7.17 7.17 7.17 7.17.943.944L18.114 20l-.943-.943-7.17-7.17-7.17 7.17-.944.943L0 18.114l.943-.943L8.113 10z"></path>
7878
</svg>
7979
</button>
80+
81+
<span
82+
[class]="cx('loadingIndicator')"
83+
[hidden]="!showLoadingIndicator || !state.isSearchStalled"
84+
>
85+
<svg
86+
width="16"
87+
height="16"
88+
viewBox="0 0 38 38"
89+
stroke="#444"
90+
[ngClass]="cx('loadingIcon')"
91+
>
92+
<g fill="none" fillRule="evenodd">
93+
<g transform="translate(1 1)" strokeWidth="2">
94+
<circle strokeOpacity=".5" cx="18" cy="18" r="18" />
95+
<path d="M36 18c0-9.94-8.06-18-18-18">
96+
<animateTransform
97+
attributeName="transform"
98+
type="rotate"
99+
from="0 18 18"
100+
to="360 18 18"
101+
dur="1s"
102+
repeatCount="indefinite"
103+
/>
104+
</path>
105+
</g>
106+
</g>
107+
</svg>
108+
</span>
80109
</form>
81110
</div>
82111
`,
@@ -91,6 +120,7 @@ export class NgAisSearchBox
91120
@Input() public resetTitle: string = 'Reset';
92121
@Input() public searchAsYouType: boolean = true;
93122
@Input() public autofocus: boolean = false;
123+
@Input() public showLoadingIndicator: boolean = true;
94124

95125
// Output events
96126
// form

0 commit comments

Comments
 (0)