@lesterarte/sefin-ui 0.0.20-dev.4 → 0.0.20-dev.6

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.
@@ -3026,6 +3026,125 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3026
3026
  type: Output
3027
3027
  }] } });
3028
3028
 
3029
+ class RateComponent {
3030
+ /** Current rating value (0 to max) */
3031
+ set value(value) {
3032
+ this._value.set(Math.max(0, Math.min(value, this.max)));
3033
+ }
3034
+ get value() {
3035
+ return this._value();
3036
+ }
3037
+ _value = signal(0, ...(ngDevMode ? [{ debugName: "_value" }] : []));
3038
+ /** Maximum rating value */
3039
+ max = 5;
3040
+ /** Whether the rating is disabled */
3041
+ disabled = false;
3042
+ /** Whether the rating is readonly */
3043
+ readonly = false;
3044
+ /** Whether to allow half stars */
3045
+ allowHalf = false;
3046
+ /** Icon type. Options: 'star' | 'heart' | 'thumb' */
3047
+ icon = 'star';
3048
+ /** Rate size. Options: 'sm' | 'md' | 'lg' */
3049
+ size = 'md';
3050
+ /** Whether to show text with rating */
3051
+ showText = false;
3052
+ /** Additional CSS classes */
3053
+ class = '';
3054
+ /** Event emitted when rating changes */
3055
+ valueChange = new EventEmitter();
3056
+ /** Event emitted when rating is hovered */
3057
+ hoverChange = new EventEmitter();
3058
+ /** Internal hover value */
3059
+ _hoverValue = signal(null, ...(ngDevMode ? [{ debugName: "_hoverValue" }] : []));
3060
+ items = computed(() => {
3061
+ return Array.from({ length: this.max }, (_, i) => i + 1);
3062
+ }, ...(ngDevMode ? [{ debugName: "items" }] : []));
3063
+ get rateClasses() {
3064
+ return [
3065
+ 'sefin-rate',
3066
+ `sefin-rate--${this.size}`,
3067
+ `sefin-rate--${this.icon}`,
3068
+ this.disabled ? 'sefin-rate--disabled' : '',
3069
+ this.readonly ? 'sefin-rate--readonly' : '',
3070
+ this.class,
3071
+ ]
3072
+ .filter(Boolean)
3073
+ .join(' ');
3074
+ }
3075
+ isInteractive() {
3076
+ return !this.disabled && !this.readonly;
3077
+ }
3078
+ getDisplayValue() {
3079
+ return this._hoverValue() ?? this.value;
3080
+ }
3081
+ getIconState(index) {
3082
+ const displayValue = this.getDisplayValue();
3083
+ if (displayValue >= index) {
3084
+ return 'full';
3085
+ }
3086
+ if (this.allowHalf && displayValue >= index - 0.5) {
3087
+ return 'half';
3088
+ }
3089
+ return 'empty';
3090
+ }
3091
+ onItemClick(index) {
3092
+ if (!this.isInteractive()) {
3093
+ return;
3094
+ }
3095
+ const newValue = index;
3096
+ if (newValue !== this.value) {
3097
+ this._value.set(newValue);
3098
+ this.valueChange.emit(newValue);
3099
+ }
3100
+ }
3101
+ onItemHover(index) {
3102
+ if (!this.isInteractive()) {
3103
+ return;
3104
+ }
3105
+ this._hoverValue.set(index);
3106
+ this.hoverChange.emit(index);
3107
+ }
3108
+ onHalfClick(index, isLeftHalf) {
3109
+ if (!this.isInteractive() || !this.allowHalf) {
3110
+ return;
3111
+ }
3112
+ const newValue = isLeftHalf ? index - 0.5 : index;
3113
+ if (newValue !== this.value) {
3114
+ this._value.set(newValue);
3115
+ this.valueChange.emit(newValue);
3116
+ }
3117
+ }
3118
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3119
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: RateComponent, isStandalone: true, selector: "sefin-rate", inputs: { value: "value", max: "max", disabled: "disabled", readonly: "readonly", allowHalf: "allowHalf", icon: "icon", size: "size", showText: "showText", class: "class" }, outputs: { valueChange: "valueChange", hoverChange: "hoverChange" }, ngImport: i0, template: "<div [class]=\"rateClasses\">\n <div class=\"sefin-rate__container\">\n <div\n *ngFor=\"let item of items(); let i = index\"\n class=\"sefin-rate__item\"\n (mouseenter)=\"onItemHover(item)\"\n (mouseleave)=\"onItemHover(null)\"\n [class.sefin-rate__item--interactive]=\"isInteractive()\"\n >\n <ng-container [ngSwitch]=\"icon\">\n <!-- Star icon -->\n <div *ngSwitchCase=\"'star'\" class=\"sefin-rate__icon-wrapper\">\n <ng-container *ngIf=\"allowHalf && isInteractive(); else fullStar\">\n <div class=\"sefin-rate__icon-half\" (click)=\"onHalfClick(item, true)\">\n <svg\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--half]=\"getIconState(item) === 'half'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n <div class=\"sefin-rate__icon-half sefin-rate__icon-half--right\" (click)=\"onHalfClick(item, false)\">\n <svg\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--half]=\"getIconState(item) === 'half'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </ng-container>\n <ng-template #fullStar>\n <svg\n class=\"sefin-rate__icon\"\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--half]=\"getIconState(item) === 'half'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n (click)=\"onItemClick(item)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </ng-template>\n </div>\n\n <!-- Heart icon -->\n <svg\n *ngSwitchCase=\"'heart'\"\n class=\"sefin-rate__icon\"\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n (click)=\"onItemClick(item)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M20.84 4.61C20.3292 4.099 19.7228 3.69364 19.0554 3.41708C18.3879 3.14052 17.6725 2.99817 16.95 2.99817C16.2275 2.99817 15.5121 3.14052 14.8446 3.41708C14.1772 3.69364 13.5708 4.099 13.06 4.61L12 5.67L10.94 4.61C9.9083 3.57831 8.50903 2.99871 7.05 2.99871C5.59096 2.99871 4.19169 3.57831 3.16 4.61C2.1283 5.64169 1.54871 7.04097 1.54871 8.5C1.54871 9.95903 2.1283 11.3583 3.16 12.39L4.22 13.45L12 21.23L19.78 13.45L20.84 12.39C21.351 11.8792 21.7564 11.2728 22.0329 10.6054C22.3095 9.93789 22.4518 9.22248 22.4518 8.5C22.4518 7.77752 22.3095 7.0621 22.0329 6.39464C21.7564 5.72718 21.351 5.12075 20.84 4.61Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n\n <!-- Thumb icon -->\n <svg\n *ngSwitchCase=\"'thumb'\"\n class=\"sefin-rate__icon\"\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n (click)=\"onItemClick(item)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7 22V11M2 13V20C2 21.1046 2.89543 22 4 22H16.4262C17.907 22 19.1662 20.9197 19.3914 19.4562L20.4683 12.4562C20.7479 10.6388 19.3411 9 17.5032 9H14C13.4477 9 13 8.55228 13 8V4.46584C13 3.10399 11.896 2 10.5342 2C10.2093 2 9.91498 2.1913 9.78306 2.48812L7.26394 8.57899C7.09882 8.95673 6.74568 9.2 6.35471 9.2H4C2.89543 9.2 2 10.0954 2 11.2V13Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </ng-container>\n </div>\n </div>\n \n <span *ngIf=\"showText\" class=\"sefin-rate__text\">\n {{ value }} / {{ max }}\n </span>\n</div>\n\n", styles: [".sefin-rate{display:inline-flex;align-items:center;gap:var(--sefin-spacing-sm, 8px);font-family:var(--sefin-font-family-base)}.sefin-rate__container{display:inline-flex;align-items:center;gap:var(--sefin-spacing-xs, 4px)}.sefin-rate__item{display:inline-flex;align-items:center;justify-content:center;position:relative;line-height:0}.sefin-rate__item--interactive{cursor:pointer}.sefin-rate__icon-wrapper{display:flex;position:relative;width:100%;height:100%}.sefin-rate__icon-half{position:absolute;width:50%;height:100%;overflow:hidden;display:flex;align-items:center;justify-content:flex-start;cursor:pointer}.sefin-rate__icon-half--right{right:0;justify-content:flex-end}.sefin-rate__icon-half svg{width:200%;height:100%}.sefin-rate__icon-half--right svg{transform:translate(-50%)}.sefin-rate__icon{display:block;transition:all .2s ease-in-out;stroke:var(--sefin-color-border);fill:none}.sefin-rate__icon--full{stroke:var(--sefin-color-primary);fill:var(--sefin-color-primary)}.sefin-rate__icon--half{stroke:var(--sefin-color-primary)}.sefin-rate__icon--empty{stroke:var(--sefin-color-border);fill:none}.sefin-rate__item--interactive .sefin-rate__icon{cursor:pointer}.sefin-rate__item--interactive .sefin-rate__icon:hover{stroke:var(--sefin-color-primary);transform:scale(1.1)}.sefin-rate__text{font-size:var(--sefin-font-size-base);color:var(--sefin-color-text-secondary);font-weight:var(--sefin-font-weight-medium);line-height:var(--sefin-line-height-normal)}.sefin-rate--sm .sefin-rate__icon,.sefin-rate--sm .sefin-rate__icon-wrapper{width:16px;height:16px}.sefin-rate--sm .sefin-rate__text{font-size:var(--sefin-font-size-sm, 14px)}.sefin-rate--md .sefin-rate__icon,.sefin-rate--md .sefin-rate__icon-wrapper{width:20px;height:20px}.sefin-rate--md .sefin-rate__text{font-size:var(--sefin-font-size-base, 16px)}.sefin-rate--lg .sefin-rate__icon,.sefin-rate--lg .sefin-rate__icon-wrapper{width:24px;height:24px}.sefin-rate--lg .sefin-rate__text{font-size:var(--sefin-font-size-lg, 18px)}.sefin-rate--star .sefin-rate__icon--full{color:var(--sefin-color-warning);stroke:var(--sefin-color-warning);fill:var(--sefin-color-warning)}.sefin-rate--star .sefin-rate__icon--half,.sefin-rate--star .sefin-rate__item--interactive .sefin-rate__icon:hover{color:var(--sefin-color-warning);stroke:var(--sefin-color-warning)}.sefin-rate--heart .sefin-rate__icon--full{color:var(--sefin-color-error);stroke:var(--sefin-color-error);fill:var(--sefin-color-error)}.sefin-rate--heart .sefin-rate__icon--half,.sefin-rate--heart .sefin-rate__item--interactive .sefin-rate__icon:hover{color:var(--sefin-color-error);stroke:var(--sefin-color-error)}.sefin-rate--thumb .sefin-rate__icon--full{color:var(--sefin-color-success);stroke:var(--sefin-color-success);fill:var(--sefin-color-success)}.sefin-rate--thumb .sefin-rate__icon--half,.sefin-rate--thumb .sefin-rate__item--interactive .sefin-rate__icon:hover{color:var(--sefin-color-success);stroke:var(--sefin-color-success)}.sefin-rate--disabled .sefin-rate__item,.sefin-rate--readonly .sefin-rate__item{cursor:default;pointer-events:none}.sefin-rate--disabled .sefin-rate__icon,.sefin-rate--readonly .sefin-rate__icon{opacity:.6}.sefin-rate .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-primary)}.sefin-rate--star .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-warning)}.sefin-rate--heart .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-error)}.sefin-rate--thumb .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-success)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3120
+ }
3121
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: RateComponent, decorators: [{
3122
+ type: Component,
3123
+ args: [{ selector: 'sefin-rate', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [class]=\"rateClasses\">\n <div class=\"sefin-rate__container\">\n <div\n *ngFor=\"let item of items(); let i = index\"\n class=\"sefin-rate__item\"\n (mouseenter)=\"onItemHover(item)\"\n (mouseleave)=\"onItemHover(null)\"\n [class.sefin-rate__item--interactive]=\"isInteractive()\"\n >\n <ng-container [ngSwitch]=\"icon\">\n <!-- Star icon -->\n <div *ngSwitchCase=\"'star'\" class=\"sefin-rate__icon-wrapper\">\n <ng-container *ngIf=\"allowHalf && isInteractive(); else fullStar\">\n <div class=\"sefin-rate__icon-half\" (click)=\"onHalfClick(item, true)\">\n <svg\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--half]=\"getIconState(item) === 'half'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n <div class=\"sefin-rate__icon-half sefin-rate__icon-half--right\" (click)=\"onHalfClick(item, false)\">\n <svg\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--half]=\"getIconState(item) === 'half'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </div>\n </ng-container>\n <ng-template #fullStar>\n <svg\n class=\"sefin-rate__icon\"\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--half]=\"getIconState(item) === 'half'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n (click)=\"onItemClick(item)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </ng-template>\n </div>\n\n <!-- Heart icon -->\n <svg\n *ngSwitchCase=\"'heart'\"\n class=\"sefin-rate__icon\"\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n (click)=\"onItemClick(item)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M20.84 4.61C20.3292 4.099 19.7228 3.69364 19.0554 3.41708C18.3879 3.14052 17.6725 2.99817 16.95 2.99817C16.2275 2.99817 15.5121 3.14052 14.8446 3.41708C14.1772 3.69364 13.5708 4.099 13.06 4.61L12 5.67L10.94 4.61C9.9083 3.57831 8.50903 2.99871 7.05 2.99871C5.59096 2.99871 4.19169 3.57831 3.16 4.61C2.1283 5.64169 1.54871 7.04097 1.54871 8.5C1.54871 9.95903 2.1283 11.3583 3.16 12.39L4.22 13.45L12 21.23L19.78 13.45L20.84 12.39C21.351 11.8792 21.7564 11.2728 22.0329 10.6054C22.3095 9.93789 22.4518 9.22248 22.4518 8.5C22.4518 7.77752 22.3095 7.0621 22.0329 6.39464C21.7564 5.72718 21.351 5.12075 20.84 4.61Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n\n <!-- Thumb icon -->\n <svg\n *ngSwitchCase=\"'thumb'\"\n class=\"sefin-rate__icon\"\n [class.sefin-rate__icon--full]=\"getIconState(item) === 'full'\"\n [class.sefin-rate__icon--empty]=\"getIconState(item) === 'empty'\"\n (click)=\"onItemClick(item)\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M7 22V11M2 13V20C2 21.1046 2.89543 22 4 22H16.4262C17.907 22 19.1662 20.9197 19.3914 19.4562L20.4683 12.4562C20.7479 10.6388 19.3411 9 17.5032 9H14C13.4477 9 13 8.55228 13 8V4.46584C13 3.10399 11.896 2 10.5342 2C10.2093 2 9.91498 2.1913 9.78306 2.48812L7.26394 8.57899C7.09882 8.95673 6.74568 9.2 6.35471 9.2H4C2.89543 9.2 2 10.0954 2 11.2V13Z\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </ng-container>\n </div>\n </div>\n \n <span *ngIf=\"showText\" class=\"sefin-rate__text\">\n {{ value }} / {{ max }}\n </span>\n</div>\n\n", styles: [".sefin-rate{display:inline-flex;align-items:center;gap:var(--sefin-spacing-sm, 8px);font-family:var(--sefin-font-family-base)}.sefin-rate__container{display:inline-flex;align-items:center;gap:var(--sefin-spacing-xs, 4px)}.sefin-rate__item{display:inline-flex;align-items:center;justify-content:center;position:relative;line-height:0}.sefin-rate__item--interactive{cursor:pointer}.sefin-rate__icon-wrapper{display:flex;position:relative;width:100%;height:100%}.sefin-rate__icon-half{position:absolute;width:50%;height:100%;overflow:hidden;display:flex;align-items:center;justify-content:flex-start;cursor:pointer}.sefin-rate__icon-half--right{right:0;justify-content:flex-end}.sefin-rate__icon-half svg{width:200%;height:100%}.sefin-rate__icon-half--right svg{transform:translate(-50%)}.sefin-rate__icon{display:block;transition:all .2s ease-in-out;stroke:var(--sefin-color-border);fill:none}.sefin-rate__icon--full{stroke:var(--sefin-color-primary);fill:var(--sefin-color-primary)}.sefin-rate__icon--half{stroke:var(--sefin-color-primary)}.sefin-rate__icon--empty{stroke:var(--sefin-color-border);fill:none}.sefin-rate__item--interactive .sefin-rate__icon{cursor:pointer}.sefin-rate__item--interactive .sefin-rate__icon:hover{stroke:var(--sefin-color-primary);transform:scale(1.1)}.sefin-rate__text{font-size:var(--sefin-font-size-base);color:var(--sefin-color-text-secondary);font-weight:var(--sefin-font-weight-medium);line-height:var(--sefin-line-height-normal)}.sefin-rate--sm .sefin-rate__icon,.sefin-rate--sm .sefin-rate__icon-wrapper{width:16px;height:16px}.sefin-rate--sm .sefin-rate__text{font-size:var(--sefin-font-size-sm, 14px)}.sefin-rate--md .sefin-rate__icon,.sefin-rate--md .sefin-rate__icon-wrapper{width:20px;height:20px}.sefin-rate--md .sefin-rate__text{font-size:var(--sefin-font-size-base, 16px)}.sefin-rate--lg .sefin-rate__icon,.sefin-rate--lg .sefin-rate__icon-wrapper{width:24px;height:24px}.sefin-rate--lg .sefin-rate__text{font-size:var(--sefin-font-size-lg, 18px)}.sefin-rate--star .sefin-rate__icon--full{color:var(--sefin-color-warning);stroke:var(--sefin-color-warning);fill:var(--sefin-color-warning)}.sefin-rate--star .sefin-rate__icon--half,.sefin-rate--star .sefin-rate__item--interactive .sefin-rate__icon:hover{color:var(--sefin-color-warning);stroke:var(--sefin-color-warning)}.sefin-rate--heart .sefin-rate__icon--full{color:var(--sefin-color-error);stroke:var(--sefin-color-error);fill:var(--sefin-color-error)}.sefin-rate--heart .sefin-rate__icon--half,.sefin-rate--heart .sefin-rate__item--interactive .sefin-rate__icon:hover{color:var(--sefin-color-error);stroke:var(--sefin-color-error)}.sefin-rate--thumb .sefin-rate__icon--full{color:var(--sefin-color-success);stroke:var(--sefin-color-success);fill:var(--sefin-color-success)}.sefin-rate--thumb .sefin-rate__icon--half,.sefin-rate--thumb .sefin-rate__item--interactive .sefin-rate__icon:hover{color:var(--sefin-color-success);stroke:var(--sefin-color-success)}.sefin-rate--disabled .sefin-rate__item,.sefin-rate--readonly .sefin-rate__item{cursor:default;pointer-events:none}.sefin-rate--disabled .sefin-rate__icon,.sefin-rate--readonly .sefin-rate__icon{opacity:.6}.sefin-rate .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-primary)}.sefin-rate--star .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-warning)}.sefin-rate--heart .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-error)}.sefin-rate--thumb .sefin-rate__icon-half .sefin-rate__icon--half{fill:var(--sefin-color-success)}\n"] }]
3124
+ }], propDecorators: { value: [{
3125
+ type: Input
3126
+ }], max: [{
3127
+ type: Input
3128
+ }], disabled: [{
3129
+ type: Input
3130
+ }], readonly: [{
3131
+ type: Input
3132
+ }], allowHalf: [{
3133
+ type: Input
3134
+ }], icon: [{
3135
+ type: Input
3136
+ }], size: [{
3137
+ type: Input
3138
+ }], showText: [{
3139
+ type: Input
3140
+ }], class: [{
3141
+ type: Input
3142
+ }], valueChange: [{
3143
+ type: Output
3144
+ }], hoverChange: [{
3145
+ type: Output
3146
+ }] } });
3147
+
3029
3148
  /**
3030
3149
  * Atoms index
3031
3150
  */
