@spicainternational/ngx-sds-components 8.3.0-beta.0 → 8.4.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.
@@ -1,21 +1,43 @@
1
1
  import * as i0 from '@angular/core';
2
- import { EventEmitter, Output, Input, ViewChild, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { inject, ChangeDetectorRef, Injector, input, EventEmitter, viewChild, ViewChild, Output, Input, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { NgControl, NG_VALUE_ACCESSOR } from '@angular/forms';
3
4
  import { FaIconComponent } from '@fortawesome/angular-fontawesome';
4
5
  import { NgClass, NgFor, NgIf } from '@angular/common';
5
6
 
6
7
  class SdsSegmentedControlComponent {
7
- constructor(cdr) {
8
- this.cdr = cdr;
9
- this.segmentPadding = 'loose';
10
- this.enableAnimation = true;
11
- this.itemChange = new EventEmitter();
12
- this.valueChange = new EventEmitter();
8
+ constructor() {
9
+ // #region Dependencies
10
+ this._cdr = inject(ChangeDetectorRef);
11
+ this._injector = inject(Injector);
13
12
  this.valueExpr = 'value';
14
13
  this.displayExpr = 'text';
15
14
  this.disabled = false;
16
15
  this.style = 'default';
16
+ this.segmentPadding = 'loose';
17
+ this.enableAnimation = true;
18
+ this.ariaLabel = input();
19
+ // #endregion Inputs
20
+ // #region Outputs
21
+ this.itemChange = new EventEmitter();
22
+ this.valueChange = new EventEmitter();
23
+ this.containerRef = viewChild('containerRef');
24
+ // #endregion DOM references
25
+ // #region ControlValueAccessor private state
26
+ this._ngControl = null;
27
+ this._onChange = () => { };
28
+ this._onTouched = () => { };
29
+ }
30
+ // #endregion ControlValueAccessor private state
31
+ ngOnInit() {
32
+ /**
33
+ * Don't inject ngControl at the constructor, because it causes Cyclic Dependency.
34
+ * We can inject it via Injector to avoid the error.
35
+ */
36
+ this._ngControl = this._injector.get(NgControl, null);
37
+ if (this._ngControl !== null) {
38
+ this._ngControl.valueAccessor = this;
39
+ }
17
40
  }
18
- ngOnInit() { }
19
41
  ngAfterViewInit() {
20
42
  if (this.enableAnimation) {
21
43
  this.updateClipPath();
@@ -27,18 +49,114 @@ class SdsSegmentedControlComponent {
27
49
  setTimeout(() => this.updateClipPath(), 50);
28
50
  }
29
51
  }
52
+ // #region ControlValueAccessor implementation
53
+ writeValue(value) {
54
+ if (value !== undefined && value !== null) {
55
+ this.value = value;
56
+ this._cdr.markForCheck();
57
+ }
58
+ }
59
+ registerOnChange(fn) {
60
+ this._onChange = fn;
61
+ }
62
+ registerOnTouched(fn) {
63
+ this._onTouched = fn;
64
+ }
65
+ setDisabledState(isDisabled) {
66
+ this.disabled = isDisabled;
67
+ this._cdr.markForCheck();
68
+ }
69
+ // #endregion ControlValueAccessor implementation
30
70
  selectItem(item, event) {
31
71
  event.stopPropagation();
32
72
  if (!this.disabled) {
33
73
  this.value = item[this.valueExpr];
34
74
  this.valueChange.emit(this.value);
35
75
  this.itemChange.emit(item);
76
+ // Notify form control if in form context
77
+ if (this._ngControl) {
78
+ this._onChange(this.value);
79
+ this._onTouched();
80
+ }
36
81
  if (this.enableAnimation) {
37
- this.cdr.detectChanges();
82
+ this._cdr.detectChanges();
38
83
  this.updateClipPath();
39
84
  }
40
85
  }
41
86
  }
87
+ onSegmentKeydown(event, item) {
88
+ if (this.disabled) {
89
+ return;
90
+ }
91
+ const currentIndex = this.getItemIndex(item);
92
+ let nextIndex = null;
93
+ switch (event.key) {
94
+ case 'ArrowLeft':
95
+ event.preventDefault();
96
+ nextIndex = currentIndex > 0 ? currentIndex - 1 : (this.items?.length ?? 1) - 1;
97
+ break;
98
+ case 'ArrowRight':
99
+ event.preventDefault();
100
+ nextIndex = currentIndex < (this.items?.length ?? 1) - 1 ? currentIndex + 1 : 0;
101
+ break;
102
+ case 'Home':
103
+ event.preventDefault();
104
+ nextIndex = 0;
105
+ break;
106
+ case 'End':
107
+ event.preventDefault();
108
+ nextIndex = (this.items?.length ?? 1) - 1;
109
+ break;
110
+ }
111
+ if (nextIndex !== null && this.items) {
112
+ this.navigateToItem(nextIndex);
113
+ }
114
+ }
115
+ getSegmentAriaLabel(item, index) {
116
+ // Only set an explicit aria-label when visible text is intentionally omitted.
117
+ if (this.displayExpr) {
118
+ return null;
119
+ }
120
+ if (this.tooltipExpr && item?.[this.tooltipExpr]) {
121
+ return String(item[this.tooltipExpr]);
122
+ }
123
+ if (item?.[this.valueExpr] !== undefined && item?.[this.valueExpr] !== null) {
124
+ return String(item[this.valueExpr]);
125
+ }
126
+ return `Segment option ${index + 1}`;
127
+ }
128
+ getItemIndex(item) {
129
+ return this.items?.indexOf(item) ?? -1;
130
+ }
131
+ navigateToItem(index) {
132
+ if (!this.items || index < 0 || index >= this.items.length) {
133
+ return;
134
+ }
135
+ const item = this.items[index];
136
+ this.value = item[this.valueExpr];
137
+ this.valueChange.emit(this.value);
138
+ this.itemChange.emit(item);
139
+ // Notify form control if in form context
140
+ if (this._ngControl) {
141
+ this._onChange(this.value);
142
+ this._onTouched();
143
+ }
144
+ if (this.enableAnimation) {
145
+ this._cdr.detectChanges();
146
+ this.updateClipPath();
147
+ }
148
+ // Focus the segment element after change detection
149
+ this.focusSegmentElement(index);
150
+ }
151
+ focusSegmentElement(index) {
152
+ // Use setTimeout to ensure DOM is updated before focusing
153
+ setTimeout(() => {
154
+ const segmentElements = this.containerRef()?.nativeElement.querySelectorAll('.segment:not(.segment-overlay)');
155
+ if (segmentElements && segmentElements[index]) {
156
+ segmentElements[index].focus();
157
+ }
158
+ }, 0);
159
+ }
42
160
  updateClipPath() {
43
161
  setTimeout(() => {
44
162
  const container = this.clipPathContainerRef?.nativeElement;
@@ -66,8 +184,14 @@ class SdsSegmentedControlComponent {
66
184
  }
67
185
  }, 0);
68
186
  }
69
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SdsSegmentedControlComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
70
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SdsSegmentedControlComponent, isStandalone: true, selector: "sds-segmented-control", inputs: { items: "items", value: "value", valueExpr: "valueExpr", displayExpr: "displayExpr", iconExpr: "iconExpr", tooltipExpr: "tooltipExpr", idExpr: "idExpr", disabled: "disabled", style: "style", segmentPadding: "segmentPadding", enableAnimation: "enableAnimation" }, outputs: { itemChange: "itemChange", valueChange: "valueChange" }, viewQueries: [{ propertyName: "clipPathContainerRef", first: true, predicate: ["clipPathContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div \n class=\"sds-segmented-control-container\" \n [ngClass]=\"{\n 'disabled': disabled,\n 'sds-segmented-control-primary': style == 'primary',\n 'sds-segmented-control-inverted': style == 'inverted',\n 'clip-path-enabled': enableAnimation\n }\">\n \n <div *ngFor=\"let item of items; let last = last;\" \n class=\"segment\" \n id=\"{{idExpr ? item[idExpr]: ''}}\"\n [class.selected]=\"item[valueExpr] == value\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [title]=\"tooltipExpr && item[tooltipExpr] ? item[tooltipExpr] : ''\"\n (click)=\"selectItem(item, $event)\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n\n <div *ngIf=\"enableAnimation\" \n class=\"sds-clip-path-overlay\" \n #clipPathContainer \n aria-hidden=\"true\">\n <div *ngFor=\"let item of items; let last = last;\" \n class=\"segment segment-overlay\" \n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [tabIndex]=\"-1\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n </div>\n</div>", styles: [".sds-segmented-control-container .segment.tight-padding{padding-left:.5rem;padding-right:.5rem}.sds-segmented-control-container{display:inline-block;padding:max(.125rem,2px);border-style:solid;border-width:1px;border-radius:6px;border-color:#ced4da;background-color:#fff;font-size:.9rem;position:relative;white-space:nowrap}.sds-segmented-control-container .disabled{pointer-events:none;opacity:.5;background:#ced4da}.sds-segmented-control-container .segment{display:inline-block;border-radius:4px;color:#343434;cursor:pointer;color:#000;font-weight:500;margin-left:auto;margin-right:auto;padding:.25rem 1rem;-webkit-user-select:none;user-select:none}.sds-segmented-control-container .segment.selected{background-color:var(--bs-gray-300)}.sds-segmented-control-container .segment.selected .separator{border-color:transparent}.sds-segmented-control-container .segment:hover:not(.selected){background-color:transparent}.sds-segmented-control-container.disabled{pointer-events:none;opacity:.5;cursor:default}.sds-segmented-control-container.sds-segmented-control-primary .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-container.sds-segmented-control-inverted .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-container.clip-path-enabled .segment.selected{background-color:initial;color:initial}.sds-segmented-control-container .sds-clip-path-overlay{position:absolute;top:max(.125rem,2px);left:max(.125rem,2px);right:max(.125rem,2px);bottom:max(.125rem,2px);display:flex;z-index:1;overflow:hidden;transition:clip-path .25s ease;pointer-events:none;border-radius:4px;background-color:var(--bs-gray-300)}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000;font-weight:500;background:transparent}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay:hover{background:transparent}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay .segment-overlay{color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-light .sds-segmented-control-container{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-light .sds-segmented-control-container .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-primary .sds-segmented-control-container .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#fff}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "spin", "pulse", "mask", "styles", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "classes", "transform", "a11yRole"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
187
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SdsSegmentedControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
188
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "17.3.12", type: SdsSegmentedControlComponent, isStandalone: true, selector: "sds-segmented-control", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: false, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: false, isRequired: false, transformFunction: null }, valueExpr: { classPropertyName: "valueExpr", publicName: "valueExpr", isSignal: false, isRequired: false, transformFunction: null }, displayExpr: { classPropertyName: "displayExpr", publicName: "displayExpr", isSignal: false, isRequired: false, transformFunction: null }, iconExpr: { classPropertyName: "iconExpr", publicName: "iconExpr", isSignal: false, isRequired: false, transformFunction: null }, tooltipExpr: { classPropertyName: "tooltipExpr", publicName: "tooltipExpr", isSignal: false, isRequired: false, transformFunction: null }, idExpr: { classPropertyName: "idExpr", publicName: "idExpr", isSignal: false, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, style: { classPropertyName: "style", publicName: "style", isSignal: false, isRequired: false, transformFunction: null }, segmentPadding: { classPropertyName: "segmentPadding", publicName: "segmentPadding", isSignal: false, isRequired: false, transformFunction: null }, enableAnimation: { classPropertyName: "enableAnimation", publicName: "enableAnimation", isSignal: false, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemChange: "itemChange", valueChange: "valueChange" }, providers: [
189
+ {
190
+ provide: NG_VALUE_ACCESSOR,
191
+ useExisting: SdsSegmentedControlComponent,
192
+ multi: true,
193
+ },
194
+ ], viewQueries: [{ propertyName: "containerRef", first: true, predicate: ["containerRef"], descendants: true, isSignal: true }, { propertyName: "clipPathContainerRef", first: true, predicate: ["clipPathContainer"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n #containerRef\n class=\"sds-segmented-control-container\"\n role=\"group\"\n [attr.aria-label]=\"ariaLabel() || 'Segmented control'\"\n [ngClass]=\"{\n 'disabled': disabled,\n 'sds-segmented-control-primary': style == 'primary',\n 'sds-segmented-control-inverted': style == 'inverted',\n 'clip-path-enabled': enableAnimation\n }\">\n\n <div *ngFor=\"let item of items; let index = index; let last = last;\"\n class=\"segment\"\n id=\"{{idExpr ? item[idExpr]: ''}}\"\n role=\"button\"\n [tabindex]=\"item[valueExpr] === value ? 0 : -1\"\n [attr.aria-label]=\"getSegmentAriaLabel(item, index)\"\n [attr.aria-pressed]=\"item[valueExpr] === value\"\n [class.selected]=\"item[valueExpr] == value\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [title]=\"tooltipExpr && item[tooltipExpr] ? item[tooltipExpr] : ''\"\n (click)=\"selectItem(item, $event)\"\n (keydown)=\"onSegmentKeydown($event, item)\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n\n <div *ngIf=\"enableAnimation\"\n class=\"sds-clip-path-overlay\"\n #clipPathContainer\n aria-hidden=\"true\">\n <div *ngFor=\"let item of items; let last = last;\"\n class=\"segment segment-overlay\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [tabIndex]=\"-1\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n </div>\n</div>\n", styles: [".sds-segmented-control-container .segment.tight-padding{padding-left:.5rem;padding-right:.5rem}.sds-segmented-control-container{display:inline-block;padding:max(.125rem,2px);border-style:solid;border-width:1px;border-radius:6px;border-color:#ced4da;background-color:#fff;font-size:.9rem;position:relative;white-space:nowrap;outline:none;transition:box-shadow .15s ease}.sds-segmented-control-container:focus-within{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--bs-primary)}.sds-segmented-control-container .disabled{pointer-events:none;opacity:.5;background:#ced4da}.sds-segmented-control-container .segment{display:inline-block;border-radius:4px;color:#343434;cursor:pointer;color:#000;font-weight:500;margin-left:auto;margin-right:auto;padding:.25rem 1rem;-webkit-user-select:none;user-select:none;outline:none;transition:box-shadow .15s ease}.sds-segmented-control-container .segment.selected{background-color:var(--bs-gray-300)}.sds-segmented-control-container .segment.selected .separator{border-color:transparent}.sds-segmented-control-container .segment:hover:not(.selected){background-color:transparent}.sds-segmented-control-container .segment:focus-visible{box-shadow:inset 0 0 0 2px #fff,inset 0 0 0 4px var(--bs-primary);border-radius:4px}.sds-segmented-control-container.disabled{pointer-events:none;opacity:.5;cursor:default}.sds-segmented-control-container.sds-segmented-control-primary .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-container.sds-segmented-control-primary .segment:focus-visible{box-shadow:inset 0 0 0 2px var(--bs-primary),inset 0 0 0 4px #fff}.sds-segmented-control-container.sds-segmented-control-primary:focus-within{box-shadow:0 0 0 2px var(--bs-primary),0 0 0 4px #fff}.sds-segmented-control-container.sds-segmented-control-inverted{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-container.sds-segmented-control-inverted .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-container.sds-segmented-control-inverted .segment:focus-visible{box-shadow:inset 0 0 0 2px var(--bs-gray-300),inset 0 0 0 4px var(--bs-primary)}.sds-segmented-control-container.sds-segmented-control-inverted:focus-within{box-shadow:0 0 0 2px var(--bs-gray-300),0 0 0 4px var(--bs-primary)}.sds-segmented-control-container.clip-path-enabled .segment.selected{background-color:initial;color:initial}.sds-segmented-control-container .sds-clip-path-overlay{position:absolute;top:max(.125rem,2px);left:max(.125rem,2px);right:max(.125rem,2px);bottom:max(.125rem,2px);display:flex;z-index:1;overflow:hidden;transition:clip-path .25s ease;pointer-events:none;border-radius:4px;background-color:var(--bs-gray-300)}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000;font-weight:500;background:transparent}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay:hover{background:transparent}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay .segment-overlay{color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-light .sds-segmented-control-container{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-light .sds-segmented-control-container .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-primary .sds-segmented-control-container .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#fff}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "spin", "pulse", "mask", "styles", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "classes", "transform", "a11yRole"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
71
195
  }
72
196
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SdsSegmentedControlComponent, decorators: [{
73
197
  type: Component,
@@ -76,11 +200,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
76
200
  NgFor,
77
201
  NgIf,
78
202
  FaIconComponent,
79
- ], template: "<div \n class=\"sds-segmented-control-container\" \n [ngClass]=\"{\n 'disabled': disabled,\n 'sds-segmented-control-primary': style == 'primary',\n 'sds-segmented-control-inverted': style == 'inverted',\n 'clip-path-enabled': enableAnimation\n }\">\n \n <div *ngFor=\"let item of items; let last = last;\" \n class=\"segment\" \n id=\"{{idExpr ? item[idExpr]: ''}}\"\n [class.selected]=\"item[valueExpr] == value\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [title]=\"tooltipExpr && item[tooltipExpr] ? item[tooltipExpr] : ''\"\n (click)=\"selectItem(item, $event)\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n\n <div *ngIf=\"enableAnimation\" \n class=\"sds-clip-path-overlay\" \n #clipPathContainer \n aria-hidden=\"true\">\n <div *ngFor=\"let item of items; let last = last;\" \n class=\"segment segment-overlay\" \n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [tabIndex]=\"-1\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n </div>\n</div>", styles: [".sds-segmented-control-container .segment.tight-padding{padding-left:.5rem;padding-right:.5rem}.sds-segmented-control-container{display:inline-block;padding:max(.125rem,2px);border-style:solid;border-width:1px;border-radius:6px;border-color:#ced4da;background-color:#fff;font-size:.9rem;position:relative;white-space:nowrap}.sds-segmented-control-container .disabled{pointer-events:none;opacity:.5;background:#ced4da}.sds-segmented-control-container .segment{display:inline-block;border-radius:4px;color:#343434;cursor:pointer;color:#000;font-weight:500;margin-left:auto;margin-right:auto;padding:.25rem 1rem;-webkit-user-select:none;user-select:none}.sds-segmented-control-container .segment.selected{background-color:var(--bs-gray-300)}.sds-segmented-control-container .segment.selected .separator{border-color:transparent}.sds-segmented-control-container .segment:hover:not(.selected){background-color:transparent}.sds-segmented-control-container.disabled{pointer-events:none;opacity:.5;cursor:default}.sds-segmented-control-container.sds-segmented-control-primary .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-container.sds-segmented-control-inverted .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-container.clip-path-enabled .segment.selected{background-color:initial;color:initial}.sds-segmented-control-container .sds-clip-path-overlay{position:absolute;top:max(.125rem,2px);left:max(.125rem,2px);right:max(.125rem,2px);bottom:max(.125rem,2px);display:flex;z-index:1;overflow:hidden;transition:clip-path .25s ease;pointer-events:none;border-radius:4px;background-color:var(--bs-gray-300)}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000;font-weight:500;background:transparent}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay:hover{background:transparent}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay .segment-overlay{color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-light .sds-segmented-control-container{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-light .sds-segmented-control-container .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-primary .sds-segmented-control-container .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#fff}\n"] }]
80
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { clipPathContainerRef: [{
81
- type: ViewChild,
82
- args: ['clipPathContainer']
83
- }], items: [{
203
+ ], providers: [
204
+ {
205
+ provide: NG_VALUE_ACCESSOR,
206
+ useExisting: SdsSegmentedControlComponent,
207
+ multi: true,
208
+ },
209
+ ], template: "<div\n #containerRef\n class=\"sds-segmented-control-container\"\n role=\"group\"\n [attr.aria-label]=\"ariaLabel() || 'Segmented control'\"\n [ngClass]=\"{\n 'disabled': disabled,\n 'sds-segmented-control-primary': style == 'primary',\n 'sds-segmented-control-inverted': style == 'inverted',\n 'clip-path-enabled': enableAnimation\n }\">\n\n <div *ngFor=\"let item of items; let index = index; let last = last;\"\n class=\"segment\"\n id=\"{{idExpr ? item[idExpr]: ''}}\"\n role=\"button\"\n [tabindex]=\"item[valueExpr] === value ? 0 : -1\"\n [attr.aria-label]=\"getSegmentAriaLabel(item, index)\"\n [attr.aria-pressed]=\"item[valueExpr] === value\"\n [class.selected]=\"item[valueExpr] == value\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [title]=\"tooltipExpr && item[tooltipExpr] ? item[tooltipExpr] : ''\"\n (click)=\"selectItem(item, $event)\"\n (keydown)=\"onSegmentKeydown($event, item)\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n\n <div *ngIf=\"enableAnimation\"\n class=\"sds-clip-path-overlay\"\n #clipPathContainer\n aria-hidden=\"true\">\n <div *ngFor=\"let item of items; let last = last;\"\n class=\"segment segment-overlay\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [tabIndex]=\"-1\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n </div>\n</div>\n", styles: [".sds-segmented-control-container .segment.tight-padding{padding-left:.5rem;padding-right:.5rem}.sds-segmented-control-container{display:inline-block;padding:max(.125rem,2px);border-style:solid;border-width:1px;border-radius:6px;border-color:#ced4da;background-color:#fff;font-size:.9rem;position:relative;white-space:nowrap;outline:none;transition:box-shadow .15s ease}.sds-segmented-control-container:focus-within{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--bs-primary)}.sds-segmented-control-container .disabled{pointer-events:none;opacity:.5;background:#ced4da}.sds-segmented-control-container .segment{display:inline-block;border-radius:4px;color:#343434;cursor:pointer;color:#000;font-weight:500;margin-left:auto;margin-right:auto;padding:.25rem 1rem;-webkit-user-select:none;user-select:none;outline:none;transition:box-shadow .15s ease}.sds-segmented-control-container .segment.selected{background-color:var(--bs-gray-300)}.sds-segmented-control-container .segment.selected .separator{border-color:transparent}.sds-segmented-control-container .segment:hover:not(.selected){background-color:transparent}.sds-segmented-control-container .segment:focus-visible{box-shadow:inset 0 0 0 2px #fff,inset 0 0 0 4px var(--bs-primary);border-radius:4px}.sds-segmented-control-container.disabled{pointer-events:none;opacity:.5;cursor:default}.sds-segmented-control-container.sds-segmented-control-primary .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-container.sds-segmented-control-primary .segment:focus-visible{box-shadow:inset 0 0 0 2px var(--bs-primary),inset 0 0 0 4px #fff}.sds-segmented-control-container.sds-segmented-control-primary:focus-within{box-shadow:0 0 0 2px var(--bs-primary),0 0 0 4px #fff}.sds-segmented-control-container.sds-segmented-control-inverted{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-container.sds-segmented-control-inverted .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-container.sds-segmented-control-inverted .segment:focus-visible{box-shadow:inset 0 0 0 2px var(--bs-gray-300),inset 0 0 0 4px var(--bs-primary)}.sds-segmented-control-container.sds-segmented-control-inverted:focus-within{box-shadow:0 0 0 2px var(--bs-gray-300),0 0 0 4px var(--bs-primary)}.sds-segmented-control-container.clip-path-enabled .segment.selected{background-color:initial;color:initial}.sds-segmented-control-container .sds-clip-path-overlay{position:absolute;top:max(.125rem,2px);left:max(.125rem,2px);right:max(.125rem,2px);bottom:max(.125rem,2px);display:flex;z-index:1;overflow:hidden;transition:clip-path .25s ease;pointer-events:none;border-radius:4px;background-color:var(--bs-gray-300)}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000;font-weight:500;background:transparent}.sds-segmented-control-container .sds-clip-path-overlay .segment-overlay:hover{background:transparent}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-container.sds-segmented-control-primary .sds-clip-path-overlay .segment-overlay{color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-container.sds-segmented-control-inverted .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-light .sds-segmented-control-container{background-color:var(--bs-gray-300);border-color:var(--bs-gray-300);border-width:0}.sds-segmented-control-light .sds-segmented-control-container .segment.selected{background-color:#fff;color:#000}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay{background-color:#fff}.sds-segmented-control-light .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#000}.sds-segmented-control-primary .sds-segmented-control-container .segment.selected{background-color:var(--bs-primary);color:#fff}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay{background-color:var(--bs-primary)}.sds-segmented-control-primary .sds-segmented-control-container .sds-clip-path-overlay .segment-overlay{color:#fff}\n"] }]
210
+ }], propDecorators: { items: [{
84
211
  type: Input
85
212
  }], value: [{
86
213
  type: Input
@@ -106,6 +233,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
106
233
  type: Output
107
234
  }], valueChange: [{
108
235
  type: Output
236
+ }], clipPathContainerRef: [{
237
+ type: ViewChild,
238
+ args: ['clipPathContainer']
109
239
  }] } });
110
240
 
111
241
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"spicainternational-ngx-sds-components-src-lib-segmented-control.mjs","sources":["../../../projects/ngx-sds-components/src/lib/segmented-control/segmented-control.component.ts","../../../projects/ngx-sds-components/src/lib/segmented-control/segmented-control.component.html","../../../projects/ngx-sds-components/src/lib/segmented-control/spicainternational-ngx-sds-components-src-lib-segmented-control.ts"],"sourcesContent":["import {\n AfterViewInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n Input,\n OnChanges,\n OnInit,\n Output,\n SimpleChanges,\n ViewChild,\n} from '@angular/core';\nimport { FaIconComponent } from '@fortawesome/angular-fontawesome';\nimport { NgClass, NgFor, NgIf } from '@angular/common';\n\n@Component({\n selector: 'sds-segmented-control',\n templateUrl: './segmented-control.component.html',\n styleUrls: ['./segmented-control.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n imports: [\n NgClass,\n NgFor,\n NgIf,\n FaIconComponent,\n ],\n})\nexport class SdsSegmentedControlComponent implements OnInit, AfterViewInit, OnChanges {\n @ViewChild('clipPathContainer') clipPathContainerRef!: ElementRef<HTMLDivElement>;\n\n @Input() items: any[] | undefined;\n @Input() value: any;\n @Input() valueExpr;\n @Input() displayExpr: string | undefined;\n @Input() iconExpr: string | undefined;\n @Input() tooltipExpr: string | undefined;\n @Input() idExpr: string | undefined;\n @Input() disabled: boolean;\n @Input() style: 'default' | 'primary' | 'inverted';\n @Input() segmentPadding: 'tight' | 'loose' = 'loose';\n @Input() enableAnimation: boolean = true;\n\n @Output() itemChange: EventEmitter<any> = new EventEmitter();\n @Output() valueChange: EventEmitter<any> = new EventEmitter();\n\n constructor(private cdr: ChangeDetectorRef) {\n this.valueExpr = 'value';\n this.displayExpr = 'text';\n this.disabled = false;\n this.style = 'default';\n }\n\n ngOnInit() {}\n\n ngAfterViewInit() {\n if (this.enableAnimation) {\n this.updateClipPath();\n }\n }\n\n ngOnChanges(changes: SimpleChanges) {\n if ((changes['value'] || changes['enableClipPathAnimation']) && this.enableAnimation) {\n // Use a longer timeout to ensure the DOM is updated\n setTimeout(() => this.updateClipPath(), 50);\n }\n }\n\n public selectItem(item: any, event: MouseEvent): void {\n event.stopPropagation();\n\n if (!this.disabled) {\n this.value = item[this.valueExpr];\n this.valueChange.emit(this.value);\n this.itemChange.emit(item);\n\n if (this.enableAnimation) {\n this.cdr.detectChanges(); \n this.updateClipPath();\n }\n }\n }\n\n private updateClipPath() {\n setTimeout(() => {\n const container = this.clipPathContainerRef?.nativeElement;\n if (!container) return;\n\n const activeSegment = container.parentElement?.querySelector(\n `.segment.selected:not(.segment-overlay)`\n ) as HTMLElement;\n\n if (activeSegment && container.parentElement) {\n const parentElement = container.parentElement;\n \n const computedStyle = window.getComputedStyle(parentElement);\n const paddingLeft = parseFloat(computedStyle.paddingLeft);\n \n const offsetLeft = activeSegment.offsetLeft - paddingLeft;\n const offsetWidth = activeSegment.offsetWidth;\n const overlayWidth = container.offsetWidth;\n\n // Only update if we have valid dimensions\n if (offsetWidth === 0 || overlayWidth === 0) {\n // Retry after a short delay if elements aren't rendered yet\n setTimeout(() => this.updateClipPath(), 100);\n return;\n }\n\n const clipLeft = offsetLeft;\n const clipRight = offsetLeft + offsetWidth;\n \n const clipLeftPercent = ((clipLeft / overlayWidth) * 100).toFixed(2);\n const clipRightPercent = (100 - (clipRight / overlayWidth) * 100).toFixed(2);\n \n container.style.clipPath = `inset(0 ${clipRightPercent}% 0 ${clipLeftPercent}% round 4px)`;\n }\n }, 0);\n }\n}","<div \n class=\"sds-segmented-control-container\" \n [ngClass]=\"{\n 'disabled': disabled,\n 'sds-segmented-control-primary': style == 'primary',\n 'sds-segmented-control-inverted': style == 'inverted',\n 'clip-path-enabled': enableAnimation\n }\">\n \n <div *ngFor=\"let item of items; let last = last;\" \n class=\"segment\" \n id=\"{{idExpr ? item[idExpr]: ''}}\"\n [class.selected]=\"item[valueExpr] == value\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [title]=\"tooltipExpr && item[tooltipExpr] ? item[tooltipExpr] : ''\"\n (click)=\"selectItem(item, $event)\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n\n <div *ngIf=\"enableAnimation\" \n class=\"sds-clip-path-overlay\" \n #clipPathContainer \n aria-hidden=\"true\">\n <div *ngFor=\"let item of items; let last = last;\" \n class=\"segment segment-overlay\" \n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [tabIndex]=\"-1\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n </div>\n</div>","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"spicainternational-ngx-sds-components-src-lib-segmented-control.mjs","sources":["../../../projects/ngx-sds-components/src/lib/segmented-control/segmented-control.component.ts","../../../projects/ngx-sds-components/src/lib/segmented-control/segmented-control.component.html","../../../projects/ngx-sds-components/src/lib/segmented-control/spicainternational-ngx-sds-components-src-lib-segmented-control.ts"],"sourcesContent":["import {\n AfterViewInit,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ElementRef,\n EventEmitter,\n Injector,\n Input,\n OnChanges,\n OnInit,\n Output,\n SimpleChanges,\n ViewChild,\n inject,\n input,\n viewChild,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';\nimport { FaIconComponent } from '@fortawesome/angular-fontawesome';\nimport { NgClass, NgFor, NgIf } from '@angular/common';\n\n@Component({\n selector: 'sds-segmented-control',\n templateUrl: './segmented-control.component.html',\n styleUrls: ['./segmented-control.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: true,\n imports: [\n NgClass,\n NgFor,\n NgIf,\n FaIconComponent,\n ],\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: SdsSegmentedControlComponent,\n multi: true,\n },\n ],\n})\nexport class SdsSegmentedControlComponent implements OnInit, AfterViewInit, OnChanges, ControlValueAccessor {\n\n\n // #region Dependencies\n private _cdr = inject(ChangeDetectorRef);\n private _injector = inject(Injector);\n // #endregion Dependencies\n\n // #region Inputs\n @Input() items: any[] | undefined;\n @Input() value: any;\n @Input() valueExpr = 'value';\n @Input() displayExpr: string | undefined = 'text';\n @Input() iconExpr: string | undefined;\n @Input() tooltipExpr: string | undefined;\n @Input() idExpr: string | undefined;\n @Input() disabled: boolean = false;\n @Input() style: 'default' | 'primary' | 'inverted' = 'default';\n @Input() segmentPadding: 'tight' | 'loose' = 'loose';\n @Input() enableAnimation: boolean = true;\n public ariaLabel = input<string | undefined>();\n // #endregion Inputs\n\n // #region Outputs\n @Output() itemChange: EventEmitter<any> = new EventEmitter();\n @Output() valueChange: EventEmitter<any> = new EventEmitter();\n // #endregion Outputs\n\n // #region DOM references\n @ViewChild('clipPathContainer') clipPathContainerRef!: ElementRef<HTMLDivElement>;\n protected containerRef = viewChild<ElementRef<HTMLDivElement>>('containerRef');\n // #endregion DOM references\n\n // #region ControlValueAccessor private state\n private _ngControl: NgControl | null = null;\n private _onChange: (value: any) => void = () => {};\n private _onTouched: () => void = () => {};\n // #endregion ControlValueAccessor private state\n\n ngOnInit() {\n /**\n * Don't inject ngControl at the constructor, because it causes Cyclic Dependency.\n * We can inject it via Injector to avoid the error.\n */\n this._ngControl = this._injector.get(NgControl, null);\n\n if (this._ngControl !== null) {\n this._ngControl.valueAccessor = this;\n }\n }\n\n ngAfterViewInit() {\n if (this.enableAnimation) {\n this.updateClipPath();\n }\n }\n\n ngOnChanges(changes: SimpleChanges) {\n if ((changes['value'] || changes['enableClipPathAnimation']) && this.enableAnimation) {\n // Use a longer timeout to ensure the DOM is updated\n setTimeout(() => this.updateClipPath(), 50);\n }\n }\n\n // #region ControlValueAccessor implementation\n public writeValue(value: any): void {\n if (value !== undefined && value !== null) {\n this.value = value;\n this._cdr.markForCheck();\n }\n }\n\n public registerOnChange(fn: (value: any) => void): void {\n this._onChange = fn;\n }\n\n public registerOnTouched(fn: () => void): void {\n this._onTouched = fn;\n }\n\n public setDisabledState(isDisabled: boolean): void {\n this.disabled = isDisabled;\n this._cdr.markForCheck();\n }\n // #endregion ControlValueAccessor implementation\n\n public selectItem(item: any, event: MouseEvent): void {\n event.stopPropagation();\n\n if (!this.disabled) {\n this.value = item[this.valueExpr];\n this.valueChange.emit(this.value);\n this.itemChange.emit(item);\n\n // Notify form control if in form context\n if (this._ngControl) {\n this._onChange(this.value);\n this._onTouched();\n }\n\n if (this.enableAnimation) {\n this._cdr.detectChanges();\n this.updateClipPath();\n }\n }\n }\n\n public onSegmentKeydown(event: KeyboardEvent, item: any): void {\n if (this.disabled) {\n return;\n }\n\n const currentIndex = this.getItemIndex(item);\n let nextIndex: number | null = null;\n\n switch (event.key) {\n case 'ArrowLeft':\n event.preventDefault();\n nextIndex = currentIndex > 0 ? currentIndex - 1 : (this.items?.length ?? 1) - 1;\n break;\n case 'ArrowRight':\n event.preventDefault();\n nextIndex = currentIndex < (this.items?.length ?? 1) - 1 ? currentIndex + 1 : 0;\n break;\n case 'Home':\n event.preventDefault();\n nextIndex = 0;\n break;\n case 'End':\n event.preventDefault();\n nextIndex = (this.items?.length ?? 1) - 1;\n break;\n }\n\n if (nextIndex !== null && this.items) {\n this.navigateToItem(nextIndex);\n }\n }\n\n public getSegmentAriaLabel(item: any, index: number): string | null {\n // Only set an explicit aria-label when visible text is intentionally omitted.\n if (this.displayExpr) {\n return null;\n }\n\n if (this.tooltipExpr && item?.[this.tooltipExpr]) {\n return String(item[this.tooltipExpr]);\n }\n\n if (item?.[this.valueExpr] !== undefined && item?.[this.valueExpr] !== null) {\n return String(item[this.valueExpr]);\n }\n\n return `Segment option ${index + 1}`;\n }\n\n private getItemIndex(item: any): number {\n return this.items?.indexOf(item) ?? -1;\n }\n\n private navigateToItem(index: number): void {\n if (!this.items || index < 0 || index >= this.items.length) {\n return;\n }\n\n const item = this.items[index];\n this.value = item[this.valueExpr];\n this.valueChange.emit(this.value);\n this.itemChange.emit(item);\n\n // Notify form control if in form context\n if (this._ngControl) {\n this._onChange(this.value);\n this._onTouched();\n }\n\n if (this.enableAnimation) {\n this._cdr.detectChanges();\n this.updateClipPath();\n }\n\n // Focus the segment element after change detection\n this.focusSegmentElement(index);\n }\n\n private focusSegmentElement(index: number): void {\n // Use setTimeout to ensure DOM is updated before focusing\n setTimeout(() => {\n const segmentElements = this.containerRef()?.nativeElement.querySelectorAll('.segment:not(.segment-overlay)');\n if (segmentElements && segmentElements[index]) {\n (segmentElements[index] as HTMLElement).focus();\n }\n }, 0);\n }\n\n private updateClipPath() {\n setTimeout(() => {\n const container = this.clipPathContainerRef?.nativeElement;\n if (!container) return;\n\n const activeSegment = container.parentElement?.querySelector(\n `.segment.selected:not(.segment-overlay)`\n ) as HTMLElement;\n\n if (activeSegment && container.parentElement) {\n const parentElement = container.parentElement;\n\n const computedStyle = window.getComputedStyle(parentElement);\n const paddingLeft = parseFloat(computedStyle.paddingLeft);\n\n const offsetLeft = activeSegment.offsetLeft - paddingLeft;\n const offsetWidth = activeSegment.offsetWidth;\n const overlayWidth = container.offsetWidth;\n\n // Only update if we have valid dimensions\n if (offsetWidth === 0 || overlayWidth === 0) {\n // Retry after a short delay if elements aren't rendered yet\n setTimeout(() => this.updateClipPath(), 100);\n return;\n }\n\n const clipLeft = offsetLeft;\n const clipRight = offsetLeft + offsetWidth;\n\n const clipLeftPercent = ((clipLeft / overlayWidth) * 100).toFixed(2);\n const clipRightPercent = (100 - (clipRight / overlayWidth) * 100).toFixed(2);\n\n container.style.clipPath = `inset(0 ${clipRightPercent}% 0 ${clipLeftPercent}% round 4px)`;\n }\n }, 0);\n }\n}\n","<div\n #containerRef\n class=\"sds-segmented-control-container\"\n role=\"group\"\n [attr.aria-label]=\"ariaLabel() || 'Segmented control'\"\n [ngClass]=\"{\n 'disabled': disabled,\n 'sds-segmented-control-primary': style == 'primary',\n 'sds-segmented-control-inverted': style == 'inverted',\n 'clip-path-enabled': enableAnimation\n }\">\n\n <div *ngFor=\"let item of items; let index = index; let last = last;\"\n class=\"segment\"\n id=\"{{idExpr ? item[idExpr]: ''}}\"\n role=\"button\"\n [tabindex]=\"item[valueExpr] === value ? 0 : -1\"\n [attr.aria-label]=\"getSegmentAriaLabel(item, index)\"\n [attr.aria-pressed]=\"item[valueExpr] === value\"\n [class.selected]=\"item[valueExpr] == value\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [title]=\"tooltipExpr && item[tooltipExpr] ? item[tooltipExpr] : ''\"\n (click)=\"selectItem(item, $event)\"\n (keydown)=\"onSegmentKeydown($event, item)\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n\n <div *ngIf=\"enableAnimation\"\n class=\"sds-clip-path-overlay\"\n #clipPathContainer\n aria-hidden=\"true\">\n <div *ngFor=\"let item of items; let last = last;\"\n class=\"segment segment-overlay\"\n [class.tight-padding]=\"segmentPadding == 'tight'\"\n [tabIndex]=\"-1\">\n\n <div class=\"sds-flex-row-center gap-2\">\n <fa-icon *ngIf=\"iconExpr && item[iconExpr]\" [icon]=\"item[iconExpr]\" [fixedWidth]=\"true\"></fa-icon>\n <span *ngIf=\"displayExpr\">{{item[displayExpr]}}</span>\n </div>\n </div>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spicainternational/ngx-sds-components",
3
- "version": "8.3.0-beta.0",
3
+ "version": "8.4.0",
4
4
  "license": "MIT",
5
5
  "description": "Spica design system angular components.",
6
6
  "type": "module",
@@ -27,6 +27,12 @@ export declare class SdsModalComponent implements OnInit, OnChanges {
27
27
  * @memberof SdsModalComponent
28
28
  */
29
29
  isDragConstrained: boolean;
30
+ /**
31
+ * @description
32
+ * Label for the close button, used for accessibility.
33
+ * If not provided, it will fall back to the default translation for "close".
34
+ */
35
+ closeButtonLabel: import("@angular/core").InputSignal<string | undefined>;
30
36
  /**
31
37
  * @deprecated Use isOpenChange instead
32
38
  */
@@ -50,5 +56,5 @@ export declare class SdsModalComponent implements OnInit, OnChanges {
50
56
  onCloseButtonClick(): void;
51
57
  onKeydown(event: KeyboardEvent): void;
52
58
  static ɵfac: i0.ɵɵFactoryDeclaration<SdsModalComponent, never>;
53
- static ɵcmp: i0.ɵɵComponentDeclaration<SdsModalComponent, "sds-modal", never, { "modalTitle": { "alias": "modalTitle"; "required": false; }; "showHeader": { "alias": "showHeader"; "required": false; }; "showFooter": { "alias": "showFooter"; "required": false; }; "size": { "alias": "size"; "required": false; }; "modalDialogId": { "alias": "modalDialogId"; "required": false; }; "showCloseButton": { "alias": "showCloseButton"; "required": false; }; "autoFocusCloseButton": { "alias": "autoFocusCloseButton"; "required": false; }; "translations": { "alias": "translations"; "required": false; }; "isScrollable": { "alias": "isScrollable"; "required": false; }; "isVerticallyCentered": { "alias": "isVerticallyCentered"; "required": false; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; }; "downSizing": { "alias": "downSizing"; "required": false; }; "isDraggable": { "alias": "isDraggable"; "required": false; }; "isDragConstrained": { "alias": "isDragConstrained"; "required": false; }; "isOpen": { "alias": "isOpen"; "required": false; }; }, { "modalOpen": "modalOpen"; "modalClose": "modalClose"; "closeClick": "closeClick"; "closeEscapeKeypress": "closeEscapeKeypress"; "isOpenChange": "isOpenChange"; }, ["headerContent"], ["header", "*", "footer"], true, never>;
59
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdsModalComponent, "sds-modal", never, { "modalTitle": { "alias": "modalTitle"; "required": false; }; "showHeader": { "alias": "showHeader"; "required": false; }; "showFooter": { "alias": "showFooter"; "required": false; }; "size": { "alias": "size"; "required": false; }; "modalDialogId": { "alias": "modalDialogId"; "required": false; }; "showCloseButton": { "alias": "showCloseButton"; "required": false; }; "autoFocusCloseButton": { "alias": "autoFocusCloseButton"; "required": false; }; "translations": { "alias": "translations"; "required": false; }; "isScrollable": { "alias": "isScrollable"; "required": false; }; "isVerticallyCentered": { "alias": "isVerticallyCentered"; "required": false; }; "closeOnEscape": { "alias": "closeOnEscape"; "required": false; }; "downSizing": { "alias": "downSizing"; "required": false; }; "isDraggable": { "alias": "isDraggable"; "required": false; }; "isDragConstrained": { "alias": "isDragConstrained"; "required": false; }; "closeButtonLabel": { "alias": "closeButtonLabel"; "required": false; "isSignal": true; }; "isOpen": { "alias": "isOpen"; "required": false; }; }, { "modalOpen": "modalOpen"; "modalClose": "modalClose"; "closeClick": "closeClick"; "closeEscapeKeypress": "closeEscapeKeypress"; "isOpenChange": "isOpenChange"; }, ["headerContent"], ["header", "*", "footer"], true, never>;
54
60
  }
@@ -1,8 +1,9 @@
1
- import { AfterViewInit, ChangeDetectorRef, ElementRef, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
1
+ import { AfterViewInit, ElementRef, EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2
+ import { ControlValueAccessor } from '@angular/forms';
2
3
  import * as i0 from "@angular/core";
3
- export declare class SdsSegmentedControlComponent implements OnInit, AfterViewInit, OnChanges {
4
- private cdr;
5
- clipPathContainerRef: ElementRef<HTMLDivElement>;
4
+ export declare class SdsSegmentedControlComponent implements OnInit, AfterViewInit, OnChanges, ControlValueAccessor {
5
+ private _cdr;
6
+ private _injector;
6
7
  items: any[] | undefined;
7
8
  value: any;
8
9
  valueExpr: string;
@@ -14,14 +15,28 @@ export declare class SdsSegmentedControlComponent implements OnInit, AfterViewIn
14
15
  style: 'default' | 'primary' | 'inverted';
15
16
  segmentPadding: 'tight' | 'loose';
16
17
  enableAnimation: boolean;
18
+ ariaLabel: import("@angular/core").InputSignal<string | undefined>;
17
19
  itemChange: EventEmitter<any>;
18
20
  valueChange: EventEmitter<any>;
19
- constructor(cdr: ChangeDetectorRef);
21
+ clipPathContainerRef: ElementRef<HTMLDivElement>;
22
+ protected containerRef: import("@angular/core").Signal<ElementRef<HTMLDivElement> | undefined>;
23
+ private _ngControl;
24
+ private _onChange;
25
+ private _onTouched;
20
26
  ngOnInit(): void;
21
27
  ngAfterViewInit(): void;
22
28
  ngOnChanges(changes: SimpleChanges): void;
29
+ writeValue(value: any): void;
30
+ registerOnChange(fn: (value: any) => void): void;
31
+ registerOnTouched(fn: () => void): void;
32
+ setDisabledState(isDisabled: boolean): void;
23
33
  selectItem(item: any, event: MouseEvent): void;
34
+ onSegmentKeydown(event: KeyboardEvent, item: any): void;
35
+ getSegmentAriaLabel(item: any, index: number): string | null;
36
+ private getItemIndex;
37
+ private navigateToItem;
38
+ private focusSegmentElement;
24
39
  private updateClipPath;
25
40
  static ɵfac: i0.ɵɵFactoryDeclaration<SdsSegmentedControlComponent, never>;
26
- static ɵcmp: i0.ɵɵComponentDeclaration<SdsSegmentedControlComponent, "sds-segmented-control", never, { "items": { "alias": "items"; "required": false; }; "value": { "alias": "value"; "required": false; }; "valueExpr": { "alias": "valueExpr"; "required": false; }; "displayExpr": { "alias": "displayExpr"; "required": false; }; "iconExpr": { "alias": "iconExpr"; "required": false; }; "tooltipExpr": { "alias": "tooltipExpr"; "required": false; }; "idExpr": { "alias": "idExpr"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "style": { "alias": "style"; "required": false; }; "segmentPadding": { "alias": "segmentPadding"; "required": false; }; "enableAnimation": { "alias": "enableAnimation"; "required": false; }; }, { "itemChange": "itemChange"; "valueChange": "valueChange"; }, never, never, true, never>;
41
+ static ɵcmp: i0.ɵɵComponentDeclaration<SdsSegmentedControlComponent, "sds-segmented-control", never, { "items": { "alias": "items"; "required": false; }; "value": { "alias": "value"; "required": false; }; "valueExpr": { "alias": "valueExpr"; "required": false; }; "displayExpr": { "alias": "displayExpr"; "required": false; }; "iconExpr": { "alias": "iconExpr"; "required": false; }; "tooltipExpr": { "alias": "tooltipExpr"; "required": false; }; "idExpr": { "alias": "idExpr"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "style": { "alias": "style"; "required": false; }; "segmentPadding": { "alias": "segmentPadding"; "required": false; }; "enableAnimation": { "alias": "enableAnimation"; "required": false; }; "ariaLabel": { "alias": "ariaLabel"; "required": false; "isSignal": true; }; }, { "itemChange": "itemChange"; "valueChange": "valueChange"; }, never, never, true, never>;
27
42
  }