inviton-powerduck 0.0.226 → 0.0.228
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.
|
@@ -237,6 +237,15 @@
|
|
|
237
237
|
min-height: 150px;
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
.list-header {
|
|
241
|
+
padding: 12px 16px;
|
|
242
|
+
font-size: 0.85rem;
|
|
243
|
+
color: #6c757d;
|
|
244
|
+
background: #f8f9fa;
|
|
245
|
+
border-bottom: 1px solid #e9ecef;
|
|
246
|
+
font-style: italic;
|
|
247
|
+
}
|
|
248
|
+
|
|
240
249
|
.list-group-label {
|
|
241
250
|
padding: 8px 16px;
|
|
242
251
|
font-size: 0.75rem;
|
|
@@ -81,6 +81,10 @@ interface SmartDropdownArgs extends FormItemWrapperArgs {
|
|
|
81
81
|
changed: (e: SmartDropdownItem[]) => void;
|
|
82
82
|
/** Called when an item is clicked. Return true to prevent default selection behavior. */
|
|
83
83
|
onItemClick?: (item: SmartDropdownItem) => boolean;
|
|
84
|
+
/** Delay in ms before showing the loading indicator. Default 650ms. */
|
|
85
|
+
loadingIndicatorDelay?: number;
|
|
86
|
+
/** Optional header shown at the top of the list to guide users. Can be a string or VNode. */
|
|
87
|
+
listHeader?: string | VNode;
|
|
84
88
|
}
|
|
85
89
|
|
|
86
90
|
@Component
|
|
@@ -121,13 +125,17 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
|
|
|
121
125
|
@Prop({ type: Function }) readonly customTriggerRender?: () => VNode;
|
|
122
126
|
@Prop() readonly changed: (e: SmartDropdownItem[]) => void;
|
|
123
127
|
@Prop({ type: Function }) readonly onItemClick?: (item: SmartDropdownItem) => boolean;
|
|
128
|
+
@Prop({ type: Number, default: 650 }) readonly loadingIndicatorDelay!: number;
|
|
129
|
+
@Prop() readonly listHeader?: string | VNode;
|
|
124
130
|
|
|
125
131
|
// --- State ---
|
|
126
132
|
isOpen = false;
|
|
127
133
|
searchQuery = '';
|
|
128
134
|
searchResults: SmartDropdownSearchResultItem[] = [];
|
|
129
135
|
isLoading = false;
|
|
136
|
+
isSearchPending = false;
|
|
130
137
|
debounceTimer: number | null = null;
|
|
138
|
+
loadingIndicatorTimer: number | null = null;
|
|
131
139
|
focusedIndex = -1;
|
|
132
140
|
triggerInputValue = '';
|
|
133
141
|
|
|
@@ -415,20 +423,36 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
|
|
|
415
423
|
clearTimeout(this.debounceTimer);
|
|
416
424
|
}
|
|
417
425
|
|
|
426
|
+
if (this.loadingIndicatorTimer) {
|
|
427
|
+
clearTimeout(this.loadingIndicatorTimer);
|
|
428
|
+
this.loadingIndicatorTimer = null;
|
|
429
|
+
}
|
|
430
|
+
|
|
418
431
|
if (val.trim().length === 0) {
|
|
419
432
|
this.isLoading = false;
|
|
433
|
+
this.isSearchPending = false;
|
|
420
434
|
this.searchResults = [];
|
|
421
435
|
return;
|
|
422
436
|
}
|
|
423
437
|
|
|
424
|
-
this.
|
|
438
|
+
this.isSearchPending = true;
|
|
425
439
|
this.debounceTimer = window.setTimeout(async () => {
|
|
440
|
+
// Start timer to show loading indicator after delay
|
|
441
|
+
this.loadingIndicatorTimer = window.setTimeout(() => {
|
|
442
|
+
this.isLoading = true;
|
|
443
|
+
}, this.loadingIndicatorDelay);
|
|
426
444
|
try {
|
|
427
445
|
this.searchResults = await this.searchData(val);
|
|
428
446
|
} catch (err) {
|
|
429
447
|
this.searchResults = [];
|
|
430
448
|
} finally {
|
|
449
|
+
if (this.loadingIndicatorTimer) {
|
|
450
|
+
clearTimeout(this.loadingIndicatorTimer);
|
|
451
|
+
this.loadingIndicatorTimer = null;
|
|
452
|
+
}
|
|
453
|
+
|
|
431
454
|
this.isLoading = false;
|
|
455
|
+
this.isSearchPending = false;
|
|
432
456
|
}
|
|
433
457
|
}, 800);
|
|
434
458
|
}
|
|
@@ -449,7 +473,10 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
|
|
|
449
473
|
if (this.multiselect) {
|
|
450
474
|
if (shouldBeSelected && !isCurrentlySelected) {
|
|
451
475
|
// Add item
|
|
452
|
-
newSelection = [
|
|
476
|
+
newSelection = [
|
|
477
|
+
...this.value,
|
|
478
|
+
item,
|
|
479
|
+
];
|
|
453
480
|
} else if (!shouldBeSelected && isCurrentlySelected) {
|
|
454
481
|
// Remove item
|
|
455
482
|
newSelection = this.value.filter(i => i.id !== item.id);
|
|
@@ -576,6 +603,11 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
|
|
|
576
603
|
// A. Search Results
|
|
577
604
|
if (this.isSearchActive) {
|
|
578
605
|
if (this.searchResults.length === 0) {
|
|
606
|
+
// Show loading if search is pending or in progress, otherwise show no results
|
|
607
|
+
if (this.isSearchPending) {
|
|
608
|
+
return <div class="loading-state" role="status">{SmartDropdownResources.loadingTextLong}</div>;
|
|
609
|
+
}
|
|
610
|
+
|
|
579
611
|
return <div class="empty-state" role="status">{SmartDropdownResources.noResultsSearch}</div>;
|
|
580
612
|
}
|
|
581
613
|
|
|
@@ -597,6 +629,11 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
|
|
|
597
629
|
|
|
598
630
|
return (
|
|
599
631
|
<div class="list-wrapper">
|
|
632
|
+
{/* 0. List Header */}
|
|
633
|
+
{this.listHeader && (
|
|
634
|
+
<div class="list-header" role="note">{this.listHeader}</div>
|
|
635
|
+
)}
|
|
636
|
+
|
|
600
637
|
{/* 1. Pinned Selected */}
|
|
601
638
|
{hasPinned && (
|
|
602
639
|
<div class="list-group section-pinned" role="group" aria-label={SmartDropdownResources.selectedTitle}>
|
|
@@ -122,7 +122,7 @@ class CheckBoxComponent extends TsxComponent<CheckBoxArgs> implements CheckBoxAr
|
|
|
122
122
|
<label class="form-check-label">
|
|
123
123
|
<input class="form-check-input" type="checkbox" checked={this.value} disabled={this.disabled || undefined} onChange={e => this.raiseChangeEvent(e)} />
|
|
124
124
|
<span class="form-check-sign"></span>
|
|
125
|
-
{this.getCustomRenderedLabel
|
|
125
|
+
{this.getCustomRenderedLabel(h) ?? this.checkboxLabelHtml}
|
|
126
126
|
</label>
|
|
127
127
|
</div>
|
|
128
128
|
);
|
|
@@ -140,7 +140,7 @@ class CheckBoxComponent extends TsxComponent<CheckBoxArgs> implements CheckBoxAr
|
|
|
140
140
|
<div class="inv-cbrb-inner">
|
|
141
141
|
<input class="inv-chckb-clickable" type="checkbox" id={`iei-input-${this.uuid}`} checked={this.value} disabled={this.disabled || undefined} onChange={e => this.raiseChangeEvent(e)} />
|
|
142
142
|
<label class="inv-chckb-clickable form-check-label " for={`iei-input-${this.uuid}`}>
|
|
143
|
-
{this.getCustomRenderedLabel
|
|
143
|
+
{this.getCustomRenderedLabel(h) ?? <HtmlLiteral innerHTML={this.checkboxLabelHtml} />}
|
|
144
144
|
</label>
|
|
145
145
|
</div>
|
|
146
146
|
</div>
|
|
@@ -160,7 +160,7 @@ class CheckBoxComponent extends TsxComponent<CheckBoxArgs> implements CheckBoxAr
|
|
|
160
160
|
<div class="inv-cbrb-inner">
|
|
161
161
|
<input class="inv-chckb-clickable" type="checkbox" id={`iei-input-${this.uuid}`} checked={this.value} disabled={this.disabled || undefined} onChange={e => this.raiseChangeEvent(e)} />
|
|
162
162
|
<label class="inv-chckb-clickable form-check-label " for={`iei-input-${this.uuid}`}>
|
|
163
|
-
{this.getCustomRenderedLabel
|
|
163
|
+
{this.getCustomRenderedLabel(h) ?? <HtmlLiteral innerHTML={this.checkboxLabelHtml} />}
|
|
164
164
|
</label>
|
|
165
165
|
</div>
|
|
166
166
|
</div>
|