inviton-powerduck 0.0.225 → 0.0.227

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.
@@ -1,89 +1,89 @@
1
- /*! Ladda http://lab.hakim.se/ladda MIT licensed Copyright (C) 2016 Hakim El Hattab, http://hakim.se ....Lightweight adaptation for Inviton API needs*/
2
- .ladda-button {
3
- position: relative;
4
- }
5
- .ladda-button .ladda-spinner {
6
- position: absolute;
7
- z-index: 2;
8
- display: inline-block;
9
- width: 32px;
10
- height: 32px;
11
- top: 50%;
12
- margin-top: 0;
13
- opacity: 0;
14
- pointer-events: none;
15
- }
16
- .ladda-button .ladda-label {
17
- position: relative;
18
- z-index: 3;
19
- }
20
- .ladda-button .ladda-progress {
21
- position: absolute;
22
- width: 0;
23
- height: 100%;
24
- left: 0;
25
- top: 0;
26
- background: rgba(0, 0, 0, 0.2);
27
- visibility: hidden;
28
- opacity: 0;
29
- -webkit-transition: 0.1s linear all !important;
30
- -moz-transition: 0.1s linear all !important;
31
- -ms-transition: 0.1s linear all !important;
32
- -o-transition: 0.1s linear all !important;
33
- transition: 0.1s linear all !important;
34
- }
35
- .ladda-button[data-loading] .ladda-progress {
36
- opacity: 1;
37
- visibility: visible;
38
- }
39
- .ladda-button,
40
- .ladda-button .ladda-label,
41
- .ladda-button .ladda-spinner {
42
- -webkit-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
43
- -moz-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
44
- -ms-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
45
- -o-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
46
- transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
47
- }
48
- .ladda-button[data-style="zoom-in"],
49
- .ladda-button[data-style="zoom-in"] .ladda-label,
50
- .ladda-button[data-style="zoom-in"] .ladda-spinner {
51
- -webkit-transition: 0.3s ease all !important;
52
- -moz-transition: 0.3s ease all !important;
53
- -ms-transition: 0.3s ease all !important;
54
- -o-transition: 0.3s ease all !important;
55
- transition: 0.3s ease all !important;
56
- }
57
- .ladda-button[data-style="zoom-in"] {
58
- overflow: hidden;
59
- }
60
- .ladda-button[data-style="zoom-in"] .ladda-spinner {
61
- left: 50%;
62
- margin-left: -16px;
63
- -webkit-transform: scale(0.2);
64
- -moz-transform: scale(0.2);
65
- -ms-transform: scale(0.2);
66
- -o-transform: scale(0.2);
67
- transform: scale(0.2);
68
- }
69
- .ladda-button[data-style="zoom-in"] .ladda-label {
70
- position: relative;
71
- display: inline-block;
72
- }
73
- .ladda-button[data-style="zoom-in"][data-loading] .ladda-label {
74
- opacity: 0;
75
- -webkit-transform: scale(2.2);
76
- -moz-transform: scale(2.2);
77
- -ms-transform: scale(2.2);
78
- -o-transform: scale(2.2);
79
- transform: scale(2.2);
80
- }
81
- .ladda-button[data-style="zoom-in"][data-loading] .ladda-spinner {
82
- opacity: 1;
83
- margin-left: 0;
84
- -webkit-transform: none;
85
- -moz-transform: none;
86
- -ms-transform: none;
87
- -o-transform: none;
88
- transform: none;
89
- }
1
+ /*! Ladda http://lab.hakim.se/ladda MIT licensed Copyright (C) 2016 Hakim El Hattab, http://hakim.se ....Lightweight adaptation for Inviton API needs*/
2
+ .ladda-button {
3
+ position: relative;
4
+ }
5
+ .ladda-button .ladda-spinner {
6
+ position: absolute;
7
+ z-index: 2;
8
+ display: inline-block;
9
+ width: 32px;
10
+ height: 32px;
11
+ top: 50%;
12
+ margin-top: 0;
13
+ opacity: 0;
14
+ pointer-events: none;
15
+ }
16
+ .ladda-button .ladda-label {
17
+ position: relative;
18
+ z-index: 3;
19
+ }
20
+ .ladda-button .ladda-progress {
21
+ position: absolute;
22
+ width: 0;
23
+ height: 100%;
24
+ left: 0;
25
+ top: 0;
26
+ background: rgba(0, 0, 0, 0.2);
27
+ visibility: hidden;
28
+ opacity: 0;
29
+ -webkit-transition: 0.1s linear all !important;
30
+ -moz-transition: 0.1s linear all !important;
31
+ -ms-transition: 0.1s linear all !important;
32
+ -o-transition: 0.1s linear all !important;
33
+ transition: 0.1s linear all !important;
34
+ }
35
+ .ladda-button[data-loading] .ladda-progress {
36
+ opacity: 1;
37
+ visibility: visible;
38
+ }
39
+ .ladda-button,
40
+ .ladda-button .ladda-label,
41
+ .ladda-button .ladda-spinner {
42
+ -webkit-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
43
+ -moz-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
44
+ -ms-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
45
+ -o-transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
46
+ transition: 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) all !important;
47
+ }
48
+ .ladda-button[data-style="zoom-in"],
49
+ .ladda-button[data-style="zoom-in"] .ladda-label,
50
+ .ladda-button[data-style="zoom-in"] .ladda-spinner {
51
+ -webkit-transition: 0.3s ease all !important;
52
+ -moz-transition: 0.3s ease all !important;
53
+ -ms-transition: 0.3s ease all !important;
54
+ -o-transition: 0.3s ease all !important;
55
+ transition: 0.3s ease all !important;
56
+ }
57
+ .ladda-button[data-style="zoom-in"] {
58
+ overflow: hidden;
59
+ }
60
+ .ladda-button[data-style="zoom-in"] .ladda-spinner {
61
+ left: 50%;
62
+ margin-left: -16px;
63
+ -webkit-transform: scale(0.2);
64
+ -moz-transform: scale(0.2);
65
+ -ms-transform: scale(0.2);
66
+ -o-transform: scale(0.2);
67
+ transform: scale(0.2);
68
+ }
69
+ .ladda-button[data-style="zoom-in"] .ladda-label {
70
+ position: relative;
71
+ display: inline-block;
72
+ }
73
+ .ladda-button[data-style="zoom-in"][data-loading] .ladda-label {
74
+ opacity: 0;
75
+ -webkit-transform: scale(2.2);
76
+ -moz-transform: scale(2.2);
77
+ -ms-transform: scale(2.2);
78
+ -o-transform: scale(2.2);
79
+ transform: scale(2.2);
80
+ }
81
+ .ladda-button[data-style="zoom-in"][data-loading] .ladda-spinner {
82
+ opacity: 1;
83
+ margin-left: 0;
84
+ -webkit-transform: none;
85
+ -moz-transform: none;
86
+ -ms-transform: none;
87
+ -o-transform: none;
88
+ transform: none;
89
+ }
@@ -1,6 +1,6 @@
1
1
  import { Temporal } from '@js-temporal/polyfill';