@@ -3432,6 +3551,144 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImpor
3432
3551
  type: Input
3433
3552
  }] } });
3434
3553
 
3554
+ class ButtonGroupComponent {
3555
+ sanitizer;
3556
+ constructor(sanitizer) {
3557
+ this.sanitizer = sanitizer;
3558
+ }
3559
+ /** Array of button options */
3560
+ options = [];
3561
+ /** Selected value (for segmented variant) */
3562
+ value = null;
3563
+ /** Whether multiple selection is allowed (for default variant) */
3564
+ multiple = false;
3565
+ /** Selected values (for multiple selection) */
3566
+ selectedValues = [];
3567
+ /** Button variant style. Options: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' */
3568
+ variant = 'primary';
3569
+ /** Button size. Options: 'sm' | 'md' | 'lg' */
3570
+ size = 'md';
3571
+ /** Button group variant. Options: 'default' | 'segmented' */
3572
+ groupVariant = 'default';
3573
+ /** Whether the button group is disabled */
3574
+ disabled = false;
3575
+ /** Additional CSS classes */
3576
+ class = '';
3577
+ /** Event emitted when value changes (for segmented variant) */
3578
+ valueChange = new EventEmitter();
3579
+ /** Event emitted when selected values change (for multiple selection) */
3580
+ selectedValuesChange = new EventEmitter();
3581
+ /** Event emitted when a button is clicked */
3582
+ buttonClick = new EventEmitter();
3583
+ get buttonGroupClasses() {
3584
+ return [
3585
+ 'sefin-button-group',
3586
+ `sefin-button-group--${this.groupVariant}`,
3587
+ `sefin-button-group--${this.size}`,
3588
+ this.disabled ? 'sefin-button-group--disabled' : '',
3589
+ this.class,
3590
+ ]
3591
+ .filter(Boolean)
3592
+ .join(' ');
3593
+ }
3594
+ isSelected(option) {
3595
+ if (this.groupVariant === 'segmented') {
3596
+ return this.value === option.value;
3597
+ }
3598
+ return this.selectedValues.includes(option.value);
3599
+ }
3600
+ onButtonClick(option) {
3601
+ if (this.disabled || option.disabled) {
3602
+ return;
3603
+ }
3604
+ this.buttonClick.emit(option);
3605
+ if (this.groupVariant === 'segmented') {
3606
+ // Toggle selection for segmented
3607
+ const newValue = this.value === option.value ? null : option.value;
3608
+ this.value = newValue;
3609
+ this.valueChange.emit(newValue);
3610
+ }
3611
+ else {
3612
+ // Multiple selection logic
3613
+ const index = this.selectedValues.indexOf(option.value);
3614
+ if (this.multiple) {
3615
+ if (index >= 0) {
3616
+ // Deselect
3617
+ this.selectedValues = this.selectedValues.filter((v) => v !== option.value);
3618
+ }
3619
+ else {
3620
+ // Select
3621
+ this.selectedValues = [...this.selectedValues, option.value];
3622
+ }
3623
+ this.selectedValuesChange.emit([...this.selectedValues]);
3624
+ }
3625
+ else {
3626
+ // Single selection (even in default variant)
3627
+ if (index >= 0) {
3628
+ // Deselect if already selected
3629
+ this.selectedValues = [];
3630
+ }
3631
+ else {
3632
+ // Select only this one
3633
+ this.selectedValues = [option.value];
3634
+ }
3635
+ this.selectedValuesChange.emit([...this.selectedValues]);
3636
+ }
3637
+ }
3638
+ }
3639
+ getButtonVariant(option) {
3640
+ // For default variant, always use primary to create unified look
3641
+ if (this.groupVariant === 'default') {
3642
+ return 'primary';
3643
+ }
3644
+ // For segmented variant, use outline for non-selected
3645
+ if (this.isSelected(option)) {
3646
+ return this.variant;
3647
+ }
3648
+ return 'outline';
3649
+ }
3650
+ sanitizeHtml(html) {
3651
+ if (!html)
3652
+ return '';
3653
+ // For simple text, return as is
3654
+ if (html.length <= 2 && !html.includes('<')) {
3655
+ return html;
3656
+ }
3657
+ // Use sanitize for user-provided HTML (icons)
3658
+ return this.sanitizer.sanitize(1, html) || '';
3659
+ }
3660
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonGroupComponent, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
3661
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.0.6", type: ButtonGroupComponent, isStandalone: true, selector: "sefin-button-group", inputs: { options: "options", value: "value", multiple: "multiple", selectedValues: "selectedValues", variant: "variant", size: "size", groupVariant: "groupVariant", disabled: "disabled", class: "class" }, outputs: { valueChange: "valueChange", selectedValuesChange: "selectedValuesChange", buttonClick: "buttonClick" }, ngImport: i0, template: "<div [class]=\"buttonGroupClasses\" role=\"group\" [attr.aria-label]=\"'Button group'\">\n <sefin-button\n *ngFor=\"let option of options\"\n [variant]=\"getButtonVariant(option)\"\n [size]=\"size\"\n [disabled]=\"disabled || option.disabled\"\n [class.sefin-button-group__button]=\"true\"\n [class.sefin-button-group__button--selected]=\"isSelected(option)\"\n (clicked)=\"onButtonClick(option)\"\n >\n <span *ngIf=\"option.icon\" class=\"sefin-button-group__icon\" [innerHTML]=\"sanitizeHtml(option.icon)\"></span>\n {{ option.label }}\n </sefin-button>\n</div>\n\n", styles: [".sefin-button-group{display:inline-flex;align-items:stretch;gap:0;font-family:var(--sefin-font-family-base);position:relative;border-radius:var(--sefin-radius-md);overflow:hidden;box-shadow:var(--sefin-shadow-sm)}.sefin-button-group__button{position:relative;border-radius:0!important;margin:0;flex:1 1 0;min-width:0;width:0;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border:none}.sefin-button-group__button:first-child,.sefin-button-group__button:last-child{border-radius:0!important}.sefin-button-group__button:hover:not(:disabled){z-index:1}.sefin-button-group__button:focus-visible{z-index:2;outline-offset:-2px}.sefin-button-group__icon{display:inline-flex;align-items:center;justify-content:center;margin-right:var(--sefin-spacing-xs, 4px);flex-shrink:0}.sefin-button-group__icon svg{display:block;width:16px;height:16px}.sefin-button-group--segmented{background-color:var(--sefin-color-surface);border:1px solid var(--sefin-color-border);padding:var(--sefin-spacing-xs, 4px);gap:var(--sefin-spacing-xs, 4px);overflow:visible}.sefin-button-group--segmented .sefin-button-group__button{border:1px solid var(--sefin-color-primary)!important;background-color:var(--sefin-color-surface)!important;color:var(--sefin-color-primary)!important;border-radius:var(--sefin-radius-sm)!important;margin:0}.sefin-button-group--segmented .sefin-button-group__button:first-child,.sefin-button-group--segmented .sefin-button-group__button:last-child{border-radius:var(--sefin-radius-sm)!important}.sefin-button-group--segmented .sefin-button-group__button:not(:first-child){margin-left:var(--sefin-spacing-xs, 4px)}.sefin-button-group--segmented .sefin-button-group__button.sefin-button-group__button--selected{background-color:var(--sefin-color-primary)!important;color:#fff!important;border-color:var(--sefin-color-primary)!important}.sefin-button-group--segmented .sefin-button-group__button:not(.sefin-button-group__button--selected){background-color:var(--sefin-color-surface)!important;color:var(--sefin-color-primary)!important}.sefin-button-group--segmented .sefin-button-group__button:hover:not(:disabled){background-color:var(--sefin-color-surface-hover)!important}.sefin-button-group--segmented .sefin-button-group__button:hover:not(:disabled).sefin-button-group__button--selected{background-color:var(--sefin-color-primary-dark)!important}.sefin-button-group--default{background-color:var(--sefin-color-primary);border:1px solid var(--sefin-color-primary);box-shadow:var(--sefin-shadow-sm);padding:0}.sefin-button-group--default .sefin-button-group__button{border:none!important;border-radius:0!important;background-color:transparent!important;color:#fff!important;margin:0;box-shadow:none!important}.sefin-button-group--default .sefin-button-group__button.sefin-button-group__button--selected,.sefin-button-group--default .sefin-button-group__button:not(.sefin-button-group__button--selected){background-color:transparent!important;color:#fff!important}.sefin-button-group--default .sefin-button-group__button:hover:not(:disabled){background-color:#ffffff1a!important}.sefin-button-group--default .sefin-button-group__button:not(:last-child):after{content:\"\";position:absolute;right:0;top:25%;bottom:25%;width:1px;background-color:#ffffff40;pointer-events:none}.sefin-button-group--sm .sefin-button-group__icon svg{width:14px;height:14px}.sefin-button-group--md .sefin-button-group__icon svg{width:16px;height:16px}.sefin-button-group--lg .sefin-button-group__icon svg{width:18px;height:18px}.sefin-button-group--disabled{opacity:.6;pointer-events:none}.sefin-button-group .sefin-button{flex:1 1 0!important;min-width:0!important;width:0!important;text-align:center!important;display:flex!important;align-items:center!important;justify-content:center!important}.sefin-button-group .sefin-button:hover:not(:disabled){transform:none!important}.sefin-button-group .sefin-button:active:not(:disabled){transform:none!important}.sefin-button-group .sefin-button{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sefin-button-group--default .sefin-button{border-radius:0!important;border:none!important;box-shadow:none!important}.sefin-button-group--default .sefin-button.sefin-button--primary{background-color:transparent!important;border:none!important}.sefin-button-group--segmented .sefin-button{box-shadow:none!important}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: ButtonComponent, selector: "sefin-button", inputs: ["variant", "size", "disabled", "type", "class"], outputs: ["clicked"] }], changeDetection: i0.ChangeDetectionStrategy.Default });
3662
+ }
3663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.6", ngImport: i0, type: ButtonGroupComponent, decorators: [{
3664
+ type: Component,
3665
+ args: [{ selector: 'sefin-button-group', standalone: true, imports: [CommonModule, ButtonComponent], changeDetection: ChangeDetectionStrategy.Default, template: "<div [class]=\"buttonGroupClasses\" role=\"group\" [attr.aria-label]=\"'Button group'\">\n <sefin-button\n *ngFor=\"let option of options\"\n [variant]=\"getButtonVariant(option)\"\n [size]=\"size\"\n [disabled]=\"disabled || option.disabled\"\n [class.sefin-button-group__button]=\"true\"\n [class.sefin-button-group__button--selected]=\"isSelected(option)\"\n (clicked)=\"onButtonClick(option)\"\n >\n <span *ngIf=\"option.icon\" class=\"sefin-button-group__icon\" [innerHTML]=\"sanitizeHtml(option.icon)\"></span>\n {{ option.label }}\n </sefin-button>\n</div>\n\n", styles: [".sefin-button-group{display:inline-flex;align-items:stretch;gap:0;font-family:var(--sefin-font-family-base);position:relative;border-radius:var(--sefin-radius-md);overflow:hidden;box-shadow:var(--sefin-shadow-sm)}.sefin-button-group__button{position:relative;border-radius:0!important;margin:0;flex:1 1 0;min-width:0;width:0;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;border:none}.sefin-button-group__button:first-child,.sefin-button-group__button:last-child{border-radius:0!important}.sefin-button-group__button:hover:not(:disabled){z-index:1}.sefin-button-group__button:focus-visible{z-index:2;outline-offset:-2px}.sefin-button-group__icon{display:inline-flex;align-items:center;justify-content:center;margin-right:var(--sefin-spacing-xs, 4px);flex-shrink:0}.sefin-button-group__icon svg{display:block;width:16px;height:16px}.sefin-button-group--segmented{background-color:var(--sefin-color-surface);border:1px solid var(--sefin-color-border);padding:var(--sefin-spacing-xs, 4px);gap:var(--sefin-spacing-xs, 4px);overflow:visible}.sefin-button-group--segmented .sefin-button-group__button{border:1px solid var(--sefin-color-primary)!important;background-color:var(--sefin-color-surface)!important;color:var(--sefin-color-primary)!important;border-radius:var(--sefin-radius-sm)!important;margin:0}.sefin-button-group--segmented .sefin-button-group__button:first-child,.sefin-button-group--segmented .sefin-button-group__button:last-child{border-radius:var(--sefin-radius-sm)!important}.sefin-button-group--segmented .sefin-button-group__button:not(:first-child){margin-left:var(--sefin-spacing-xs, 4px)}.sefin-button-group--segmented .sefin-button-group__button.sefin-button-group__button--selected{background-color:var(--sefin-color-primary)!important;color:#fff!important;border-color:var(--sefin-color-primary)!important}.sefin-button-group--segmented .sefin-button-group__button:not(.sefin-button-group__button--selected){background-color:var(--sefin-color-surface)!important;color:var(--sefin-color-primary)!important}.sefin-button-group--segmented .sefin-button-group__button:hover:not(:disabled){background-color:var(--sefin-color-surface-hover)!important}.sefin-button-group--segmented .sefin-button-group__button:hover:not(:disabled).sefin-button-group__button--selected{background-color:var(--sefin-color-primary-dark)!important}.sefin-button-group--default{background-color:var(--sefin-color-primary);border:1px solid var(--sefin-color-primary);box-shadow:var(--sefin-shadow-sm);padding:0}.sefin-button-group--default .sefin-button-group__button{border:none!important;border-radius:0!important;background-color:transparent!important;color:#fff!important;margin:0;box-shadow:none!important}.sefin-button-group--default .sefin-button-group__button.sefin-button-group__button--selected,.sefin-button-group--default .sefin-button-group__button:not(.sefin-button-group__button--selected){background-color:transparent!important;color:#fff!important}.sefin-button-group--default .sefin-button-group__button:hover:not(:disabled){background-color:#ffffff1a!important}.sefin-button-group--default .sefin-button-group__button:not(:last-child):after{content:\"\";position:absolute;right:0;top:25%;bottom:25%;width:1px;background-color:#ffffff40;pointer-events:none}.sefin-button-group--sm .sefin-button-group__icon svg{width:14px;height:14px}.sefin-button-group--md .sefin-button-group__icon svg{width:16px;height:16px}.sefin-button-group--lg .sefin-button-group__icon svg{width:18px;height:18px}.sefin-button-group--disabled{opacity:.6;pointer-events:none}.sefin-button-group .sefin-button{flex:1 1 0!important;min-width:0!important;width:0!important;text-align:center!important;display:flex!important;align-items:center!important;justify-content:center!important}.sefin-button-group .sefin-button:hover:not(:disabled){transform:none!important}.sefin-button-group .sefin-button:active:not(:disabled){transform:none!important}.sefin-button-group .sefin-button{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.sefin-button-group--default .sefin-button{border-radius:0!important;border:none!important;box-shadow:none!important}.sefin-button-group--default .sefin-button.sefin-button--primary{background-color:transparent!important;border:none!important}.sefin-button-group--segmented .sefin-button{box-shadow:none!important}\n"] }]
3666
+ }], ctorParameters: () => [{ type: i1$1.DomSanitizer }], propDecorators: { options: [{
3667
+ type: Input
3668
+ }], value: [{
3669
+ type: Input
3670
+ }], multiple: [{
3671
+ type: Input
3672
+ }], selectedValues: [{
3673
+ type: Input
3674
+ }], variant: [{
3675
+ type: Input
3676
+ }], size: [{
3677
+ type: Input
3678
+ }], groupVariant: [{
3679
+ type: Input
3680
+ }], disabled: [{
3681
+ type: Input
3682
+ }], class: [{
3683
+ type: Input
3684
+ }], valueChange: [{
3685
+ type: Output
3686
+ }], selectedValuesChange: [{
3687
+ type: Output
3688
+ }], buttonClick: [{
3689
+ type: Output
3690
+ }] } });
3691
+
3435
3692
  class CardComponent {
3436
3693
  /** Card variant style. Options: 'default' | 'elevated' | 'outlined' */
3437
3694
  variant = 'default';
@@ -4647,5 +4904,5 @@ const STYLES_PATH = './styles/index.scss';
4647
4904
  * Generated bundle index. Do not edit.
4648
4905
  */
4649
4906
 
4650
- export { AccordionItemComponent, AlertComponent, AutocompleteComponent, AvatarComponent, BORDER_RADIUS_TOKENS, BRAND_THEME, BadgeComponent, BreadcrumbsComponent, ButtonComponent, COLOR_TOKENS, CardComponent, CheckboxComponent, ChipComponent, ContainerComponent, DARK_THEME, DESIGN_TOKENS, DatepickerComponent, DividerComponent, FabButtonComponent, IconButtonComponent, IconComponent, ImageComponent, LIGHT_THEME, LinkComponent, PaginationComponent, ProgressBarComponent, RadioComponent, SHADOW_TOKENS, SPACING_TOKENS, STYLES_PATH, SelectComponent, SpinnerComponent, StackComponent, SwitchComponent, TYPOGRAPHY_TOKENS, TabComponent, TagComponent, TextFieldComponent, TextareaComponent, ThemeLoader, ToastComponent, TooltipComponent, TypographyComponent };
4907
+ export { AccordionItemComponent, AlertComponent, AutocompleteComponent, AvatarComponent, BORDER_RADIUS_TOKENS, BRAND_THEME, BadgeComponent, BreadcrumbsComponent, ButtonComponent, ButtonGroupComponent, COLOR_TOKENS, CardComponent, CheckboxComponent, ChipComponent, ContainerComponent, DARK_THEME, DESIGN_TOKENS, DatepickerComponent, DividerComponent, FabButtonComponent, IconButtonComponent, IconComponent, ImageComponent, LIGHT_THEME, LinkComponent, PaginationComponent, ProgressBarComponent, RadioComponent, RateComponent, SHADOW_TOKENS, SPACING_TOKENS, STYLES_PATH, SelectComponent, SpinnerComponent, StackComponent, SwitchComponent, TYPOGRAPHY_TOKENS, TabComponent, TagComponent, TextFieldComponent, TextareaComponent, ThemeLoader, ToastComponent, TooltipComponent, TypographyComponent };
4651
4908
  //# sourceMappingURL=lesterarte-sefin-ui.mjs.map