2
- import { DomainHelper } from './domain-helper';
3
2
  import { globalState } from '../../app/global-state';
3
+ import { DomainHelper } from './domain-helper';
4
4
 
5
5
  // Cookie manipulation abstraction
6
6
  export class CookieProvider {
@@ -16,9 +16,9 @@ export class CookieProvider {
16
16
  value: string,
17
17
  expiration?: Temporal.PlainDateTime,
18
18
  ) {
19
- if (!globalState.windowExists) {
20
- return;
21
- }
19
+ if (!globalState.windowExists) {
20
+ return;
21
+ }
22
22
 
23
23
  let domain = DomainHelper.getCookieDomain();
24
24
  if (domain.length > 0) {
@@ -27,7 +27,9 @@ export class CookieProvider {
27
27
 
28
28
  let realExpiration;
29
29
  if (expiration != null) {
30
- realExpiration = expiration.toZonedDateTime('UTC').epochMilliseconds;
30
+ const instant = expiration.toZonedDateTime('UTC').toInstant();
31
+ // eslint-disable-next-line no-restricted-syntax
32
+ realExpiration = new Date(instant.epochMilliseconds).toUTCString();
31
33
  } else {
32
34
  realExpiration = '';
33
35
  }
@@ -41,9 +43,9 @@ export class CookieProvider {
41
43
  * @param name Name of the cookie
42
44
  */
43
45
  static read(name: string): string {
44
- if (!globalState.windowExists) {
45
- return null;
46
- }
46
+ if (!globalState.windowExists) {
47
+ return null;
48
+ }
47
49
 
48
50
  name = `${name}=`;
49
51
  const ca = document.cookie.split(';');
@@ -1,4 +1,4 @@
1
- .gopass-filter-wrapper {
1
+ .smart-dropdown-wrapper {
2
2
  /* ... [Previous variables and base styles] ... */
3
3
  --bs-blue: #0d6efd;
4
4
  --bs-btn-bg: #0d6efd;
@@ -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;
@@ -257,7 +266,10 @@
257
266
  }
258
267
 
259
268
  .list-item-custom-container {
269
+ padding: 8px 16px;
260
270
  cursor: pointer;
271
+ display: flex;
272
+ align-items: center;
261
273
  border-bottom: 1px solid #f8f9fa;
262
274
  transition: background-color 0.15s;
263
275
 
@@ -376,7 +388,7 @@
376
388
 
377
389
  /* When in 'input' mode on Desktop: Hide internal search header and footer */
378
390
  @media (min-width: 769px) {
379
- &.mode-input {
391
+ &.mode-input {
380
392
  .internal-search-header {
381
393
  display: none !important;
382
394
  }
@@ -407,7 +419,7 @@
407
419
 
408
420
  /* On Mobile, always show the internal search/footer even if in 'input' mode */
409
421
  /* because the external input is behind the modal */
410
- &.mode-input {
422
+ &.mode-input {
411
423
  .internal-search-header {
412
424
  display: flex !important;
413
425
  }
@@ -49,6 +49,21 @@ export interface SmartDropdownSection {
49
49
  items: SmartDropdownItem[];
50
50
  }
51
51
 
52
+ /** Callback to change selection state of an item */
53
+ export type SelectionChangedCallback = (forceSelected?: boolean) => void;
54
+
55
+ /** Arguments passed to customListItemRender */
56
+ export interface CustomListItemRenderArgs {
57
+ /** The item being rendered */
58
+ item: SmartDropdownItem;
59
+ /** Whether the item is currently selected */
60
+ isSelected: boolean;
61
+ /** Callback to change selection state. Call with true to select, false to deselect, or undefined to toggle */
62
+ selectionChanged: SelectionChangedCallback;
63
+ /** Renders the item using the default SmartDropdown renderer */
64
+ baseRender: () => VNode;
65
+ }
66
+
52
67
  interface SmartDropdownArgs extends FormItemWrapperArgs {
53
68
  categories: SmartDropdownCategoryItem[];
54
69
  customSections: SmartDropdownSection[];
@@ -60,9 +75,16 @@ interface SmartDropdownArgs extends FormItemWrapperArgs {
60
75
  buttonLayout: 'footer' | 'inline';
61
76
  searchMode: 'dropdown' | 'input';
62
77
  customTriggerScope?: 'mobile' | 'desktop' | 'all';
63
- customSectionRender?: (item: SmartDropdownItem, selected: boolean) => VNode;
78
+ /** Custom renderer for list items. Receives args object with item, isSelected, selectionChanged, and baseRender */
79
+ customListItemRender?: (args: CustomListItemRenderArgs) => VNode;
64
80
  customTriggerRender?: () => VNode;
65
81
  changed: (e: SmartDropdownItem[]) => void;
82
+ /** Called when an item is clicked. Return true to prevent default selection behavior. */
83
+ onItemClick?: (item: SmartDropdownItem) => boolean;
84
+ /** Delay in ms before showing the loading indicator. Default 650ms. */
85
+ loadingIndicatorDelay?: number;
86
+ /** Optional header text shown at the top of the list to guide users. */
87
+ listHeader?: string;
66
88
  }
67
89
 
68
90
  @Component
@@ -99,16 +121,21 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
99
121
  @Prop({ type: String, default: 'footer' }) readonly buttonLayout!: 'footer' | 'inline';
100
122
  @Prop({ type: String, default: 'dropdown' }) readonly searchMode!: 'dropdown' | 'input';
101
123
  @Prop({ type: String, default: 'all' }) readonly customTriggerScope!: 'mobile' | 'desktop' | 'all';
102
- @Prop({ type: Function }) readonly customSectionRender?: (item: SmartDropdownItem, selected: boolean) => VNode;
124
+ @Prop({ type: Function }) readonly customListItemRender?: (args: CustomListItemRenderArgs) => VNode;
103
125
  @Prop({ type: Function }) readonly customTriggerRender?: () => VNode;
104
126
  @Prop() readonly changed: (e: SmartDropdownItem[]) => void;
127
+ @Prop({ type: Function }) readonly onItemClick?: (item: SmartDropdownItem) => boolean;
128
+ @Prop({ type: Number, default: 650 }) readonly loadingIndicatorDelay!: number;
129
+ @Prop({ type: String }) readonly listHeader?: string;
105
130
 
106
131
  // --- State ---
107
132
  isOpen = false;
108
133
  searchQuery = '';
109
134
  searchResults: SmartDropdownSearchResultItem[] = [];
110
135
  isLoading = false;
136
+ isSearchPending = false;
111
137
  debounceTimer: number | null = null;
138
+ loadingIndicatorTimer: number | null = null;
112
139
  focusedIndex = -1;
113
140
  triggerInputValue = '';
114
141
 
@@ -396,39 +423,69 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
396
423
  clearTimeout(this.debounceTimer);
397
424
  }
398
425
 
426
+ if (this.loadingIndicatorTimer) {
427
+ clearTimeout(this.loadingIndicatorTimer);
428
+ this.loadingIndicatorTimer = null;
429
+ }
430
+
399
431
  if (val.trim().length === 0) {
400
432
  this.isLoading = false;
433
+ this.isSearchPending = false;
401
434
  this.searchResults = [];
402
435
  return;
403
436
  }
404
437
 
405
- this.isLoading = true;
438
+ this.isSearchPending = true;
406
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);
407
444
  try {
408
445
  this.searchResults = await this.searchData(val);
409
446
  } catch (err) {
410
447
  this.searchResults = [];
411
448
  } finally {
449
+ if (this.loadingIndicatorTimer) {
450
+ clearTimeout(this.loadingIndicatorTimer);
451
+ this.loadingIndicatorTimer = null;
452
+ }
453
+
412
454
  this.isLoading = false;
455
+ this.isSearchPending = false;
413
456
  }
414
457
  }, 800);
415
458
  }
416
459
 
417
- handleItemClick(item: SmartDropdownItem) {
418
- const isSelected = this.isSelected(item);
460
+ handleItemClick(item: SmartDropdownItem, forceSelected?: boolean) {
461
+ // Allow parent to intercept and handle the click
462
+ if (this.onItemClick?.(item)) {
463
+ this.closeDropdown();
464
+ return;
465
+ }
466
+
467
+ const isCurrentlySelected = this.isSelected(item);
468
+ // Use forceSelected if provided, otherwise toggle based on current state
469
+ const shouldBeSelected = forceSelected !== undefined ? forceSelected : !isCurrentlySelected;
470
+
419
471
  let newSelection: SmartDropdownItem[] = [];
420
472
 
421
473
  if (this.multiselect) {
422
- if (isSelected) {
423
- newSelection = this.value.filter(i => i.id !== item.id);
424
- } else {
474
+ if (shouldBeSelected && !isCurrentlySelected) {
475
+ // Add item
425
476
  newSelection = [
426
477
  ...this.value,
427
478
  item,
428
479
  ];
480
+ } else if (!shouldBeSelected && isCurrentlySelected) {
481
+ // Remove item
482
+ newSelection = this.value.filter(i => i.id !== item.id);
483
+ } else {
484
+ // No change needed
485
+ newSelection = [...this.value];
429
486
  }
430
487
  } else {
431
- newSelection = [item];
488
+ newSelection = shouldBeSelected ? [item] : [];
432
489
  this.closeDropdown();
433
490
  }
434
491
 
@@ -546,6 +603,11 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
546
603
  // A. Search Results
547
604
  if (this.isSearchActive) {
548
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
+
549
611
  return <div class="empty-state" role="status">{SmartDropdownResources.noResultsSearch}</div>;
550
612
  }
551
613
 
@@ -567,6 +629,11 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
567
629
 
568
630
  return (
569
631
  <div class="list-wrapper">
632
+ {/* 0. List Header */}
633
+ {this.listHeader && (
634
+ <div class="list-header" role="note">{this.listHeader}</div>
635
+ )}
636
+
570
637
  {/* 1. Pinned Selected */}
571
638
  {hasPinned && (
572
639
  <div class="list-group section-pinned" role="group" aria-label={SmartDropdownResources.selectedTitle}>
@@ -600,17 +667,52 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
600
667
  );
601
668
  }
602
669
 
670
+ /** Renders the default list item content (without wrapper) */
671
+ renderDefaultListItemContent(item: SmartDropdownItem, isSelected: boolean): VNode {
672
+ const searchResult = item as SmartDropdownSearchResultItem;
673
+ const hasSubtitle = !!searchResult.subtitle;
674
+ const hasImage = !!searchResult.imageUrl;
675
+ const showCheckbox = this.multiselect && !this.isSearchActive && !hasImage;
676
+
677
+ return (
678
+ <>
679
+ {hasImage
680
+ ? (
681
+ <img src={searchResult.imageUrl} class="result-image" alt="" />
682
+ )
683
+ : (
684
+ showCheckbox && <div class={`checkbox-visual ${isSelected ? 'checked' : ''}`} aria-hidden="true"></div>
685
+ )}
686
+
687
+ <div class="item-content">
688
+ <span class="item-text">{item.text}</span>
689
+ {hasSubtitle && (
690
+ <span class="item-subtitle">{searchResult.subtitle}</span>
691
+ )}
692
+ </div>
693
+ </>
694
+ );
695
+ }
696
+
603
697
  renderListItem(item: SmartDropdownItem, index: number) {
604
698
  const isSelected = this.isSelected(item);
605
699
  const isFocused = this.focusedIndex === index;
606
700
  const uniqueId = `${this.uid}-option-${index}`;
607
701
 
702
+ // Create selectionChanged callback for this item
703
+ const selectionChanged: SelectionChangedCallback = (forceSelected?: boolean) => {
704
+ this.handleItemClick(item, forceSelected);
705
+ };
706
+
707
+ // Create baseRender function that returns the default rendering
708
+ const baseRender = (): VNode => this.renderDefaultListItemContent(item, isSelected);
709
+
608
710
  // Wrapper properties for accessibility
609
711
  const wrapperProps = {
610
712
  'id': uniqueId,
611
713
  'class': {
612
- 'list-item-custom-container': !!this.customSectionRender,
613
- 'list-item': !this.customSectionRender,
714
+ 'list-item-custom-container': !!this.customListItemRender,
715
+ 'list-item': !this.customListItemRender,
614
716
  'selected': isSelected,
615
717
  'focused': isFocused, // Visual focus state
616
718
  'no-checkbox': !this.multiselect,
@@ -622,36 +724,18 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
622
724
  };
623
725
 
624
726
  // 1. Custom Renderer
625
- if (this.customSectionRender) {
727
+ if (this.customListItemRender) {
626
728
  return (
627
729
  <div {...wrapperProps}>
628
- {this.customSectionRender(item, isSelected)}
730
+ {this.customListItemRender({ item, isSelected, selectionChanged, baseRender })}
629
731
  </div>
630
732
  );
631
733
  }
632
734
 
633
735
  // 2. Default Renderer
634
- const searchResult = item as SmartDropdownSearchResultItem;
635
- const hasSubtitle = !!searchResult.subtitle;
636
- const hasImage = !!searchResult.imageUrl;
637
- const showCheckbox = this.multiselect && !this.isSearchActive && !hasImage;
638
-
639
736
  return (
640
737
  <div {...wrapperProps}>
641
- {hasImage
642
- ? (
643
- <img src={searchResult.imageUrl} class="result-image" alt="" />
644
- )
645
- : (
646
- showCheckbox && <div class={`checkbox-visual ${isSelected ? 'checked' : ''}`} aria-hidden="true"></div>
647
- )}
648
-
649
- <div class="item-content">
650
- <span class="item-text">{item.text}</span>
651
- {hasSubtitle && (
652
- <span class="item-subtitle">{searchResult.subtitle}</span>
653
- )}
654
- </div>
738
+ {this.renderDefaultListItemContent(item, isSelected)}
655
739
  </div>
656
740
  );
657
741
  }
@@ -662,7 +746,7 @@ export default class SmartDropdown extends TsxComponent<SmartDropdownArgs> imple
662
746
  return (
663
747
  <FormItemWrapper label={this.label} cssClass={this.cssClass} mandatory={this.mandatory} wrap={this.wrap} appendIcon={this.appendIcon} prependIcon={this.prependIcon} hint={this.hint} marginType={this.marginType} appendClicked={this.appendClicked} prependClicked={this.prependClicked} prependIconClicked={this.prependIconClicked} appendIconClicked={this.appendIconClicked} maxWidth={this.maxWidth} validationState={this.validationState} labelButtons={this.labelButtons} subtitle={this.subtitle} showClearValueButton={this.showClearValueButton}>
664
748
  <div
665
- class={`gopass-filter-wrapper mode-${this.searchMode}`}
749
+ class={`smart-dropdown-wrapper mode-${this.searchMode}`}
666
750
  // Only the outer wrapper acts as combobox if not in direct input mode
667
751
  role={this.searchMode !== 'input' ? 'combobox' : undefined}
668
752
  aria-expanded={this.isOpen}
@@ -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 != null ? this.getCustomRenderedLabel(h) : this.checkboxLabelHtml}
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 != null ? this.getCustomRenderedLabel(h) : <HtmlLiteral innerHTML={this.checkboxLabelHtml} />}
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 != null ? this.getCustomRenderedLabel(h) : <HtmlLiteral innerHTML={this.checkboxLabelHtml} />}
163
+ {this.getCustomRenderedLabel(h) ?? <HtmlLiteral innerHTML={this.checkboxLabelHtml} />}
164
164
  </label>
165
165
  </div>
166
166
  </div>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "inviton-powerduck",
3
3
  "type": "module",
4
- "version": "0.0.225",
4
+ "version": "0.0.227",
5
5
  "files": [
6
6
  "app/",
7
7
  "common/",