@kksdev/ds-angular 1.5.0 → 1.6.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.
@@ -6,7 +6,7 @@ import * as i1$1 from '@fortawesome/angular-fontawesome';
6
6
  import { FaIconComponent, FontAwesomeModule } from '@fortawesome/angular-fontawesome';
7
7
  import * as i1$4 from '@angular/forms';
8
8
  import { FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';
9
- import { faInfoCircle, faTimesCircle, faExclamationTriangle, faCheckCircle, faTimes, faEye, faEyeSlash, faClose, faCircleInfo, faCircleXmark, faCircleExclamation, faCircleCheck, faChevronDown, faChevronLeft, faChevronRight, faAnglesLeft, faAnglesRight, faCheck, faSearch, faXmark, faSpinner, faCalendar, faCloudArrowUp, faFile, faFileImage, faFilePdf, faFileWord, faFileExcel, faInbox, faStar, faStarHalfStroke, faClock, faChevronUp, faFolder, faFolderOpen, faCircle, faCircleHalfStroke, faTriangleExclamation } from '@fortawesome/free-solid-svg-icons';
9
+ import { faInfoCircle, faTimesCircle, faExclamationTriangle, faCheckCircle, faTimes, faEye, faEyeSlash, faClose, faCircleInfo, faCircleXmark, faCircleExclamation, faCircleCheck, faChevronDown, faChevronLeft, faChevronRight, faAnglesLeft, faAnglesRight, faCheck, faSearch, faXmark, faSpinner, faCalendar, faCloudArrowUp, faFile, faFileImage, faFilePdf, faFileWord, faFileExcel, faInbox, faStar, faStarHalfStroke, faClock, faChevronUp, faFolder, faFolderOpen, faCircle, faCircleHalfStroke, faTriangleExclamation, faMinus, faPlus, faEyeDropper } from '@fortawesome/free-solid-svg-icons';
10
10
  import * as i1$2 from '@angular/router';
11
11
  import { RouterModule } from '@angular/router';
12
12
  import * as i1$3 from '@angular/cdk/overlay';
@@ -11431,6 +11431,1470 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
11431
11431
  }, template: "<div class=\"ds-calendar__container\">\n <!-- Header avec navigation et s\u00E9lecteur mode -->\n <div class=\"ds-calendar__header\">\n <div class=\"ds-calendar__nav\">\n @if (currentMode() === 'month') {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"previousMonth()\"\n aria-label=\"Mois pr\u00E9c\u00E9dent\"\n >\n <fa-icon [icon]=\"icons.chevronLeft\"></fa-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"previousYear()\"\n aria-label=\"Ann\u00E9e pr\u00E9c\u00E9dente\"\n >\n <fa-icon [icon]=\"icons.chevronLeft\"></fa-icon>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"ds-calendar__title\"\n (click)=\"toggleMode()\"\n [attr.aria-label]=\"currentMode() === 'month' ? 'Voir l\\'ann\u00E9e' : 'Voir le mois'\"\n >\n {{ calendarTitle() }}\n </button>\n\n @if (currentMode() === 'month') {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"nextMonth()\"\n aria-label=\"Mois suivant\"\n >\n <fa-icon [icon]=\"icons.chevronRight\"></fa-icon>\n </button>\n } @else {\n <button\n type=\"button\"\n class=\"ds-calendar__nav-btn\"\n (click)=\"nextYear()\"\n aria-label=\"Ann\u00E9e suivante\"\n >\n <fa-icon [icon]=\"icons.chevronRight\"></fa-icon>\n </button>\n }\n </div>\n\n <div class=\"ds-calendar__mode-selector\">\n <button\n type=\"button\"\n class=\"ds-calendar__mode-btn\"\n [class.ds-calendar__mode-btn--active]=\"currentMode() === 'month'\"\n (click)=\"currentMode() === 'year' && toggleMode()\"\n >\n Mois\n </button>\n <button\n type=\"button\"\n class=\"ds-calendar__mode-btn\"\n [class.ds-calendar__mode-btn--active]=\"currentMode() === 'year'\"\n (click)=\"currentMode() === 'month' && toggleMode()\"\n >\n Ann\u00E9e\n </button>\n </div>\n </div>\n\n <!-- Vue mois -->\n @if (currentMode() === 'month') {\n <div class=\"ds-calendar__month-view\">\n <!-- Noms des jours de la semaine -->\n <div class=\"ds-calendar__weekdays\">\n @for (day of weekDays(); track day) {\n <div class=\"ds-calendar__weekday\">{{ day }}</div>\n }\n </div>\n\n <!-- Grille des jours -->\n <div class=\"ds-calendar__grid\">\n @for (day of calendarGrid(); track day.date.getTime()) {\n <button\n type=\"button\"\n [class]=\"getDayClasses(day)\"\n [disabled]=\"day.isDisabled\"\n (click)=\"selectDate(day)\"\n [attr.aria-label]=\"day.date.toLocaleDateString(locale())\"\n [attr.aria-current]=\"day.isToday ? 'date' : null\"\n >\n <span class=\"ds-calendar__day-number\">{{ day.date.getDate() }}</span>\n\n @if (day.events.length > 0) {\n <div class=\"ds-calendar__events\">\n @for (event of day.events; track event.id) {\n <div\n [class]=\"getEventClasses(event)\"\n [title]=\"event.title\"\n (click)=\"onEventClick(event, $event)\"\n role=\"button\"\n [attr.aria-label]=\"event.title\"\n >\n <span class=\"ds-calendar__event-dot\"></span>\n @if (size() === 'lg') {\n <span class=\"ds-calendar__event-title\">{{ event.title }}</span>\n }\n </div>\n }\n </div>\n }\n </button>\n }\n </div>\n </div>\n }\n\n <!-- Vue ann\u00E9e -->\n @if (currentMode() === 'year') {\n <div class=\"ds-calendar__year-view\">\n <div class=\"ds-calendar__months-grid\">\n @for (month of monthGrid(); track month.monthIndex) {\n <button\n type=\"button\"\n [class]=\"getMonthClasses(month)\"\n (click)=\"selectMonth(month)\"\n [attr.aria-label]=\"month.label\"\n [attr.aria-current]=\"month.isCurrentMonth ? 'true' : null\"\n >\n {{ month.label }}\n </button>\n }\n </div>\n </div>\n }\n</div>\n", styles: [".ds-calendar{display:block;width:100%}.ds-calendar__container{background:var(--calendar-bg, var(--white));border:1px solid var(--calendar-border, var(--gray-200));border-radius:var(--calendar-radius, var(--radius-2));overflow:hidden}.ds-calendar__header{display:flex;align-items:center;justify-content:space-between;padding:var(--calendar-header-padding, var(--space-4));border-bottom:1px solid var(--calendar-border, var(--gray-200));background:var(--calendar-header-bg, var(--gray-50))}.ds-calendar__nav{display:flex;align-items:center;gap:var(--calendar-nav-gap, var(--space-2))}.ds-calendar__nav-btn{display:inline-flex;align-items:center;justify-content:center;width:var(--calendar-nav-btn-size, 32px);height:var(--calendar-nav-btn-size, 32px);padding:0;background:transparent;border:1px solid var(--calendar-nav-btn-border, var(--gray-300));border-radius:var(--calendar-nav-btn-radius, var(--radius-1));color:var(--calendar-nav-btn-color, var(--gray-700));font-size:var(--calendar-nav-btn-font-size, var(--font-size-3));cursor:pointer;transition:all .2s ease}.ds-calendar__nav-btn:hover:not(:disabled){background:var(--calendar-nav-btn-hover-bg, var(--gray-100));border-color:var(--calendar-nav-btn-hover-border, var(--gray-400));color:var(--calendar-nav-btn-hover-color, var(--gray-900))}.ds-calendar__nav-btn:active:not(:disabled){transform:scale(.95)}.ds-calendar__nav-btn:disabled{opacity:.5;cursor:not-allowed}.ds-calendar__title{padding:var(--calendar-title-padding, var(--space-2) var(--space-3));background:transparent;border:1px solid transparent;border-radius:var(--calendar-title-radius, var(--radius-1));color:var(--calendar-title-color, var(--gray-900));font-size:var(--calendar-title-font-size, var(--font-size-4));font-weight:var(--calendar-title-font-weight, 600);cursor:pointer;transition:all .2s ease}.ds-calendar__title:hover{background:var(--calendar-title-hover-bg, var(--gray-100));border-color:var(--calendar-title-hover-border, var(--gray-300))}.ds-calendar__mode-selector{display:flex;gap:var(--calendar-mode-gap, var(--space-1));background:var(--calendar-mode-bg, var(--white));border:1px solid var(--calendar-mode-border, var(--gray-300));border-radius:var(--calendar-mode-radius, var(--radius-1));padding:var(--calendar-mode-padding, 2px)}.ds-calendar__mode-btn{padding:var(--calendar-mode-btn-padding, var(--space-1) var(--space-3));background:transparent;border:none;border-radius:var(--calendar-mode-btn-radius, var(--radius-1));color:var(--calendar-mode-btn-color, var(--gray-700));font-size:var(--calendar-mode-btn-font-size, var(--font-size-2));cursor:pointer;transition:all .2s ease}.ds-calendar__mode-btn:hover{color:var(--calendar-mode-btn-hover-color, var(--gray-900))}.ds-calendar__mode-btn--active{background:var(--calendar-mode-btn-active-bg, var(--color-primary));color:var(--calendar-mode-btn-active-color, var(--white))}.ds-calendar__month-view{padding:var(--calendar-month-view-padding, var(--space-4))}.ds-calendar__weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--calendar-weekday-gap, var(--space-1));margin-bottom:var(--calendar-weekday-margin, var(--space-2))}.ds-calendar__weekday{text-align:center;color:var(--calendar-weekday-color, var(--gray-600));font-size:var(--calendar-weekday-font-size, var(--font-size-2));font-weight:var(--calendar-weekday-font-weight, 600);text-transform:uppercase;padding:var(--calendar-weekday-padding, var(--space-2) 0)}.ds-calendar__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--calendar-grid-gap, var(--space-1))}.ds-calendar__day{position:relative;aspect-ratio:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-start;padding:var(--calendar-day-padding, var(--space-2));background:var(--calendar-day-bg, transparent);border:1px solid var(--calendar-day-border, transparent);border-radius:var(--calendar-day-radius, var(--radius-1));color:var(--calendar-day-color, var(--gray-900));font-size:var(--calendar-day-font-size, var(--font-size-3));cursor:pointer;transition:all .2s ease}.ds-calendar__day:hover:not(:disabled){background:var(--calendar-day-hover-bg, var(--gray-100));border-color:var(--calendar-day-hover-border, var(--gray-300))}.ds-calendar__day--other-month{color:var(--calendar-day-other-month-color, var(--gray-400))}.ds-calendar__day--today{background:var(--calendar-day-today-bg, var(--blue-50));border-color:var(--calendar-day-today-border, var(--color-primary));color:var(--calendar-day-today-color, var(--color-primary));font-weight:600}.ds-calendar__day--disabled{opacity:.4;cursor:not-allowed;background:var(--calendar-day-disabled-bg, var(--gray-50))}.ds-calendar__day--has-events .ds-calendar__day-number{font-weight:600}.ds-calendar__day-number{line-height:1;margin-bottom:var(--calendar-day-number-margin, var(--space-1))}.ds-calendar__events{display:flex;flex-direction:column;gap:var(--calendar-events-gap, 2px);width:100%;margin-top:auto}.ds-calendar__event{display:flex;align-items:center;gap:var(--calendar-event-gap, var(--space-1));padding:var(--calendar-event-padding, 2px);border-radius:var(--calendar-event-radius, var(--radius-1));cursor:pointer;transition:all .2s ease}.ds-calendar__event:hover{transform:scale(1.05)}.ds-calendar__event-dot{width:var(--calendar-event-dot-size, 6px);height:var(--calendar-event-dot-size, 6px);border-radius:50%;background:var(--calendar-event-dot-color, var(--gray-500));flex-shrink:0}.ds-calendar__event-title{font-size:var(--calendar-event-title-font-size, var(--font-size-1));color:var(--calendar-event-title-color, var(--gray-700));white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ds-calendar__event--success .ds-calendar__event-dot{background:var(--calendar-event-success-color, var(--success))}.ds-calendar__event--warning .ds-calendar__event-dot{background:var(--calendar-event-warning-color, var(--warning))}.ds-calendar__event--error .ds-calendar__event-dot{background:var(--calendar-event-error-color, var(--error))}.ds-calendar__year-view{padding:var(--calendar-year-view-padding, var(--space-4))}.ds-calendar__months-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--calendar-months-gap, var(--space-3))}.ds-calendar__month{padding:var(--calendar-month-padding, var(--space-4));background:var(--calendar-month-bg, transparent);border:1px solid var(--calendar-month-border, var(--gray-200));border-radius:var(--calendar-month-radius, var(--radius-2));color:var(--calendar-month-color, var(--gray-900));font-size:var(--calendar-month-font-size, var(--font-size-3));font-weight:500;cursor:pointer;transition:all .2s ease;text-align:center}.ds-calendar__month:hover{background:var(--calendar-month-hover-bg, var(--gray-50));border-color:var(--calendar-month-hover-border, var(--gray-300))}.ds-calendar__month--current{background:var(--calendar-month-current-bg, var(--blue-50));border-color:var(--calendar-month-current-border, var(--color-primary));color:var(--calendar-month-current-color, var(--color-primary));font-weight:600}.ds-calendar--sm .ds-calendar__header{padding:var(--calendar-header-padding-sm, var(--space-2))}.ds-calendar--sm .ds-calendar__title{font-size:var(--calendar-title-font-size-sm, var(--font-size-3))}.ds-calendar--sm .ds-calendar__weekday{font-size:var(--calendar-weekday-font-size-sm, var(--font-size-1))}.ds-calendar--sm .ds-calendar__day{padding:var(--calendar-day-padding-sm, var(--space-1));font-size:var(--calendar-day-font-size-sm, var(--font-size-2))}.ds-calendar--sm .ds-calendar__month{padding:var(--calendar-month-padding-sm, var(--space-2));font-size:var(--calendar-month-font-size-sm, var(--font-size-2))}.ds-calendar--lg .ds-calendar__header{padding:var(--calendar-header-padding-lg, var(--space-6))}.ds-calendar--lg .ds-calendar__title{font-size:var(--calendar-title-font-size-lg, var(--font-size-5))}.ds-calendar--lg .ds-calendar__weekday{font-size:var(--calendar-weekday-font-size-lg, var(--font-size-3))}.ds-calendar--lg .ds-calendar__day{padding:var(--calendar-day-padding-lg, var(--space-3));font-size:var(--calendar-day-font-size-lg, var(--font-size-4))}.ds-calendar--lg .ds-calendar__month{padding:var(--calendar-month-padding-lg, var(--space-6));font-size:var(--calendar-month-font-size-lg, var(--font-size-4))}\n"] }]
11432
11432
  }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], events: [{ type: i0.Input, args: [{ isSignal: true, alias: "events", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }], firstDayOfWeek: [{ type: i0.Input, args: [{ isSignal: true, alias: "firstDayOfWeek", required: false }] }], disabledDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabledDate", required: false }] }], dateSelect: [{ type: i0.Output, args: ["dateSelect"] }], monthChange: [{ type: i0.Output, args: ["monthChange"] }], modeChange: [{ type: i0.Output, args: ["modeChange"] }], eventClick: [{ type: i0.Output, args: ["eventClick"] }] } });
11433
11433
 
11434
+ class DsInputNumber {
11435
+ // Config
11436
+ min = input(-Infinity, ...(ngDevMode ? [{ debugName: "min" }] : []));
11437
+ max = input(Infinity, ...(ngDevMode ? [{ debugName: "max" }] : []));
11438
+ step = input(1, ...(ngDevMode ? [{ debugName: "step" }] : []));
11439
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
11440
+ readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
11441
+ required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
11442
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
11443
+ placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
11444
+ prefix = input(undefined, ...(ngDevMode ? [{ debugName: "prefix" }] : []));
11445
+ suffix = input(undefined, ...(ngDevMode ? [{ debugName: "suffix" }] : []));
11446
+ precision = input(0, ...(ngDevMode ? [{ debugName: "precision" }] : []));
11447
+ controls = input(true, ...(ngDevMode ? [{ debugName: "controls" }] : []));
11448
+ controlsPosition = input('both', ...(ngDevMode ? [{ debugName: "controlsPosition" }] : []));
11449
+ // Accessibility
11450
+ ariaLabel = input(undefined, ...(ngDevMode ? [{ debugName: "ariaLabel" }] : []));
11451
+ id = input(crypto.randomUUID(), ...(ngDevMode ? [{ debugName: "id" }] : []));
11452
+ name = input(undefined, ...(ngDevMode ? [{ debugName: "name" }] : []));
11453
+ // Events
11454
+ valueChange = output();
11455
+ // ViewChild
11456
+ inputElement;
11457
+ // Icons
11458
+ faMinus = faMinus;
11459
+ faPlus = faPlus;
11460
+ // Internal state
11461
+ disabledState = signal(false, ...(ngDevMode ? [{ debugName: "disabledState" }] : []));
11462
+ internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
11463
+ focused = signal(false, ...(ngDevMode ? [{ debugName: "focused" }] : []));
11464
+ displayValue = signal('', ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
11465
+ constructor() {
11466
+ // Effect pour formater l'affichage
11467
+ effect(() => {
11468
+ const val = this.internalValue();
11469
+ if (val === null) {
11470
+ this.displayValue.set('');
11471
+ return;
11472
+ }
11473
+ const formatted = this.formatValue(val);
11474
+ this.displayValue.set(formatted);
11475
+ });
11476
+ }
11477
+ isDisabled = computed(() => this.disabled() || this.disabledState(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
11478
+ isReadonly = computed(() => this.readonly(), ...(ngDevMode ? [{ debugName: "isReadonly" }] : []));
11479
+ showControls = computed(() => this.controls() && !this.isDisabled() && !this.isReadonly(), ...(ngDevMode ? [{ debugName: "showControls" }] : []));
11480
+ controlsOnRight = computed(() => this.controlsPosition() === 'right', ...(ngDevMode ? [{ debugName: "controlsOnRight" }] : []));
11481
+ controlsOnBoth = computed(() => this.controlsPosition() === 'both', ...(ngDevMode ? [{ debugName: "controlsOnBoth" }] : []));
11482
+ containerClasses = computed(() => {
11483
+ const classes = ['ds-input-number'];
11484
+ classes.push(`ds-input-number--${this.size()}`);
11485
+ if (this.isDisabled())
11486
+ classes.push('ds-input-number--disabled');
11487
+ if (this.isReadonly())
11488
+ classes.push('ds-input-number--readonly');
11489
+ if (this.focused())
11490
+ classes.push('ds-input-number--focused');
11491
+ if (this.controlsOnRight())
11492
+ classes.push('ds-input-number--controls-right');
11493
+ if (this.controlsOnBoth())
11494
+ classes.push('ds-input-number--controls-both');
11495
+ if (this.prefix())
11496
+ classes.push('ds-input-number--has-prefix');
11497
+ if (this.suffix())
11498
+ classes.push('ds-input-number--has-suffix');
11499
+ return classes.join(' ');
11500
+ }, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
11501
+ canDecrement = computed(() => {
11502
+ if (!this.showControls())
11503
+ return false;
11504
+ const val = this.internalValue();
11505
+ if (val === null)
11506
+ return true;
11507
+ return val > this.min();
11508
+ }, ...(ngDevMode ? [{ debugName: "canDecrement" }] : []));
11509
+ canIncrement = computed(() => {
11510
+ if (!this.showControls())
11511
+ return false;
11512
+ const val = this.internalValue();
11513
+ if (val === null)
11514
+ return true;
11515
+ return val < this.max();
11516
+ }, ...(ngDevMode ? [{ debugName: "canIncrement" }] : []));
11517
+ // ControlValueAccessor
11518
+ onChange = () => { };
11519
+ onTouched = () => { };
11520
+ writeValue(value) {
11521
+ this.internalValue.set(value);
11522
+ }
11523
+ registerOnChange(fn) {
11524
+ this.onChange = fn;
11525
+ }
11526
+ registerOnTouched(fn) {
11527
+ this.onTouched = fn;
11528
+ }
11529
+ setDisabledState(isDisabled) {
11530
+ this.disabledState.set(isDisabled);
11531
+ }
11532
+ // Helpers
11533
+ formatValue(value) {
11534
+ const prec = this.precision();
11535
+ return prec > 0 ? value.toFixed(prec) : Math.floor(value).toString();
11536
+ }
11537
+ parseValue(input) {
11538
+ if (input === '' || input === '-')
11539
+ return null;
11540
+ const parsed = parseFloat(input);
11541
+ if (isNaN(parsed))
11542
+ return null;
11543
+ return parsed;
11544
+ }
11545
+ clampValue(value) {
11546
+ return Math.max(this.min(), Math.min(this.max(), value));
11547
+ }
11548
+ roundToPrecision(value) {
11549
+ const prec = this.precision();
11550
+ if (prec === 0)
11551
+ return Math.round(value);
11552
+ const multiplier = Math.pow(10, prec);
11553
+ return Math.round(value * multiplier) / multiplier;
11554
+ }
11555
+ emitValue(value) {
11556
+ this.onChange(value);
11557
+ if (value !== null) {
11558
+ this.valueChange.emit(value);
11559
+ }
11560
+ }
11561
+ // Event handlers
11562
+ onInputChange(event) {
11563
+ if (this.isDisabled() || this.isReadonly())
11564
+ return;
11565
+ const target = event.target;
11566
+ const parsed = this.parseValue(target.value);
11567
+ if (parsed === null) {
11568
+ this.internalValue.set(null);
11569
+ this.emitValue(null);
11570
+ return;
11571
+ }
11572
+ const clamped = this.clampValue(parsed);
11573
+ const rounded = this.roundToPrecision(clamped);
11574
+ this.internalValue.set(rounded);
11575
+ this.emitValue(rounded);
11576
+ }
11577
+ onInputBlur() {
11578
+ this.focused.set(false);
11579
+ this.onTouched();
11580
+ // Formater la valeur au blur
11581
+ const val = this.internalValue();
11582
+ if (val !== null) {
11583
+ const clamped = this.clampValue(val);
11584
+ const rounded = this.roundToPrecision(clamped);
11585
+ if (rounded !== val) {
11586
+ this.internalValue.set(rounded);
11587
+ this.emitValue(rounded);
11588
+ }
11589
+ }
11590
+ }
11591
+ onInputFocus() {
11592
+ this.focused.set(true);
11593
+ }
11594
+ onKeyDown(event) {
11595
+ if (this.isDisabled() || this.isReadonly())
11596
+ return;
11597
+ const stepVal = this.step();
11598
+ let handled = false;
11599
+ switch (event.key) {
11600
+ case 'ArrowUp':
11601
+ this.increment();
11602
+ handled = true;
11603
+ break;
11604
+ case 'ArrowDown':
11605
+ this.decrement();
11606
+ handled = true;
11607
+ break;
11608
+ case 'Home':
11609
+ this.setToMin();
11610
+ handled = true;
11611
+ break;
11612
+ case 'End':
11613
+ this.setToMax();
11614
+ handled = true;
11615
+ break;
11616
+ case 'PageUp':
11617
+ this.incrementBy(stepVal * 10);
11618
+ handled = true;
11619
+ break;
11620
+ case 'PageDown':
11621
+ this.decrementBy(stepVal * 10);
11622
+ handled = true;
11623
+ break;
11624
+ }
11625
+ if (handled) {
11626
+ event.preventDefault();
11627
+ }
11628
+ }
11629
+ increment() {
11630
+ if (!this.canIncrement())
11631
+ return;
11632
+ this.incrementBy(this.step());
11633
+ }
11634
+ decrement() {
11635
+ if (!this.canDecrement())
11636
+ return;
11637
+ this.decrementBy(this.step());
11638
+ }
11639
+ incrementBy(delta) {
11640
+ const current = this.internalValue() ?? this.min();
11641
+ const newValue = this.clampValue(this.roundToPrecision(current + delta));
11642
+ this.internalValue.set(newValue);
11643
+ this.emitValue(newValue);
11644
+ this.inputElement?.nativeElement.focus();
11645
+ }
11646
+ decrementBy(delta) {
11647
+ const current = this.internalValue() ?? this.max();
11648
+ const newValue = this.clampValue(this.roundToPrecision(current - delta));
11649
+ this.internalValue.set(newValue);
11650
+ this.emitValue(newValue);
11651
+ this.inputElement?.nativeElement.focus();
11652
+ }
11653
+ setToMin() {
11654
+ const newValue = this.min();
11655
+ this.internalValue.set(newValue);
11656
+ this.emitValue(newValue);
11657
+ }
11658
+ setToMax() {
11659
+ const newValue = this.max();
11660
+ this.internalValue.set(newValue);
11661
+ this.emitValue(newValue);
11662
+ }
11663
+ // ARIA helpers
11664
+ ariaValueMin = computed(() => this.min(), ...(ngDevMode ? [{ debugName: "ariaValueMin" }] : []));
11665
+ ariaValueMax = computed(() => this.max(), ...(ngDevMode ? [{ debugName: "ariaValueMax" }] : []));
11666
+ ariaValueNow = computed(() => this.internalValue() ?? undefined, ...(ngDevMode ? [{ debugName: "ariaValueNow" }] : []));
11667
+ ariaValueText = computed(() => {
11668
+ const val = this.internalValue();
11669
+ if (val === null)
11670
+ return undefined;
11671
+ const prefixStr = this.prefix() ?? '';
11672
+ const suffixStr = this.suffix() ?? '';
11673
+ return `${prefixStr}${this.formatValue(val)}${suffixStr}`;
11674
+ }, ...(ngDevMode ? [{ debugName: "ariaValueText" }] : []));
11675
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsInputNumber, deps: [], target: i0.ɵɵFactoryTarget.Component });
11676
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsInputNumber, isStandalone: true, selector: "ds-input-number", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, precision: { classPropertyName: "precision", publicName: "precision", isSignal: true, isRequired: false, transformFunction: null }, controls: { classPropertyName: "controls", publicName: "controls", isSignal: true, isRequired: false, transformFunction: null }, controlsPosition: { classPropertyName: "controlsPosition", publicName: "controlsPosition", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "valueChange" }, providers: [
11677
+ {
11678
+ provide: NG_VALUE_ACCESSOR,
11679
+ useExisting: forwardRef(() => DsInputNumber),
11680
+ multi: true,
11681
+ },
11682
+ ], viewQueries: [{ propertyName: "inputElement", first: true, predicate: ["inputElement"], descendants: true }], ngImport: i0, template: "<div [class]=\"containerClasses()\">\n <!-- Bouton d\u00E9cr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n }\n\n <!-- Wrapper pour input + prefix/suffix -->\n <div class=\"ds-input-number__input-wrapper\">\n @if (prefix()) {\n <span class=\"ds-input-number__prefix\">{{ prefix() }}</span>\n }\n\n <input\n #inputElement\n type=\"text\"\n class=\"ds-input-number__input\"\n [id]=\"id()\"\n [name]=\"name()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"isReadonly()\"\n [required]=\"required()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-valuemin]=\"ariaValueMin()\"\n [attr.aria-valuemax]=\"ariaValueMax()\"\n [attr.aria-valuenow]=\"ariaValueNow()\"\n [attr.aria-valuetext]=\"ariaValueText()\"\n role=\"spinbutton\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (focus)=\"onInputFocus()\"\n (keydown)=\"onKeyDown($event)\"\n />\n\n @if (suffix()) {\n <span class=\"ds-input-number__suffix\">{{ suffix() }}</span>\n }\n </div>\n\n <!-- Boutons position right -->\n @if (showControls() && controlsOnRight()) {\n <div class=\"ds-input-number__controls-right\">\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment-right\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement-right\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n </div>\n }\n\n <!-- Bouton incr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n }\n</div>\n", styles: [".ds-input-number{display:inline-flex;align-items:stretch;position:relative;vertical-align:middle;width:100%;max-width:200px}.ds-input-number__input-wrapper{display:flex;align-items:center;flex:1;position:relative;background-color:var(--input-bg, var(--gray-50));border:1px solid var(--input-border-color, var(--gray-300));border-radius:var(--input-border-radius, var(--radius-2));transition:all .2s ease;overflow:hidden}.ds-input-number--focused .ds-input-number__input-wrapper{border-color:var(--input-focus-border, var(--color-primary));box-shadow:0 0 0 3px var(--input-focus-ring, rgba(37, 99, 235, .1))}.ds-input-number--disabled .ds-input-number__input-wrapper{background-color:var(--input-bg-disabled, var(--gray-100));border-color:var(--input-border-disabled, var(--gray-200));cursor:not-allowed}.ds-input-number--readonly .ds-input-number__input-wrapper{background-color:var(--input-bg-readonly, var(--gray-50));border-color:var(--input-border-color, var(--gray-300))}.ds-input-number__input{flex:1;border:none;outline:none;background:transparent;color:var(--input-text-color, var(--gray-900));font-family:inherit;text-align:center;padding:0 var(--space-2, .5rem)}.ds-input-number__input::placeholder{color:var(--input-placeholder, var(--gray-500))}.ds-input-number__input:disabled{cursor:not-allowed;color:var(--input-text-disabled, var(--gray-500))}.ds-input-number--readonly .ds-input-number__input{cursor:default}.ds-input-number__input::-webkit-outer-spin-button,.ds-input-number__input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-input-number__input[type=number]{-moz-appearance:textfield}.ds-input-number__prefix,.ds-input-number__suffix{display:inline-flex;align-items:center;color:var(--input-placeholder, var(--gray-500));font-size:inherit;padding:0 var(--space-2, .5rem);-webkit-user-select:none;user-select:none}.ds-input-number__prefix{padding-right:0}.ds-input-number__suffix{padding-left:0}.ds-input-number__btn{display:inline-flex;align-items:center;justify-content:center;border:none;outline:none;cursor:pointer;background-color:var(--input-number-btn-bg, var(--gray-100));color:var(--input-text-color, var(--gray-900));transition:all .15s ease;-webkit-user-select:none;user-select:none}.ds-input-number__btn:hover:not(:disabled){background-color:var(--input-number-btn-hover, var(--gray-200))}.ds-input-number__btn:active:not(:disabled){background-color:var(--input-number-btn-active, var(--gray-300))}.ds-input-number__btn:disabled{cursor:not-allowed;background-color:var(--input-number-btn-disabled, var(--gray-50));color:var(--input-text-disabled, var(--gray-400))}.ds-input-number__btn fa-icon{font-size:.875em}.ds-input-number--controls-both .ds-input-number__btn--decrement{border-right:1px solid var(--input-border-color, var(--gray-300));border-top-left-radius:var(--input-border-radius, var(--radius-2));border-bottom-left-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__btn--increment{border-left:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2));border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__input-wrapper{border-radius:0}.ds-input-number--controls-right .ds-input-number__controls-right{display:flex;flex-direction:column;border-left:1px solid var(--input-border-color, var(--gray-300))}.ds-input-number--controls-right .ds-input-number__btn--increment-right,.ds-input-number--controls-right .ds-input-number__btn--decrement-right{flex:1;width:var(--input-number-btn-size-md, 24px)}.ds-input-number--controls-right .ds-input-number__btn--increment-right{border-bottom:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__btn--decrement-right{border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__input-wrapper{border-top-right-radius:0;border-bottom-right-radius:0}.ds-input-number--sm{font-size:var(--font-size-sm, .875rem)}.ds-input-number--sm .ds-input-number__input-wrapper{height:var(--input-number-height-sm, 32px)}.ds-input-number--sm .ds-input-number__btn{width:var(--input-number-btn-size-sm, 28px);height:var(--input-number-btn-size-sm, 28px)}.ds-input-number--sm.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-sm, 20px);height:calc(var(--input-number-height-sm, 32px) / 2)}.ds-input-number--md{font-size:var(--font-size-base, 1rem)}.ds-input-number--md .ds-input-number__input-wrapper{height:var(--input-number-height-md, 40px)}.ds-input-number--md .ds-input-number__btn{width:var(--input-number-btn-size-md, 36px);height:var(--input-number-btn-size-md, 36px)}.ds-input-number--md.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-md, 24px);height:calc(var(--input-number-height-md, 40px) / 2)}.ds-input-number--lg{font-size:var(--font-size-lg, 1.125rem)}.ds-input-number--lg .ds-input-number__input-wrapper{height:var(--input-number-height-lg, 48px)}.ds-input-number--lg .ds-input-number__btn{width:var(--input-number-btn-size-lg, 44px);height:var(--input-number-btn-size-lg, 44px)}.ds-input-number--lg.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-lg, 28px);height:calc(var(--input-number-height-lg, 48px) / 2)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
11683
+ }
11684
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsInputNumber, decorators: [{
11685
+ type: Component,
11686
+ args: [{ selector: 'ds-input-number', imports: [CommonModule, FaIconComponent], providers: [
11687
+ {
11688
+ provide: NG_VALUE_ACCESSOR,
11689
+ useExisting: forwardRef(() => DsInputNumber),
11690
+ multi: true,
11691
+ },
11692
+ ], template: "<div [class]=\"containerClasses()\">\n <!-- Bouton d\u00E9cr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n }\n\n <!-- Wrapper pour input + prefix/suffix -->\n <div class=\"ds-input-number__input-wrapper\">\n @if (prefix()) {\n <span class=\"ds-input-number__prefix\">{{ prefix() }}</span>\n }\n\n <input\n #inputElement\n type=\"text\"\n class=\"ds-input-number__input\"\n [id]=\"id()\"\n [name]=\"name()\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"isReadonly()\"\n [required]=\"required()\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-valuemin]=\"ariaValueMin()\"\n [attr.aria-valuemax]=\"ariaValueMax()\"\n [attr.aria-valuenow]=\"ariaValueNow()\"\n [attr.aria-valuetext]=\"ariaValueText()\"\n role=\"spinbutton\"\n (input)=\"onInputChange($event)\"\n (blur)=\"onInputBlur()\"\n (focus)=\"onInputFocus()\"\n (keydown)=\"onKeyDown($event)\"\n />\n\n @if (suffix()) {\n <span class=\"ds-input-number__suffix\">{{ suffix() }}</span>\n }\n </div>\n\n <!-- Boutons position right -->\n @if (showControls() && controlsOnRight()) {\n <div class=\"ds-input-number__controls-right\">\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment-right\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--decrement-right\"\n [disabled]=\"!canDecrement()\"\n (click)=\"decrement()\"\n [attr.aria-label]=\"'Decrement value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faMinus\" />\n </button>\n </div>\n }\n\n <!-- Bouton incr\u00E9mentation (position both) -->\n @if (showControls() && controlsOnBoth()) {\n <button\n type=\"button\"\n class=\"ds-input-number__btn ds-input-number__btn--increment\"\n [disabled]=\"!canIncrement()\"\n (click)=\"increment()\"\n [attr.aria-label]=\"'Increment value'\"\n tabindex=\"-1\"\n >\n <fa-icon [icon]=\"faPlus\" />\n </button>\n }\n</div>\n", styles: [".ds-input-number{display:inline-flex;align-items:stretch;position:relative;vertical-align:middle;width:100%;max-width:200px}.ds-input-number__input-wrapper{display:flex;align-items:center;flex:1;position:relative;background-color:var(--input-bg, var(--gray-50));border:1px solid var(--input-border-color, var(--gray-300));border-radius:var(--input-border-radius, var(--radius-2));transition:all .2s ease;overflow:hidden}.ds-input-number--focused .ds-input-number__input-wrapper{border-color:var(--input-focus-border, var(--color-primary));box-shadow:0 0 0 3px var(--input-focus-ring, rgba(37, 99, 235, .1))}.ds-input-number--disabled .ds-input-number__input-wrapper{background-color:var(--input-bg-disabled, var(--gray-100));border-color:var(--input-border-disabled, var(--gray-200));cursor:not-allowed}.ds-input-number--readonly .ds-input-number__input-wrapper{background-color:var(--input-bg-readonly, var(--gray-50));border-color:var(--input-border-color, var(--gray-300))}.ds-input-number__input{flex:1;border:none;outline:none;background:transparent;color:var(--input-text-color, var(--gray-900));font-family:inherit;text-align:center;padding:0 var(--space-2, .5rem)}.ds-input-number__input::placeholder{color:var(--input-placeholder, var(--gray-500))}.ds-input-number__input:disabled{cursor:not-allowed;color:var(--input-text-disabled, var(--gray-500))}.ds-input-number--readonly .ds-input-number__input{cursor:default}.ds-input-number__input::-webkit-outer-spin-button,.ds-input-number__input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-input-number__input[type=number]{-moz-appearance:textfield}.ds-input-number__prefix,.ds-input-number__suffix{display:inline-flex;align-items:center;color:var(--input-placeholder, var(--gray-500));font-size:inherit;padding:0 var(--space-2, .5rem);-webkit-user-select:none;user-select:none}.ds-input-number__prefix{padding-right:0}.ds-input-number__suffix{padding-left:0}.ds-input-number__btn{display:inline-flex;align-items:center;justify-content:center;border:none;outline:none;cursor:pointer;background-color:var(--input-number-btn-bg, var(--gray-100));color:var(--input-text-color, var(--gray-900));transition:all .15s ease;-webkit-user-select:none;user-select:none}.ds-input-number__btn:hover:not(:disabled){background-color:var(--input-number-btn-hover, var(--gray-200))}.ds-input-number__btn:active:not(:disabled){background-color:var(--input-number-btn-active, var(--gray-300))}.ds-input-number__btn:disabled{cursor:not-allowed;background-color:var(--input-number-btn-disabled, var(--gray-50));color:var(--input-text-disabled, var(--gray-400))}.ds-input-number__btn fa-icon{font-size:.875em}.ds-input-number--controls-both .ds-input-number__btn--decrement{border-right:1px solid var(--input-border-color, var(--gray-300));border-top-left-radius:var(--input-border-radius, var(--radius-2));border-bottom-left-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__btn--increment{border-left:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2));border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-both .ds-input-number__input-wrapper{border-radius:0}.ds-input-number--controls-right .ds-input-number__controls-right{display:flex;flex-direction:column;border-left:1px solid var(--input-border-color, var(--gray-300))}.ds-input-number--controls-right .ds-input-number__btn--increment-right,.ds-input-number--controls-right .ds-input-number__btn--decrement-right{flex:1;width:var(--input-number-btn-size-md, 24px)}.ds-input-number--controls-right .ds-input-number__btn--increment-right{border-bottom:1px solid var(--input-border-color, var(--gray-300));border-top-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__btn--decrement-right{border-bottom-right-radius:var(--input-border-radius, var(--radius-2))}.ds-input-number--controls-right .ds-input-number__input-wrapper{border-top-right-radius:0;border-bottom-right-radius:0}.ds-input-number--sm{font-size:var(--font-size-sm, .875rem)}.ds-input-number--sm .ds-input-number__input-wrapper{height:var(--input-number-height-sm, 32px)}.ds-input-number--sm .ds-input-number__btn{width:var(--input-number-btn-size-sm, 28px);height:var(--input-number-btn-size-sm, 28px)}.ds-input-number--sm.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-sm, 20px);height:calc(var(--input-number-height-sm, 32px) / 2)}.ds-input-number--md{font-size:var(--font-size-base, 1rem)}.ds-input-number--md .ds-input-number__input-wrapper{height:var(--input-number-height-md, 40px)}.ds-input-number--md .ds-input-number__btn{width:var(--input-number-btn-size-md, 36px);height:var(--input-number-btn-size-md, 36px)}.ds-input-number--md.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-md, 24px);height:calc(var(--input-number-height-md, 40px) / 2)}.ds-input-number--lg{font-size:var(--font-size-lg, 1.125rem)}.ds-input-number--lg .ds-input-number__input-wrapper{height:var(--input-number-height-lg, 48px)}.ds-input-number--lg .ds-input-number__btn{width:var(--input-number-btn-size-lg, 44px);height:var(--input-number-btn-size-lg, 44px)}.ds-input-number--lg.ds-input-number--controls-right .ds-input-number__btn{width:var(--input-number-btn-size-lg, 28px);height:calc(var(--input-number-height-lg, 48px) / 2)}\n"] }]
11693
+ }], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], precision: [{ type: i0.Input, args: [{ isSignal: true, alias: "precision", required: false }] }], controls: [{ type: i0.Input, args: [{ isSignal: true, alias: "controls", required: false }] }], controlsPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "controlsPosition", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], valueChange: [{ type: i0.Output, args: ["valueChange"] }], inputElement: [{
11694
+ type: ViewChild,
11695
+ args: ['inputElement', { static: false }]
11696
+ }] } });
11697
+
11698
+ /**
11699
+ * DS Segmented Control
11700
+ *
11701
+ * Composant groupe de boutons mutuellement exclusifs visuellement connectés.
11702
+ * Alternative stylisée aux boutons radio pour basculer entre vues, modes ou options.
11703
+ *
11704
+ * @example
11705
+ * // Formulaire réactif
11706
+ * <ds-segmented-control
11707
+ * formControlName="view"
11708
+ * [options]="viewOptions"
11709
+ * size="md"
11710
+ * fullWidth
11711
+ * />
11712
+ *
11713
+ * @example
11714
+ * // Template-driven
11715
+ * <ds-segmented-control
11716
+ * [(ngModel)]="selectedView"
11717
+ * [options]="[
11718
+ * { value: 'list', label: 'Liste', icon: 'fas-list' },
11719
+ * { value: 'grid', label: 'Grille', icon: 'fas-grid' },
11720
+ * { value: 'map', label: 'Carte', icon: 'fas-map' }
11721
+ * ]"
11722
+ * color="neutral"
11723
+ * />
11724
+ */
11725
+ class DsSegmentedControl {
11726
+ /**
11727
+ * Liste des options du segmented control
11728
+ */
11729
+ options = input.required(...(ngDevMode ? [{ debugName: "options" }] : []));
11730
+ /**
11731
+ * Taille du segmented control (sm, md, lg)
11732
+ */
11733
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
11734
+ /**
11735
+ * État désactivé global
11736
+ */
11737
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
11738
+ /**
11739
+ * Prend toute la largeur du conteneur
11740
+ */
11741
+ fullWidth = input(false, ...(ngDevMode ? [{ debugName: "fullWidth" }] : []));
11742
+ /**
11743
+ * Orientation (horizontal, vertical)
11744
+ */
11745
+ orientation = input('horizontal', ...(ngDevMode ? [{ debugName: "orientation" }] : []));
11746
+ /**
11747
+ * Couleur du segment actif (primary, neutral)
11748
+ */
11749
+ color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : []));
11750
+ // Internal state
11751
+ disabledState = signal(false, ...(ngDevMode ? [{ debugName: "disabledState" }] : []));
11752
+ internalValue = signal(null, ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
11753
+ // Computed properties
11754
+ isDisabled = computed(() => this.disabled() || this.disabledState(), ...(ngDevMode ? [{ debugName: "isDisabled" }] : []));
11755
+ containerClasses = computed(() => ({
11756
+ 'ds-segmented-control': true,
11757
+ [`ds-segmented-control--${this.size()}`]: true,
11758
+ [`ds-segmented-control--${this.orientation()}`]: true,
11759
+ [`ds-segmented-control--${this.color()}`]: true,
11760
+ 'ds-segmented-control--full-width': this.fullWidth(),
11761
+ 'ds-segmented-control--disabled': this.isDisabled(),
11762
+ }), ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
11763
+ activeIndex = computed(() => {
11764
+ const value = this.internalValue();
11765
+ if (!value)
11766
+ return -1;
11767
+ return this.options().findIndex((opt) => opt.value === value);
11768
+ }, ...(ngDevMode ? [{ debugName: "activeIndex" }] : []));
11769
+ /**
11770
+ * Vérifie si une option est sélectionnée
11771
+ */
11772
+ isOptionSelected(option) {
11773
+ return this.internalValue() === option.value;
11774
+ }
11775
+ /**
11776
+ * Vérifie si une option est désactivée
11777
+ */
11778
+ isOptionDisabled(option) {
11779
+ return this.isDisabled() || !!option.disabled;
11780
+ }
11781
+ /**
11782
+ * Classes CSS pour un segment
11783
+ */
11784
+ getSegmentClasses(option) {
11785
+ return {
11786
+ 'ds-segmented-control__segment': true,
11787
+ 'ds-segmented-control__segment--active': this.isOptionSelected(option),
11788
+ 'ds-segmented-control__segment--disabled': this.isOptionDisabled(option),
11789
+ };
11790
+ }
11791
+ // ControlValueAccessor implementation
11792
+ onChange = () => { };
11793
+ onTouched = () => { };
11794
+ writeValue(value) {
11795
+ this.internalValue.set(value);
11796
+ }
11797
+ registerOnChange(fn) {
11798
+ this.onChange = fn;
11799
+ }
11800
+ registerOnTouched(fn) {
11801
+ this.onTouched = fn;
11802
+ }
11803
+ setDisabledState(isDisabled) {
11804
+ this.disabledState.set(isDisabled);
11805
+ }
11806
+ // Event handlers
11807
+ onSegmentClick(option) {
11808
+ if (this.isOptionDisabled(option)) {
11809
+ return;
11810
+ }
11811
+ this.internalValue.set(option.value);
11812
+ this.onChange(option.value);
11813
+ this.onTouched();
11814
+ }
11815
+ onKeydown(event) {
11816
+ const target = event.target;
11817
+ if (target.getAttribute('role') !== 'radio')
11818
+ return;
11819
+ const currentIndex = this.activeIndex();
11820
+ const optionsArray = this.options();
11821
+ const isHorizontal = this.orientation() === 'horizontal';
11822
+ let nextIndex = currentIndex;
11823
+ switch (event.key) {
11824
+ case 'ArrowLeft':
11825
+ if (!isHorizontal)
11826
+ return;
11827
+ event.preventDefault();
11828
+ nextIndex = this.findPreviousEnabledOption(currentIndex);
11829
+ break;
11830
+ case 'ArrowRight':
11831
+ if (!isHorizontal)
11832
+ return;
11833
+ event.preventDefault();
11834
+ nextIndex = this.findNextEnabledOption(currentIndex);
11835
+ break;
11836
+ case 'ArrowUp':
11837
+ if (isHorizontal)
11838
+ return;
11839
+ event.preventDefault();
11840
+ nextIndex = this.findPreviousEnabledOption(currentIndex);
11841
+ break;
11842
+ case 'ArrowDown':
11843
+ if (isHorizontal)
11844
+ return;
11845
+ event.preventDefault();
11846
+ nextIndex = this.findNextEnabledOption(currentIndex);
11847
+ break;
11848
+ case 'Home':
11849
+ event.preventDefault();
11850
+ nextIndex = this.findNextEnabledOption(-1);
11851
+ break;
11852
+ case 'End':
11853
+ event.preventDefault();
11854
+ nextIndex = this.findPreviousEnabledOption(optionsArray.length);
11855
+ break;
11856
+ default:
11857
+ return;
11858
+ }
11859
+ if (nextIndex !== currentIndex && nextIndex !== -1) {
11860
+ this.onSegmentClick(optionsArray[nextIndex]);
11861
+ this.focusSegment(nextIndex);
11862
+ }
11863
+ }
11864
+ findNextEnabledOption(startIndex) {
11865
+ const optionsArray = this.options();
11866
+ for (let i = startIndex + 1; i < optionsArray.length; i++) {
11867
+ if (!optionsArray[i].disabled)
11868
+ return i;
11869
+ }
11870
+ return startIndex === -1 ? 0 : startIndex;
11871
+ }
11872
+ findPreviousEnabledOption(startIndex) {
11873
+ const optionsArray = this.options();
11874
+ for (let i = startIndex - 1; i >= 0; i--) {
11875
+ if (!optionsArray[i].disabled)
11876
+ return i;
11877
+ }
11878
+ return startIndex === optionsArray.length ? optionsArray.length - 1 : startIndex;
11879
+ }
11880
+ focusSegment(index) {
11881
+ setTimeout(() => {
11882
+ const segment = document.querySelector(`.ds-segmented-control__segment[data-index="${index}"]`);
11883
+ segment?.focus();
11884
+ }, 0);
11885
+ }
11886
+ // Track function for @for
11887
+ trackByValue(_index, option) {
11888
+ return option.value;
11889
+ }
11890
+ /**
11891
+ * Parse l'icône depuis le format string vers le format FontAwesome
11892
+ * @param iconName - Nom de l'icône (ex: 'fas-list', 'list', 'fa-solid fa-list')
11893
+ * @returns Tuple [prefix, iconName] pour FontAwesome
11894
+ */
11895
+ parseIcon(iconName) {
11896
+ // Format: 'fas-list' ou 'far-check'
11897
+ if (iconName.includes('-')) {
11898
+ const parts = iconName.split('-');
11899
+ if (parts[0] === 'fas' || parts[0] === 'far' || parts[0] === 'fab') {
11900
+ return [parts[0], parts.slice(1).join('-')];
11901
+ }
11902
+ }
11903
+ // Par défaut, utiliser 'fas' comme préfixe
11904
+ return ['fas', iconName];
11905
+ }
11906
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsSegmentedControl, deps: [], target: i0.ɵɵFactoryTarget.Component });
11907
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsSegmentedControl, isStandalone: true, selector: "ds-segmented-control", inputs: { options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, fullWidth: { classPropertyName: "fullWidth", publicName: "fullWidth", isSignal: true, isRequired: false, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "keydown": "onKeydown($event)" } }, providers: [
11908
+ {
11909
+ provide: NG_VALUE_ACCESSOR,
11910
+ useExisting: forwardRef(() => DsSegmentedControl),
11911
+ multi: true,
11912
+ },
11913
+ ], ngImport: i0, template: "<div\n [ngClass]=\"containerClasses()\"\n role=\"radiogroup\"\n [attr.aria-disabled]=\"isDisabled()\"\n>\n @for (option of options(); track trackByValue($index, option)) {\n <button\n type=\"button\"\n role=\"radio\"\n [ngClass]=\"getSegmentClasses(option)\"\n [attr.data-index]=\"$index\"\n [attr.aria-checked]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"isOptionDisabled(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n [tabindex]=\"isOptionSelected(option) ? 0 : -1\"\n (click)=\"onSegmentClick(option)\"\n >\n @if (option.icon) {\n <fa-icon\n class=\"ds-segmented-control__icon\"\n [icon]=\"parseIcon(option.icon)\"\n />\n }\n <span class=\"ds-segmented-control__label\">{{ option.label }}</span>\n </button>\n }\n</div>\n", styles: [".ds-segmented-control{display:inline-flex;background:var(--segmented-bg);border-radius:var(--segmented-border-radius);padding:var(--segmented-gap);gap:var(--segmented-gap);box-shadow:inset 0 0 0 1px var(--segmented-border-color)}.ds-segmented-control--horizontal{flex-direction:row}.ds-segmented-control--vertical{flex-direction:column}.ds-segmented-control--full-width{display:flex;width:100%}.ds-segmented-control--full-width .ds-segmented-control__segment{flex:1}.ds-segmented-control--disabled{opacity:.5;cursor:not-allowed}.ds-segmented-control--sm .ds-segmented-control__segment{height:var(--segmented-height-sm);padding:0 var(--segmented-padding-sm);font-size:var(--segmented-font-size-sm);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--sm .ds-segmented-control__icon{font-size:var(--segmented-icon-size-sm)}.ds-segmented-control--md .ds-segmented-control__segment{height:var(--segmented-height-md);padding:0 var(--segmented-padding-md);font-size:var(--segmented-font-size-md);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--md .ds-segmented-control__icon{font-size:var(--segmented-icon-size-md)}.ds-segmented-control--lg .ds-segmented-control__segment{height:var(--segmented-height-lg);padding:0 var(--segmented-padding-lg);font-size:var(--segmented-font-size-lg);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--lg .ds-segmented-control__icon{font-size:var(--segmented-icon-size-lg)}.ds-segmented-control__segment{display:inline-flex;align-items:center;justify-content:center;gap:var(--segmented-segment-gap);border:none;background:transparent;color:var(--segmented-text);font-weight:500;cursor:pointer;transition:all .2s ease;white-space:nowrap;-webkit-user-select:none;user-select:none}.ds-segmented-control__segment:hover:not(.ds-segmented-control__segment--disabled):not(.ds-segmented-control__segment--active){background:var(--segmented-hover-bg)}.ds-segmented-control__segment:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-segmented-control__segment--active{background:var(--segmented-active-bg);color:var(--segmented-active-text);box-shadow:var(--segmented-active-shadow);font-weight:600}.ds-segmented-control__segment--disabled{cursor:not-allowed;opacity:.4}.ds-segmented-control__icon{display:inline-flex;flex-shrink:0}.ds-segmented-control__label{display:inline-flex}.ds-segmented-control--primary .ds-segmented-control__segment--active{background:var(--segmented-active-bg-primary);color:var(--segmented-active-text-primary)}.ds-segmented-control--neutral .ds-segmented-control__segment--active{background:var(--segmented-active-bg-neutral);color:var(--segmented-active-text-neutral)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }] });
11914
+ }
11915
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsSegmentedControl, decorators: [{
11916
+ type: Component,
11917
+ args: [{ selector: 'ds-segmented-control', standalone: true, imports: [CommonModule, FontAwesomeModule], providers: [
11918
+ {
11919
+ provide: NG_VALUE_ACCESSOR,
11920
+ useExisting: forwardRef(() => DsSegmentedControl),
11921
+ multi: true,
11922
+ },
11923
+ ], template: "<div\n [ngClass]=\"containerClasses()\"\n role=\"radiogroup\"\n [attr.aria-disabled]=\"isDisabled()\"\n>\n @for (option of options(); track trackByValue($index, option)) {\n <button\n type=\"button\"\n role=\"radio\"\n [ngClass]=\"getSegmentClasses(option)\"\n [attr.data-index]=\"$index\"\n [attr.aria-checked]=\"isOptionSelected(option)\"\n [attr.aria-disabled]=\"isOptionDisabled(option)\"\n [disabled]=\"isOptionDisabled(option)\"\n [tabindex]=\"isOptionSelected(option) ? 0 : -1\"\n (click)=\"onSegmentClick(option)\"\n >\n @if (option.icon) {\n <fa-icon\n class=\"ds-segmented-control__icon\"\n [icon]=\"parseIcon(option.icon)\"\n />\n }\n <span class=\"ds-segmented-control__label\">{{ option.label }}</span>\n </button>\n }\n</div>\n", styles: [".ds-segmented-control{display:inline-flex;background:var(--segmented-bg);border-radius:var(--segmented-border-radius);padding:var(--segmented-gap);gap:var(--segmented-gap);box-shadow:inset 0 0 0 1px var(--segmented-border-color)}.ds-segmented-control--horizontal{flex-direction:row}.ds-segmented-control--vertical{flex-direction:column}.ds-segmented-control--full-width{display:flex;width:100%}.ds-segmented-control--full-width .ds-segmented-control__segment{flex:1}.ds-segmented-control--disabled{opacity:.5;cursor:not-allowed}.ds-segmented-control--sm .ds-segmented-control__segment{height:var(--segmented-height-sm);padding:0 var(--segmented-padding-sm);font-size:var(--segmented-font-size-sm);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--sm .ds-segmented-control__icon{font-size:var(--segmented-icon-size-sm)}.ds-segmented-control--md .ds-segmented-control__segment{height:var(--segmented-height-md);padding:0 var(--segmented-padding-md);font-size:var(--segmented-font-size-md);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--md .ds-segmented-control__icon{font-size:var(--segmented-icon-size-md)}.ds-segmented-control--lg .ds-segmented-control__segment{height:var(--segmented-height-lg);padding:0 var(--segmented-padding-lg);font-size:var(--segmented-font-size-lg);border-radius:calc(var(--segmented-border-radius) - var(--segmented-gap))}.ds-segmented-control--lg .ds-segmented-control__icon{font-size:var(--segmented-icon-size-lg)}.ds-segmented-control__segment{display:inline-flex;align-items:center;justify-content:center;gap:var(--segmented-segment-gap);border:none;background:transparent;color:var(--segmented-text);font-weight:500;cursor:pointer;transition:all .2s ease;white-space:nowrap;-webkit-user-select:none;user-select:none}.ds-segmented-control__segment:hover:not(.ds-segmented-control__segment--disabled):not(.ds-segmented-control__segment--active){background:var(--segmented-hover-bg)}.ds-segmented-control__segment:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-segmented-control__segment--active{background:var(--segmented-active-bg);color:var(--segmented-active-text);box-shadow:var(--segmented-active-shadow);font-weight:600}.ds-segmented-control__segment--disabled{cursor:not-allowed;opacity:.4}.ds-segmented-control__icon{display:inline-flex;flex-shrink:0}.ds-segmented-control__label{display:inline-flex}.ds-segmented-control--primary .ds-segmented-control__segment--active{background:var(--segmented-active-bg-primary);color:var(--segmented-active-text-primary)}.ds-segmented-control--neutral .ds-segmented-control__segment--active{background:var(--segmented-active-bg-neutral);color:var(--segmented-active-text-neutral)}\n"] }]
11924
+ }], propDecorators: { options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], fullWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "fullWidth", required: false }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], onKeydown: [{
11925
+ type: HostListener,
11926
+ args: ['keydown', ['$event']]
11927
+ }] } });
11928
+
11929
+ class DsColorPickerPanelComponent {
11930
+ spectrumCanvas;
11931
+ // Config (set by parent)
11932
+ value = '';
11933
+ showAlpha = false;
11934
+ presetColors = [];
11935
+ recentColors = [];
11936
+ showRecentColors = false;
11937
+ format = 'hex';
11938
+ // Outputs
11939
+ colorSelected = output();
11940
+ closed = output();
11941
+ // Icons
11942
+ checkIcon = faCheck;
11943
+ // State
11944
+ hue = signal(0, ...(ngDevMode ? [{ debugName: "hue" }] : []));
11945
+ saturation = signal(100, ...(ngDevMode ? [{ debugName: "saturation" }] : []));
11946
+ lightness = signal(50, ...(ngDevMode ? [{ debugName: "lightness" }] : []));
11947
+ alpha = signal(1, ...(ngDevMode ? [{ debugName: "alpha" }] : []));
11948
+ cursorX = signal(null, ...(ngDevMode ? [{ debugName: "cursorX" }] : []));
11949
+ cursorY = signal(null, ...(ngDevMode ? [{ debugName: "cursorY" }] : []));
11950
+ isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
11951
+ // Computed
11952
+ rgb = computed(() => this.hslToRGB(this.hue(), this.saturation(), this.lightness()), ...(ngDevMode ? [{ debugName: "rgb" }] : []));
11953
+ hexValue = computed(() => {
11954
+ const rgb = this.rgb();
11955
+ const r = rgb.r.toString(16).padStart(2, '0');
11956
+ const g = rgb.g.toString(16).padStart(2, '0');
11957
+ const b = rgb.b.toString(16).padStart(2, '0');
11958
+ return `#${r}${g}${b}`;
11959
+ }, ...(ngDevMode ? [{ debugName: "hexValue" }] : []));
11960
+ currentColor = computed(() => {
11961
+ if (this.showAlpha && this.alpha() < 1) {
11962
+ const rgb = this.rgb();
11963
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${this.alpha()})`;
11964
+ }
11965
+ return this.hexValue();
11966
+ }, ...(ngDevMode ? [{ debugName: "currentColor" }] : []));
11967
+ constructor() {
11968
+ // Observer les changements de couleur
11969
+ effect(() => {
11970
+ const color = this.currentColor();
11971
+ if (color !== this.value) {
11972
+ this.colorSelected.emit(color);
11973
+ }
11974
+ });
11975
+ }
11976
+ ngAfterViewInit() {
11977
+ this.initializeFromValue();
11978
+ this.renderSpectrum();
11979
+ }
11980
+ initializeFromValue() {
11981
+ if (!this.value) {
11982
+ this.updateCursor();
11983
+ return;
11984
+ }
11985
+ const rgb = this.parseColor(this.value);
11986
+ if (rgb) {
11987
+ const hsl = this.rgbToHSL(rgb.r, rgb.g, rgb.b);
11988
+ this.hue.set(hsl.h);
11989
+ this.saturation.set(hsl.s);
11990
+ this.lightness.set(hsl.l);
11991
+ if (rgb.a !== undefined) {
11992
+ this.alpha.set(rgb.a);
11993
+ }
11994
+ this.updateCursor();
11995
+ }
11996
+ }
11997
+ renderSpectrum() {
11998
+ if (!this.spectrumCanvas)
11999
+ return;
12000
+ const canvas = this.spectrumCanvas.nativeElement;
12001
+ const ctx = canvas.getContext('2d');
12002
+ if (!ctx)
12003
+ return;
12004
+ const width = canvas.width;
12005
+ const height = canvas.height;
12006
+ // Gradient de saturation (horizontal)
12007
+ const satGradient = ctx.createLinearGradient(0, 0, width, 0);
12008
+ satGradient.addColorStop(0, 'white');
12009
+ satGradient.addColorStop(1, `hsl(${this.hue()}, 100%, 50%)`);
12010
+ ctx.fillStyle = satGradient;
12011
+ ctx.fillRect(0, 0, width, height);
12012
+ // Gradient de luminosité (vertical)
12013
+ const lightGradient = ctx.createLinearGradient(0, 0, 0, height);
12014
+ lightGradient.addColorStop(0, 'transparent');
12015
+ lightGradient.addColorStop(1, 'black');
12016
+ ctx.fillStyle = lightGradient;
12017
+ ctx.fillRect(0, 0, width, height);
12018
+ }
12019
+ updateCursor() {
12020
+ if (!this.spectrumCanvas)
12021
+ return;
12022
+ const canvas = this.spectrumCanvas.nativeElement;
12023
+ const x = (this.saturation() / 100) * canvas.width;
12024
+ const y = ((100 - this.lightness()) / 100) * canvas.height;
12025
+ this.cursorX.set(x);
12026
+ this.cursorY.set(y);
12027
+ }
12028
+ onHueChange(event) {
12029
+ const target = event.target;
12030
+ this.hue.set(parseInt(target.value, 10));
12031
+ this.renderSpectrum();
12032
+ }
12033
+ onAlphaChange(event) {
12034
+ const target = event.target;
12035
+ this.alpha.set(parseInt(target.value, 10) / 100);
12036
+ }
12037
+ onSpectrumMouseDown(event) {
12038
+ this.isDragging.set(true);
12039
+ this.updateColorFromSpectrum(event);
12040
+ }
12041
+ onSpectrumMouseMove(event) {
12042
+ if (this.isDragging()) {
12043
+ this.updateColorFromSpectrum(event);
12044
+ }
12045
+ }
12046
+ onSpectrumMouseUp() {
12047
+ this.isDragging.set(false);
12048
+ }
12049
+ updateColorFromSpectrum(event) {
12050
+ if (!this.spectrumCanvas)
12051
+ return;
12052
+ const canvas = this.spectrumCanvas.nativeElement;
12053
+ const rect = canvas.getBoundingClientRect();
12054
+ const x = Math.max(0, Math.min(event.clientX - rect.left, canvas.width));
12055
+ const y = Math.max(0, Math.min(event.clientY - rect.top, canvas.height));
12056
+ const saturation = (x / canvas.width) * 100;
12057
+ const lightness = 100 - (y / canvas.height) * 100;
12058
+ this.saturation.set(Math.round(saturation));
12059
+ this.lightness.set(Math.round(lightness));
12060
+ this.cursorX.set(x);
12061
+ this.cursorY.set(y);
12062
+ }
12063
+ onHexInput(event) {
12064
+ const target = event.target;
12065
+ const hex = target.value;
12066
+ if (!hex.startsWith('#')) {
12067
+ target.value = '#' + hex;
12068
+ return;
12069
+ }
12070
+ const rgb = this.parseColor(hex);
12071
+ if (rgb) {
12072
+ const hsl = this.rgbToHSL(rgb.r, rgb.g, rgb.b);
12073
+ this.hue.set(hsl.h);
12074
+ this.saturation.set(hsl.s);
12075
+ this.lightness.set(hsl.l);
12076
+ this.renderSpectrum();
12077
+ this.updateCursor();
12078
+ }
12079
+ }
12080
+ onRGBInput(channel, event) {
12081
+ const target = event.target;
12082
+ const value = parseInt(target.value, 10);
12083
+ if (isNaN(value) || value < 0 || value > 255)
12084
+ return;
12085
+ const currentRGB = this.rgb();
12086
+ const newRGB = { ...currentRGB, [channel]: value };
12087
+ const hsl = this.rgbToHSL(newRGB.r, newRGB.g, newRGB.b);
12088
+ this.hue.set(hsl.h);
12089
+ this.saturation.set(hsl.s);
12090
+ this.lightness.set(hsl.l);
12091
+ this.renderSpectrum();
12092
+ this.updateCursor();
12093
+ }
12094
+ onAlphaInputManual(event) {
12095
+ const target = event.target;
12096
+ const value = parseFloat(target.value);
12097
+ if (isNaN(value) || value < 0 || value > 1)
12098
+ return;
12099
+ this.alpha.set(value);
12100
+ }
12101
+ selectPreset(color) {
12102
+ const rgb = this.parseColor(color);
12103
+ if (rgb) {
12104
+ const hsl = this.rgbToHSL(rgb.r, rgb.g, rgb.b);
12105
+ this.hue.set(hsl.h);
12106
+ this.saturation.set(hsl.s);
12107
+ this.lightness.set(hsl.l);
12108
+ if (rgb.a !== undefined) {
12109
+ this.alpha.set(rgb.a);
12110
+ }
12111
+ this.renderSpectrum();
12112
+ this.updateCursor();
12113
+ }
12114
+ }
12115
+ // === Conversions de couleurs ===
12116
+ hslToRGB(h, s, l) {
12117
+ h = h / 360;
12118
+ s = s / 100;
12119
+ l = l / 100;
12120
+ let r, g, b;
12121
+ if (s === 0) {
12122
+ r = g = b = l;
12123
+ }
12124
+ else {
12125
+ const hue2rgb = (p, q, t) => {
12126
+ if (t < 0)
12127
+ t += 1;
12128
+ if (t > 1)
12129
+ t -= 1;
12130
+ if (t < 1 / 6)
12131
+ return p + (q - p) * 6 * t;
12132
+ if (t < 1 / 2)
12133
+ return q;
12134
+ if (t < 2 / 3)
12135
+ return p + (q - p) * (2 / 3 - t) * 6;
12136
+ return p;
12137
+ };
12138
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
12139
+ const p = 2 * l - q;
12140
+ r = hue2rgb(p, q, h + 1 / 3);
12141
+ g = hue2rgb(p, q, h);
12142
+ b = hue2rgb(p, q, h - 1 / 3);
12143
+ }
12144
+ return {
12145
+ r: Math.round(r * 255),
12146
+ g: Math.round(g * 255),
12147
+ b: Math.round(b * 255),
12148
+ };
12149
+ }
12150
+ rgbToHSL(r, g, b) {
12151
+ r /= 255;
12152
+ g /= 255;
12153
+ b /= 255;
12154
+ const max = Math.max(r, g, b);
12155
+ const min = Math.min(r, g, b);
12156
+ let h = 0;
12157
+ let s = 0;
12158
+ const l = (max + min) / 2;
12159
+ if (max !== min) {
12160
+ const d = max - min;
12161
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
12162
+ switch (max) {
12163
+ case r:
12164
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
12165
+ break;
12166
+ case g:
12167
+ h = ((b - r) / d + 2) / 6;
12168
+ break;
12169
+ case b:
12170
+ h = ((r - g) / d + 4) / 6;
12171
+ break;
12172
+ }
12173
+ }
12174
+ return {
12175
+ h: Math.round(h * 360),
12176
+ s: Math.round(s * 100),
12177
+ l: Math.round(l * 100),
12178
+ };
12179
+ }
12180
+ parseColor(color) {
12181
+ // Parse HEX
12182
+ if (color.startsWith('#')) {
12183
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(color);
12184
+ if (!result)
12185
+ return null;
12186
+ return {
12187
+ r: parseInt(result[1], 16),
12188
+ g: parseInt(result[2], 16),
12189
+ b: parseInt(result[3], 16),
12190
+ a: result[4] ? parseInt(result[4], 16) / 255 : undefined,
12191
+ };
12192
+ }
12193
+ // Parse RGB/RGBA
12194
+ if (color.startsWith('rgb')) {
12195
+ const match = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
12196
+ if (!match)
12197
+ return null;
12198
+ return {
12199
+ r: parseInt(match[1], 10),
12200
+ g: parseInt(match[2], 10),
12201
+ b: parseInt(match[3], 10),
12202
+ a: match[4] ? parseFloat(match[4]) : undefined,
12203
+ };
12204
+ }
12205
+ return null;
12206
+ }
12207
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPickerPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
12208
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsColorPickerPanelComponent, isStandalone: true, selector: "ds-color-picker-panel", outputs: { colorSelected: "colorSelected", closed: "closed" }, viewQueries: [{ propertyName: "spectrumCanvas", first: true, predicate: ["spectrumCanvas"], descendants: true }], ngImport: i0, template: `
12209
+ <div class="ds-color-picker-panel" role="dialog" aria-label="Color picker">
12210
+ <!-- Spectre de couleurs -->
12211
+ <div class="ds-color-picker-panel__spectrum">
12212
+ <canvas
12213
+ #spectrumCanvas
12214
+ class="ds-color-picker-panel__spectrum-canvas"
12215
+ width="280"
12216
+ height="180"
12217
+ (mousedown)="onSpectrumMouseDown($event)"
12218
+ (mousemove)="onSpectrumMouseMove($event)"
12219
+ (mouseup)="onSpectrumMouseUp()"
12220
+ (mouseleave)="onSpectrumMouseUp()">
12221
+ </canvas>
12222
+
12223
+ <!-- Curseur de sélection -->
12224
+ @if (cursorX() !== null && cursorY() !== null) {
12225
+ <div
12226
+ class="ds-color-picker-panel__cursor"
12227
+ [style.left.px]="cursorX()"
12228
+ [style.top.px]="cursorY()">
12229
+ </div>
12230
+ }
12231
+ </div>
12232
+
12233
+ <!-- Slider de teinte -->
12234
+ <div class="ds-color-picker-panel__hue-slider">
12235
+ <input
12236
+ type="range"
12237
+ class="ds-color-picker-panel__slider"
12238
+ min="0"
12239
+ max="360"
12240
+ step="1"
12241
+ [value]="hue()"
12242
+ (input)="onHueChange($event)"
12243
+ aria-label="Hue" />
12244
+ </div>
12245
+
12246
+ <!-- Slider alpha (optionnel) -->
12247
+ @if (showAlpha) {
12248
+ <div class="ds-color-picker-panel__alpha-slider">
12249
+ <div class="ds-color-picker-panel__alpha-bg"></div>
12250
+ <input
12251
+ type="range"
12252
+ class="ds-color-picker-panel__slider ds-color-picker-panel__slider--alpha"
12253
+ min="0"
12254
+ max="100"
12255
+ step="1"
12256
+ [value]="alpha() * 100"
12257
+ (input)="onAlphaChange($event)"
12258
+ aria-label="Alpha" />
12259
+ </div>
12260
+ }
12261
+
12262
+ <!-- Inputs manuels -->
12263
+ <div class="ds-color-picker-panel__inputs">
12264
+ @if (format === 'hex') {
12265
+ <div class="ds-color-picker-panel__input-group">
12266
+ <label class="ds-color-picker-panel__label">HEX</label>
12267
+ <input
12268
+ type="text"
12269
+ class="ds-color-picker-panel__input"
12270
+ [value]="hexValue()"
12271
+ (input)="onHexInput($event)"
12272
+ maxlength="7"
12273
+ placeholder="#000000" />
12274
+ </div>
12275
+ }
12276
+
12277
+ @if (format === 'rgb') {
12278
+ <div class="ds-color-picker-panel__input-group">
12279
+ <label class="ds-color-picker-panel__label">R</label>
12280
+ <input
12281
+ type="number"
12282
+ class="ds-color-picker-panel__input"
12283
+ min="0"
12284
+ max="255"
12285
+ [value]="rgb().r"
12286
+ (input)="onRGBInput('r', $event)" />
12287
+ </div>
12288
+ <div class="ds-color-picker-panel__input-group">
12289
+ <label class="ds-color-picker-panel__label">G</label>
12290
+ <input
12291
+ type="number"
12292
+ class="ds-color-picker-panel__input"
12293
+ min="0"
12294
+ max="255"
12295
+ [value]="rgb().g"
12296
+ (input)="onRGBInput('g', $event)" />
12297
+ </div>
12298
+ <div class="ds-color-picker-panel__input-group">
12299
+ <label class="ds-color-picker-panel__label">B</label>
12300
+ <input
12301
+ type="number"
12302
+ class="ds-color-picker-panel__input"
12303
+ min="0"
12304
+ max="255"
12305
+ [value]="rgb().b"
12306
+ (input)="onRGBInput('b', $event)" />
12307
+ </div>
12308
+ @if (showAlpha) {
12309
+ <div class="ds-color-picker-panel__input-group">
12310
+ <label class="ds-color-picker-panel__label">A</label>
12311
+ <input
12312
+ type="number"
12313
+ class="ds-color-picker-panel__input"
12314
+ min="0"
12315
+ max="1"
12316
+ step="0.01"
12317
+ [value]="alpha()"
12318
+ (input)="onAlphaInputManual($event)" />
12319
+ </div>
12320
+ }
12321
+ }
12322
+ </div>
12323
+
12324
+ <!-- Couleurs prédéfinies -->
12325
+ @if (presetColors.length > 0) {
12326
+ <div class="ds-color-picker-panel__presets">
12327
+ <div class="ds-color-picker-panel__presets-label">Presets</div>
12328
+ <div class="ds-color-picker-panel__presets-grid">
12329
+ @for (color of presetColors; track color) {
12330
+ <button
12331
+ type="button"
12332
+ class="ds-color-picker-panel__preset"
12333
+ [style.background-color]="color"
12334
+ [class.ds-color-picker-panel__preset--selected]="color === value"
12335
+ (click)="selectPreset(color)"
12336
+ [attr.aria-label]="'Select ' + color">
12337
+ @if (color === value) {
12338
+ <fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
12339
+ }
12340
+ </button>
12341
+ }
12342
+ </div>
12343
+ </div>
12344
+ }
12345
+
12346
+ <!-- Couleurs récentes -->
12347
+ @if (showRecentColors && recentColors.length > 0) {
12348
+ <div class="ds-color-picker-panel__recent">
12349
+ <div class="ds-color-picker-panel__recent-label">Recent</div>
12350
+ <div class="ds-color-picker-panel__recent-grid">
12351
+ @for (color of recentColors; track color) {
12352
+ <button
12353
+ type="button"
12354
+ class="ds-color-picker-panel__preset"
12355
+ [style.background-color]="color"
12356
+ [class.ds-color-picker-panel__preset--selected]="color === value"
12357
+ (click)="selectPreset(color)"
12358
+ [attr.aria-label]="'Select ' + color">
12359
+ @if (color === value) {
12360
+ <fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
12361
+ }
12362
+ </button>
12363
+ }
12364
+ </div>
12365
+ </div>
12366
+ }
12367
+ </div>
12368
+ `, isInline: true, styles: [".ds-color-picker-panel{position:relative;display:flex;flex-direction:column;gap:var(--space-3);width:300px;padding:var(--space-4);background:var(--colorpicker-panel-bg, var(--background-main));border:1px solid var(--colorpicker-panel-border, var(--border-default));border-radius:var(--colorpicker-panel-radius, var(--radius-2));box-shadow:var(--colorpicker-panel-shadow, var(--shadow-3))}.ds-color-picker-panel__spectrum{position:relative;width:100%;height:180px;border-radius:var(--radius-1);overflow:hidden;cursor:crosshair;border:1px solid var(--border-default)}.ds-color-picker-panel__spectrum-canvas{display:block;width:100%;height:100%}.ds-color-picker-panel__cursor{position:absolute;width:16px;height:16px;border:2px solid white;border-radius:50%;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;transform:translate(-50%,-50%);pointer-events:none}.ds-color-picker-panel__hue-slider,.ds-color-picker-panel__alpha-slider{position:relative;width:100%;height:12px;border-radius:var(--radius-1);overflow:hidden}.ds-color-picker-panel__hue-slider{background:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.ds-color-picker-panel__alpha-slider .ds-color-picker-panel__alpha-bg{position:absolute;inset:0;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__slider{position:relative;width:100%;height:100%;-webkit-appearance:none;appearance:none;background:transparent;cursor:pointer;z-index:1}.ds-color-picker-panel__slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider::-moz-range-thumb{width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__slider--alpha{background:linear-gradient(to right,transparent 0%,currentColor 100%)}.ds-color-picker-panel__inputs{display:flex;gap:var(--space-2)}.ds-color-picker-panel__input-group{display:flex;flex-direction:column;gap:var(--space-1);flex:1}.ds-color-picker-panel__label{font-size:var(--font-size-1);font-weight:600;color:var(--text-muted);text-transform:uppercase}.ds-color-picker-panel__input{width:100%;padding:var(--space-1) var(--space-2);background:var(--colorpicker-input-bg, var(--background-main));border:1px solid var(--colorpicker-input-border, var(--border-default));border-radius:var(--radius-1);color:var(--colorpicker-input-text, var(--text-default));font-size:var(--font-size-2);font-family:monospace;text-align:center;outline:none;transition:border-color var(--duration-fast, .15s) ease}.ds-color-picker-panel__input:focus{border-color:var(--color-primary)}.ds-color-picker-panel__input:hover:not(:focus){border-color:var(--border-strong)}.ds-color-picker-panel__input[type=number]{-moz-appearance:textfield}.ds-color-picker-panel__input[type=number]::-webkit-outer-spin-button,.ds-color-picker-panel__input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-color-picker-panel__presets,.ds-color-picker-panel__recent{display:flex;flex-direction:column;gap:var(--space-2)}.ds-color-picker-panel__presets-label,.ds-color-picker-panel__recent-label{font-size:var(--font-size-2);font-weight:600;color:var(--text-muted)}.ds-color-picker-panel__presets-grid,.ds-color-picker-panel__recent-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:var(--space-2)}.ds-color-picker-panel__preset{position:relative;width:28px;height:28px;padding:0;background:currentColor;border:2px solid var(--colorpicker-preset-border, var(--border-default));border-radius:var(--radius-1);cursor:pointer;transition:transform var(--duration-fast, .15s) ease,border-color var(--duration-fast, .15s) ease;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__preset:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker-panel__preset:hover:not(:disabled){transform:scale(1.1);border-color:var(--color-primary)}.ds-color-picker-panel__preset:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__preset--selected{border-color:var(--color-primary);border-width:3px}.ds-color-picker-panel__preset-check{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5));font-size:var(--font-size-2);z-index:1}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
12369
+ }
12370
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPickerPanelComponent, decorators: [{
12371
+ type: Component,
12372
+ args: [{ selector: 'ds-color-picker-panel', standalone: true, imports: [CommonModule, FormsModule, FontAwesomeModule], template: `
12373
+ <div class="ds-color-picker-panel" role="dialog" aria-label="Color picker">
12374
+ <!-- Spectre de couleurs -->
12375
+ <div class="ds-color-picker-panel__spectrum">
12376
+ <canvas
12377
+ #spectrumCanvas
12378
+ class="ds-color-picker-panel__spectrum-canvas"
12379
+ width="280"
12380
+ height="180"
12381
+ (mousedown)="onSpectrumMouseDown($event)"
12382
+ (mousemove)="onSpectrumMouseMove($event)"
12383
+ (mouseup)="onSpectrumMouseUp()"
12384
+ (mouseleave)="onSpectrumMouseUp()">
12385
+ </canvas>
12386
+
12387
+ <!-- Curseur de sélection -->
12388
+ @if (cursorX() !== null && cursorY() !== null) {
12389
+ <div
12390
+ class="ds-color-picker-panel__cursor"
12391
+ [style.left.px]="cursorX()"
12392
+ [style.top.px]="cursorY()">
12393
+ </div>
12394
+ }
12395
+ </div>
12396
+
12397
+ <!-- Slider de teinte -->
12398
+ <div class="ds-color-picker-panel__hue-slider">
12399
+ <input
12400
+ type="range"
12401
+ class="ds-color-picker-panel__slider"
12402
+ min="0"
12403
+ max="360"
12404
+ step="1"
12405
+ [value]="hue()"
12406
+ (input)="onHueChange($event)"
12407
+ aria-label="Hue" />
12408
+ </div>
12409
+
12410
+ <!-- Slider alpha (optionnel) -->
12411
+ @if (showAlpha) {
12412
+ <div class="ds-color-picker-panel__alpha-slider">
12413
+ <div class="ds-color-picker-panel__alpha-bg"></div>
12414
+ <input
12415
+ type="range"
12416
+ class="ds-color-picker-panel__slider ds-color-picker-panel__slider--alpha"
12417
+ min="0"
12418
+ max="100"
12419
+ step="1"
12420
+ [value]="alpha() * 100"
12421
+ (input)="onAlphaChange($event)"
12422
+ aria-label="Alpha" />
12423
+ </div>
12424
+ }
12425
+
12426
+ <!-- Inputs manuels -->
12427
+ <div class="ds-color-picker-panel__inputs">
12428
+ @if (format === 'hex') {
12429
+ <div class="ds-color-picker-panel__input-group">
12430
+ <label class="ds-color-picker-panel__label">HEX</label>
12431
+ <input
12432
+ type="text"
12433
+ class="ds-color-picker-panel__input"
12434
+ [value]="hexValue()"
12435
+ (input)="onHexInput($event)"
12436
+ maxlength="7"
12437
+ placeholder="#000000" />
12438
+ </div>
12439
+ }
12440
+
12441
+ @if (format === 'rgb') {
12442
+ <div class="ds-color-picker-panel__input-group">
12443
+ <label class="ds-color-picker-panel__label">R</label>
12444
+ <input
12445
+ type="number"
12446
+ class="ds-color-picker-panel__input"
12447
+ min="0"
12448
+ max="255"
12449
+ [value]="rgb().r"
12450
+ (input)="onRGBInput('r', $event)" />
12451
+ </div>
12452
+ <div class="ds-color-picker-panel__input-group">
12453
+ <label class="ds-color-picker-panel__label">G</label>
12454
+ <input
12455
+ type="number"
12456
+ class="ds-color-picker-panel__input"
12457
+ min="0"
12458
+ max="255"
12459
+ [value]="rgb().g"
12460
+ (input)="onRGBInput('g', $event)" />
12461
+ </div>
12462
+ <div class="ds-color-picker-panel__input-group">
12463
+ <label class="ds-color-picker-panel__label">B</label>
12464
+ <input
12465
+ type="number"
12466
+ class="ds-color-picker-panel__input"
12467
+ min="0"
12468
+ max="255"
12469
+ [value]="rgb().b"
12470
+ (input)="onRGBInput('b', $event)" />
12471
+ </div>
12472
+ @if (showAlpha) {
12473
+ <div class="ds-color-picker-panel__input-group">
12474
+ <label class="ds-color-picker-panel__label">A</label>
12475
+ <input
12476
+ type="number"
12477
+ class="ds-color-picker-panel__input"
12478
+ min="0"
12479
+ max="1"
12480
+ step="0.01"
12481
+ [value]="alpha()"
12482
+ (input)="onAlphaInputManual($event)" />
12483
+ </div>
12484
+ }
12485
+ }
12486
+ </div>
12487
+
12488
+ <!-- Couleurs prédéfinies -->
12489
+ @if (presetColors.length > 0) {
12490
+ <div class="ds-color-picker-panel__presets">
12491
+ <div class="ds-color-picker-panel__presets-label">Presets</div>
12492
+ <div class="ds-color-picker-panel__presets-grid">
12493
+ @for (color of presetColors; track color) {
12494
+ <button
12495
+ type="button"
12496
+ class="ds-color-picker-panel__preset"
12497
+ [style.background-color]="color"
12498
+ [class.ds-color-picker-panel__preset--selected]="color === value"
12499
+ (click)="selectPreset(color)"
12500
+ [attr.aria-label]="'Select ' + color">
12501
+ @if (color === value) {
12502
+ <fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
12503
+ }
12504
+ </button>
12505
+ }
12506
+ </div>
12507
+ </div>
12508
+ }
12509
+
12510
+ <!-- Couleurs récentes -->
12511
+ @if (showRecentColors && recentColors.length > 0) {
12512
+ <div class="ds-color-picker-panel__recent">
12513
+ <div class="ds-color-picker-panel__recent-label">Recent</div>
12514
+ <div class="ds-color-picker-panel__recent-grid">
12515
+ @for (color of recentColors; track color) {
12516
+ <button
12517
+ type="button"
12518
+ class="ds-color-picker-panel__preset"
12519
+ [style.background-color]="color"
12520
+ [class.ds-color-picker-panel__preset--selected]="color === value"
12521
+ (click)="selectPreset(color)"
12522
+ [attr.aria-label]="'Select ' + color">
12523
+ @if (color === value) {
12524
+ <fa-icon [icon]="checkIcon" class="ds-color-picker-panel__preset-check"></fa-icon>
12525
+ }
12526
+ </button>
12527
+ }
12528
+ </div>
12529
+ </div>
12530
+ }
12531
+ </div>
12532
+ `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".ds-color-picker-panel{position:relative;display:flex;flex-direction:column;gap:var(--space-3);width:300px;padding:var(--space-4);background:var(--colorpicker-panel-bg, var(--background-main));border:1px solid var(--colorpicker-panel-border, var(--border-default));border-radius:var(--colorpicker-panel-radius, var(--radius-2));box-shadow:var(--colorpicker-panel-shadow, var(--shadow-3))}.ds-color-picker-panel__spectrum{position:relative;width:100%;height:180px;border-radius:var(--radius-1);overflow:hidden;cursor:crosshair;border:1px solid var(--border-default)}.ds-color-picker-panel__spectrum-canvas{display:block;width:100%;height:100%}.ds-color-picker-panel__cursor{position:absolute;width:16px;height:16px;border:2px solid white;border-radius:50%;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;transform:translate(-50%,-50%);pointer-events:none}.ds-color-picker-panel__hue-slider,.ds-color-picker-panel__alpha-slider{position:relative;width:100%;height:12px;border-radius:var(--radius-1);overflow:hidden}.ds-color-picker-panel__hue-slider{background:linear-gradient(to right,red,#ff0,#0f0,#0ff,#00f,#f0f,red)}.ds-color-picker-panel__alpha-slider .ds-color-picker-panel__alpha-bg{position:absolute;inset:0;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__slider{position:relative;width:100%;height:100%;-webkit-appearance:none;appearance:none;background:transparent;cursor:pointer;z-index:1}.ds-color-picker-panel__slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider::-moz-range-thumb{width:16px;height:16px;border:2px solid white;border-radius:50%;background:transparent;box-shadow:0 0 0 1px #0000004d,0 2px 4px #0003;cursor:pointer}.ds-color-picker-panel__slider:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__slider--alpha{background:linear-gradient(to right,transparent 0%,currentColor 100%)}.ds-color-picker-panel__inputs{display:flex;gap:var(--space-2)}.ds-color-picker-panel__input-group{display:flex;flex-direction:column;gap:var(--space-1);flex:1}.ds-color-picker-panel__label{font-size:var(--font-size-1);font-weight:600;color:var(--text-muted);text-transform:uppercase}.ds-color-picker-panel__input{width:100%;padding:var(--space-1) var(--space-2);background:var(--colorpicker-input-bg, var(--background-main));border:1px solid var(--colorpicker-input-border, var(--border-default));border-radius:var(--radius-1);color:var(--colorpicker-input-text, var(--text-default));font-size:var(--font-size-2);font-family:monospace;text-align:center;outline:none;transition:border-color var(--duration-fast, .15s) ease}.ds-color-picker-panel__input:focus{border-color:var(--color-primary)}.ds-color-picker-panel__input:hover:not(:focus){border-color:var(--border-strong)}.ds-color-picker-panel__input[type=number]{-moz-appearance:textfield}.ds-color-picker-panel__input[type=number]::-webkit-outer-spin-button,.ds-color-picker-panel__input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ds-color-picker-panel__presets,.ds-color-picker-panel__recent{display:flex;flex-direction:column;gap:var(--space-2)}.ds-color-picker-panel__presets-label,.ds-color-picker-panel__recent-label{font-size:var(--font-size-2);font-weight:600;color:var(--text-muted)}.ds-color-picker-panel__presets-grid,.ds-color-picker-panel__recent-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:var(--space-2)}.ds-color-picker-panel__preset{position:relative;width:28px;height:28px;padding:0;background:currentColor;border:2px solid var(--colorpicker-preset-border, var(--border-default));border-radius:var(--radius-1);cursor:pointer;transition:transform var(--duration-fast, .15s) ease,border-color var(--duration-fast, .15s) ease;background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0}.ds-color-picker-panel__preset:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker-panel__preset:hover:not(:disabled){transform:scale(1.1);border-color:var(--color-primary)}.ds-color-picker-panel__preset:focus-visible{outline:2px solid var(--color-primary);outline-offset:2px}.ds-color-picker-panel__preset--selected{border-color:var(--color-primary);border-width:3px}.ds-color-picker-panel__preset-check{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:#fff;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5));font-size:var(--font-size-2);z-index:1}\n"] }]
12533
+ }], ctorParameters: () => [], propDecorators: { spectrumCanvas: [{
12534
+ type: ViewChild,
12535
+ args: ['spectrumCanvas']
12536
+ }], colorSelected: [{ type: i0.Output, args: ["colorSelected"] }], closed: [{ type: i0.Output, args: ["closed"] }] } });
12537
+
12538
+ /**
12539
+ * DsColorPicker - Composant de sélection de couleur
12540
+ *
12541
+ * @description
12542
+ * Sélecteur de couleur avec palette prédéfinie, spectre de couleurs,
12543
+ * support RGB/HSL, alpha channel optionnel, et intégration formulaires.
12544
+ *
12545
+ * @example
12546
+ * ```html
12547
+ * <ds-color-picker
12548
+ * [value]="'#3b82f6'"
12549
+ * [showAlpha]="true"
12550
+ * (colorChange)="onColorChange($event)">
12551
+ * </ds-color-picker>
12552
+ * ```
12553
+ */
12554
+ class DsColorPicker {
12555
+ overlay;
12556
+ elementRef;
12557
+ // Inputs
12558
+ value = input('', ...(ngDevMode ? [{ debugName: "value" }] : []));
12559
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : []));
12560
+ disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
12561
+ showAlpha = input(false, ...(ngDevMode ? [{ debugName: "showAlpha" }] : []));
12562
+ presetColors = input([], ...(ngDevMode ? [{ debugName: "presetColors" }] : []));
12563
+ format = input('hex', ...(ngDevMode ? [{ debugName: "format" }] : []));
12564
+ placeholder = input('Select color', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
12565
+ allowClear = input(true, ...(ngDevMode ? [{ debugName: "allowClear" }] : []));
12566
+ showRecentColors = input(true, ...(ngDevMode ? [{ debugName: "showRecentColors" }] : []));
12567
+ maxRecentColors = input(8, ...(ngDevMode ? [{ debugName: "maxRecentColors" }] : []));
12568
+ // Outputs
12569
+ colorChange = output();
12570
+ // Icons
12571
+ pickerIcon = faEyeDropper;
12572
+ clearIcon = faTimes;
12573
+ checkIcon = faCheck;
12574
+ // State
12575
+ isOpen = signal(false, ...(ngDevMode ? [{ debugName: "isOpen" }] : []));
12576
+ internalValue = signal('', ...(ngDevMode ? [{ debugName: "internalValue" }] : []));
12577
+ isFocused = signal(false, ...(ngDevMode ? [{ debugName: "isFocused" }] : []));
12578
+ recentColors = signal([], ...(ngDevMode ? [{ debugName: "recentColors" }] : []));
12579
+ // Overlay
12580
+ overlayRef = null;
12581
+ // Computed
12582
+ containerClasses = computed(() => {
12583
+ const classes = ['ds-color-picker'];
12584
+ classes.push(`ds-color-picker--${this.size()}`);
12585
+ if (this.disabled())
12586
+ classes.push('ds-color-picker--disabled');
12587
+ if (this.isFocused())
12588
+ classes.push('ds-color-picker--focused');
12589
+ if (this.isOpen())
12590
+ classes.push('ds-color-picker--open');
12591
+ return classes.join(' ');
12592
+ }, ...(ngDevMode ? [{ debugName: "containerClasses" }] : []));
12593
+ displayValue = computed(() => {
12594
+ const val = this.internalValue();
12595
+ if (!val)
12596
+ return '';
12597
+ // Convertir selon le format demandé
12598
+ const format = this.format();
12599
+ if (format === 'hex') {
12600
+ return this.toHex(val);
12601
+ }
12602
+ else if (format === 'rgb') {
12603
+ return this.toRGB(val);
12604
+ }
12605
+ else if (format === 'hsl') {
12606
+ return this.toHSL(val);
12607
+ }
12608
+ return val;
12609
+ }, ...(ngDevMode ? [{ debugName: "displayValue" }] : []));
12610
+ previewColor = computed(() => {
12611
+ return this.internalValue() || 'transparent';
12612
+ }, ...(ngDevMode ? [{ debugName: "previewColor" }] : []));
12613
+ effectivePresets = computed(() => {
12614
+ const custom = this.presetColors();
12615
+ if (custom.length > 0)
12616
+ return custom;
12617
+ // Palette par défaut
12618
+ return [
12619
+ '#000000', '#ffffff', '#f87171', '#fb923c', '#fbbf24', '#facc15',
12620
+ '#a3e635', '#4ade80', '#34d399', '#2dd4bf', '#22d3ee', '#38bdf8',
12621
+ '#60a5fa', '#818cf8', '#a78bfa', '#c084fc', '#e879f9', '#f472b6',
12622
+ '#fb7185', '#f43f5e', '#ef4444', '#dc2626', '#b91c1c', '#991b1b',
12623
+ ];
12624
+ }, ...(ngDevMode ? [{ debugName: "effectivePresets" }] : []));
12625
+ // ControlValueAccessor
12626
+ onChange = () => { };
12627
+ onTouched = () => { };
12628
+ constructor(overlay, elementRef) {
12629
+ this.overlay = overlay;
12630
+ this.elementRef = elementRef;
12631
+ // Sync external value with internal
12632
+ effect(() => {
12633
+ const val = this.value();
12634
+ if (val !== this.internalValue()) {
12635
+ this.internalValue.set(val);
12636
+ }
12637
+ });
12638
+ // Charger les couleurs récentes depuis localStorage
12639
+ this.loadRecentColors();
12640
+ }
12641
+ writeValue(value) {
12642
+ this.internalValue.set(value || '');
12643
+ }
12644
+ registerOnChange(fn) {
12645
+ this.onChange = fn;
12646
+ }
12647
+ registerOnTouched(fn) {
12648
+ this.onTouched = fn;
12649
+ }
12650
+ setDisabledState(isDisabled) {
12651
+ // Géré par input disabled
12652
+ }
12653
+ toggle() {
12654
+ if (this.disabled())
12655
+ return;
12656
+ if (this.isOpen()) {
12657
+ this.close();
12658
+ }
12659
+ else {
12660
+ this.open();
12661
+ }
12662
+ }
12663
+ open() {
12664
+ if (this.disabled() || this.isOpen())
12665
+ return;
12666
+ this.isOpen.set(true);
12667
+ this.createOverlay();
12668
+ }
12669
+ close() {
12670
+ if (!this.isOpen())
12671
+ return;
12672
+ this.isOpen.set(false);
12673
+ this.destroyOverlay();
12674
+ this.onTouched();
12675
+ }
12676
+ onFocus() {
12677
+ if (!this.disabled()) {
12678
+ this.isFocused.set(true);
12679
+ }
12680
+ }
12681
+ onBlur() {
12682
+ this.isFocused.set(false);
12683
+ if (!this.isOpen()) {
12684
+ this.onTouched();
12685
+ }
12686
+ }
12687
+ clear() {
12688
+ if (this.disabled())
12689
+ return;
12690
+ this.updateValue('');
12691
+ }
12692
+ onColorSelected(color) {
12693
+ this.updateValue(color);
12694
+ this.addToRecentColors(color);
12695
+ }
12696
+ updateValue(value) {
12697
+ this.internalValue.set(value);
12698
+ this.onChange(value);
12699
+ this.colorChange.emit(value);
12700
+ }
12701
+ createOverlay() {
12702
+ if (this.overlayRef)
12703
+ return;
12704
+ const positionStrategy = this.overlay
12705
+ .position()
12706
+ .flexibleConnectedTo(this.elementRef.nativeElement.querySelector('.ds-color-picker__trigger'))
12707
+ .withPositions([
12708
+ {
12709
+ originX: 'start',
12710
+ originY: 'bottom',
12711
+ overlayX: 'start',
12712
+ overlayY: 'top',
12713
+ offsetY: 8,
12714
+ },
12715
+ {
12716
+ originX: 'start',
12717
+ originY: 'top',
12718
+ overlayX: 'start',
12719
+ overlayY: 'bottom',
12720
+ offsetY: -8,
12721
+ },
12722
+ ]);
12723
+ this.overlayRef = this.overlay.create({
12724
+ positionStrategy,
12725
+ hasBackdrop: true,
12726
+ backdropClass: 'cdk-overlay-transparent-backdrop',
12727
+ scrollStrategy: this.overlay.scrollStrategies.reposition(),
12728
+ });
12729
+ const portal = new ComponentPortal(DsColorPickerPanelComponent);
12730
+ const componentRef = this.overlayRef.attach(portal);
12731
+ // Configuration du panel
12732
+ componentRef.instance.value = this.internalValue();
12733
+ componentRef.instance.showAlpha = this.showAlpha();
12734
+ componentRef.instance.presetColors = this.effectivePresets();
12735
+ componentRef.instance.recentColors = this.recentColors();
12736
+ componentRef.instance.showRecentColors = this.showRecentColors();
12737
+ componentRef.instance.format = this.format();
12738
+ // Écouter les événements
12739
+ componentRef.instance.colorSelected.subscribe((color) => {
12740
+ this.onColorSelected(color);
12741
+ });
12742
+ componentRef.instance.closed.subscribe(() => {
12743
+ this.close();
12744
+ });
12745
+ // Fermer au clic sur backdrop
12746
+ this.overlayRef.backdropClick().subscribe(() => {
12747
+ this.close();
12748
+ });
12749
+ }
12750
+ destroyOverlay() {
12751
+ if (this.overlayRef) {
12752
+ this.overlayRef.dispose();
12753
+ this.overlayRef = null;
12754
+ }
12755
+ }
12756
+ addToRecentColors(color) {
12757
+ if (!this.showRecentColors() || !color)
12758
+ return;
12759
+ const recent = this.recentColors();
12760
+ const filtered = recent.filter(c => c !== color);
12761
+ const updated = [color, ...filtered].slice(0, this.maxRecentColors());
12762
+ this.recentColors.set(updated);
12763
+ this.saveRecentColors(updated);
12764
+ }
12765
+ loadRecentColors() {
12766
+ try {
12767
+ const stored = localStorage.getItem('ds-color-picker-recent');
12768
+ if (stored) {
12769
+ const colors = JSON.parse(stored);
12770
+ if (Array.isArray(colors)) {
12771
+ this.recentColors.set(colors.slice(0, this.maxRecentColors()));
12772
+ }
12773
+ }
12774
+ }
12775
+ catch (e) {
12776
+ // Ignorer les erreurs de parsing
12777
+ }
12778
+ }
12779
+ saveRecentColors(colors) {
12780
+ try {
12781
+ localStorage.setItem('ds-color-picker-recent', JSON.stringify(colors));
12782
+ }
12783
+ catch (e) {
12784
+ // Ignorer les erreurs de stockage
12785
+ }
12786
+ }
12787
+ // === Conversions de couleurs ===
12788
+ toHex(color) {
12789
+ if (color.startsWith('#'))
12790
+ return color;
12791
+ const rgb = this.parseRGB(color);
12792
+ if (rgb) {
12793
+ const r = rgb.r.toString(16).padStart(2, '0');
12794
+ const g = rgb.g.toString(16).padStart(2, '0');
12795
+ const b = rgb.b.toString(16).padStart(2, '0');
12796
+ return `#${r}${g}${b}`;
12797
+ }
12798
+ return color;
12799
+ }
12800
+ toRGB(color) {
12801
+ if (color.startsWith('rgb'))
12802
+ return color;
12803
+ const rgb = this.hexToRGB(color);
12804
+ if (rgb) {
12805
+ if (rgb.a !== undefined) {
12806
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`;
12807
+ }
12808
+ return `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`;
12809
+ }
12810
+ return color;
12811
+ }
12812
+ toHSL(color) {
12813
+ if (color.startsWith('hsl'))
12814
+ return color;
12815
+ const rgb = this.hexToRGB(color);
12816
+ if (rgb) {
12817
+ const hsl = this.rgbToHSL(rgb);
12818
+ if (hsl.a !== undefined) {
12819
+ return `hsla(${hsl.h}, ${hsl.s}%, ${hsl.l}%, ${hsl.a})`;
12820
+ }
12821
+ return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`;
12822
+ }
12823
+ return color;
12824
+ }
12825
+ hexToRGB(hex) {
12826
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
12827
+ if (!result)
12828
+ return null;
12829
+ return {
12830
+ r: parseInt(result[1], 16),
12831
+ g: parseInt(result[2], 16),
12832
+ b: parseInt(result[3], 16),
12833
+ a: result[4] ? parseInt(result[4], 16) / 255 : undefined,
12834
+ };
12835
+ }
12836
+ parseRGB(rgb) {
12837
+ const match = rgb.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
12838
+ if (!match)
12839
+ return null;
12840
+ return {
12841
+ r: parseInt(match[1], 10),
12842
+ g: parseInt(match[2], 10),
12843
+ b: parseInt(match[3], 10),
12844
+ a: match[4] ? parseFloat(match[4]) : undefined,
12845
+ };
12846
+ }
12847
+ rgbToHSL(rgb) {
12848
+ const r = rgb.r / 255;
12849
+ const g = rgb.g / 255;
12850
+ const b = rgb.b / 255;
12851
+ const max = Math.max(r, g, b);
12852
+ const min = Math.min(r, g, b);
12853
+ let h = 0;
12854
+ let s = 0;
12855
+ const l = (max + min) / 2;
12856
+ if (max !== min) {
12857
+ const d = max - min;
12858
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
12859
+ switch (max) {
12860
+ case r:
12861
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
12862
+ break;
12863
+ case g:
12864
+ h = ((b - r) / d + 2) / 6;
12865
+ break;
12866
+ case b:
12867
+ h = ((r - g) / d + 4) / 6;
12868
+ break;
12869
+ }
12870
+ }
12871
+ return {
12872
+ h: Math.round(h * 360),
12873
+ s: Math.round(s * 100),
12874
+ l: Math.round(l * 100),
12875
+ a: rgb.a,
12876
+ };
12877
+ }
12878
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPicker, deps: [{ token: i1$3.Overlay }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
12879
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: DsColorPicker, isStandalone: true, selector: "ds-color-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, showAlpha: { classPropertyName: "showAlpha", publicName: "showAlpha", isSignal: true, isRequired: false, transformFunction: null }, presetColors: { classPropertyName: "presetColors", publicName: "presetColors", isSignal: true, isRequired: false, transformFunction: null }, format: { classPropertyName: "format", publicName: "format", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, allowClear: { classPropertyName: "allowClear", publicName: "allowClear", isSignal: true, isRequired: false, transformFunction: null }, showRecentColors: { classPropertyName: "showRecentColors", publicName: "showRecentColors", isSignal: true, isRequired: false, transformFunction: null }, maxRecentColors: { classPropertyName: "maxRecentColors", publicName: "maxRecentColors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { colorChange: "colorChange" }, providers: [
12880
+ {
12881
+ provide: NG_VALUE_ACCESSOR,
12882
+ useExisting: forwardRef(() => DsColorPicker),
12883
+ multi: true,
12884
+ },
12885
+ ], ngImport: i0, template: "<div [class]=\"containerClasses()\">\n <div class=\"ds-color-picker__trigger\" (click)=\"toggle()\">\n <!-- Preview de la couleur -->\n <div\n class=\"ds-color-picker__preview\"\n [style.background-color]=\"previewColor()\"\n [attr.aria-label]=\"'Color: ' + displayValue()\">\n </div>\n\n <!-- Input texte -->\n <input\n type=\"text\"\n class=\"ds-color-picker__input\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n readonly\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [attr.aria-label]=\"placeholder()\" />\n\n <!-- Actions -->\n <div class=\"ds-color-picker__actions\">\n @if (allowClear() && internalValue()) {\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--clear\"\n [disabled]=\"disabled()\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"'Clear color'\">\n <fa-icon [icon]=\"clearIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--picker\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'Open color picker'\">\n <fa-icon [icon]=\"pickerIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n </div>\n </div>\n</div>\n", styles: [".ds-color-picker{position:relative;display:inline-flex;width:100%}.ds-color-picker__trigger{position:relative;display:flex;align-items:center;gap:var(--colorpicker-gap, var(--space-2));width:100%;background:var(--colorpicker-bg, var(--background-main));border:1px solid var(--colorpicker-border, var(--border-default));border-radius:var(--colorpicker-radius, var(--radius-2));padding:var(--colorpicker-padding, var(--space-2));cursor:pointer;transition:border-color var(--duration-fast, .15s) ease,box-shadow var(--duration-fast, .15s) ease}.ds-color-picker__trigger:hover:not([disabled]){border-color:var(--colorpicker-border-hover, var(--border-strong))}.ds-color-picker__preview{flex-shrink:0;width:var(--colorpicker-preview-size, 28px);height:var(--colorpicker-preview-size, 28px);border:2px solid var(--colorpicker-preview-border, var(--border-default));border-radius:var(--radius-1);background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;position:relative}.ds-color-picker__preview:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker__input{flex:1;min-width:0;background:transparent;border:none;color:var(--colorpicker-text, var(--text-default));font-size:var(--colorpicker-font-size, var(--font-size-3));outline:none;cursor:pointer}.ds-color-picker__input::placeholder{color:var(--colorpicker-placeholder, var(--text-muted))}.ds-color-picker__input:disabled{cursor:not-allowed}.ds-color-picker__actions{display:flex;align-items:center;gap:var(--space-1)}.ds-color-picker__action{display:flex;align-items:center;justify-content:center;width:var(--colorpicker-action-size, 24px);height:var(--colorpicker-action-size, 24px);padding:0;background:transparent;border:none;border-radius:var(--radius-1);color:var(--colorpicker-icon, var(--text-muted));cursor:pointer;transition:background-color var(--duration-fast, .15s) ease,color var(--duration-fast, .15s) ease}.ds-color-picker__action:hover:not(:disabled){background:var(--colorpicker-action-hover-bg, var(--surface-hover));color:var(--text-default)}.ds-color-picker__action:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.ds-color-picker__action:disabled{opacity:.5;cursor:not-allowed}.ds-color-picker__action--clear{color:var(--colorpicker-clear-icon, var(--text-muted))}.ds-color-picker__action--clear:hover:not(:disabled){color:var(--error)}.ds-color-picker--sm .ds-color-picker__trigger{padding:var(--colorpicker-padding-sm, var(--space-1) var(--space-2));height:var(--colorpicker-height-sm, 32px)}.ds-color-picker--sm .ds-color-picker__preview{width:var(--colorpicker-preview-size-sm, 20px);height:var(--colorpicker-preview-size-sm, 20px)}.ds-color-picker--sm .ds-color-picker__input{font-size:var(--colorpicker-font-size-sm, var(--font-size-2))}.ds-color-picker--sm .ds-color-picker__action{width:var(--colorpicker-action-size-sm, 20px);height:var(--colorpicker-action-size-sm, 20px);font-size:var(--font-size-2)}.ds-color-picker--md .ds-color-picker__trigger{padding:var(--colorpicker-padding-md, var(--space-2));height:var(--colorpicker-height-md, 40px)}.ds-color-picker--md .ds-color-picker__preview{width:var(--colorpicker-preview-size-md, 28px);height:var(--colorpicker-preview-size-md, 28px)}.ds-color-picker--md .ds-color-picker__input{font-size:var(--colorpicker-font-size-md, var(--font-size-3))}.ds-color-picker--md .ds-color-picker__action{width:var(--colorpicker-action-size-md, 24px);height:var(--colorpicker-action-size-md, 24px);font-size:var(--font-size-3)}.ds-color-picker--lg .ds-color-picker__trigger{padding:var(--colorpicker-padding-lg, var(--space-3));height:var(--colorpicker-height-lg, 48px)}.ds-color-picker--lg .ds-color-picker__preview{width:var(--colorpicker-preview-size-lg, 36px);height:var(--colorpicker-preview-size-lg, 36px)}.ds-color-picker--lg .ds-color-picker__input{font-size:var(--colorpicker-font-size-lg, var(--font-size-4))}.ds-color-picker--lg .ds-color-picker__action{width:var(--colorpicker-action-size-lg, 28px);height:var(--colorpicker-action-size-lg, 28px);font-size:var(--font-size-4)}.ds-color-picker--focused .ds-color-picker__trigger{border-color:var(--color-primary);box-shadow:0 0 0 3px var(--colorpicker-focus-shadow, rgba(59, 130, 246, .25))}.ds-color-picker--open .ds-color-picker__trigger{border-color:var(--color-primary)}.ds-color-picker--disabled{opacity:.6;pointer-events:none;cursor:not-allowed}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FontAwesomeModule }, { kind: "component", type: i1$1.FaIconComponent, selector: "fa-icon", inputs: ["icon", "title", "animation", "mask", "flip", "size", "pull", "border", "inverse", "symbol", "rotate", "fixedWidth", "transform", "a11yRole"], outputs: ["iconChange", "titleChange", "animationChange", "maskChange", "flipChange", "sizeChange", "pullChange", "borderChange", "inverseChange", "symbolChange", "rotateChange", "fixedWidthChange", "transformChange", "a11yRoleChange"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: OverlayModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
12886
+ }
12887
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: DsColorPicker, decorators: [{
12888
+ type: Component,
12889
+ args: [{ selector: 'ds-color-picker', standalone: true, imports: [CommonModule, FontAwesomeModule, FormsModule, OverlayModule], changeDetection: ChangeDetectionStrategy.OnPush, providers: [
12890
+ {
12891
+ provide: NG_VALUE_ACCESSOR,
12892
+ useExisting: forwardRef(() => DsColorPicker),
12893
+ multi: true,
12894
+ },
12895
+ ], template: "<div [class]=\"containerClasses()\">\n <div class=\"ds-color-picker__trigger\" (click)=\"toggle()\">\n <!-- Preview de la couleur -->\n <div\n class=\"ds-color-picker__preview\"\n [style.background-color]=\"previewColor()\"\n [attr.aria-label]=\"'Color: ' + displayValue()\">\n </div>\n\n <!-- Input texte -->\n <input\n type=\"text\"\n class=\"ds-color-picker__input\"\n [value]=\"displayValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n readonly\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n [attr.aria-label]=\"placeholder()\" />\n\n <!-- Actions -->\n <div class=\"ds-color-picker__actions\">\n @if (allowClear() && internalValue()) {\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--clear\"\n [disabled]=\"disabled()\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"'Clear color'\">\n <fa-icon [icon]=\"clearIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n }\n\n <button\n type=\"button\"\n class=\"ds-color-picker__action ds-color-picker__action--picker\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"'Open color picker'\">\n <fa-icon [icon]=\"pickerIcon\" aria-hidden=\"true\"></fa-icon>\n </button>\n </div>\n </div>\n</div>\n", styles: [".ds-color-picker{position:relative;display:inline-flex;width:100%}.ds-color-picker__trigger{position:relative;display:flex;align-items:center;gap:var(--colorpicker-gap, var(--space-2));width:100%;background:var(--colorpicker-bg, var(--background-main));border:1px solid var(--colorpicker-border, var(--border-default));border-radius:var(--colorpicker-radius, var(--radius-2));padding:var(--colorpicker-padding, var(--space-2));cursor:pointer;transition:border-color var(--duration-fast, .15s) ease,box-shadow var(--duration-fast, .15s) ease}.ds-color-picker__trigger:hover:not([disabled]){border-color:var(--colorpicker-border-hover, var(--border-strong))}.ds-color-picker__preview{flex-shrink:0;width:var(--colorpicker-preview-size, 28px);height:var(--colorpicker-preview-size, 28px);border:2px solid var(--colorpicker-preview-border, var(--border-default));border-radius:var(--radius-1);background-image:linear-gradient(45deg,#ccc 25%,transparent 25%),linear-gradient(-45deg,#ccc 25%,transparent 25%),linear-gradient(45deg,transparent 75%,#ccc 75%),linear-gradient(-45deg,transparent 75%,#ccc 75%);background-size:8px 8px;background-position:0 0,0 4px,4px -4px,-4px 0;position:relative}.ds-color-picker__preview:after{content:\"\";position:absolute;inset:0;background-color:currentColor;border-radius:inherit}.ds-color-picker__input{flex:1;min-width:0;background:transparent;border:none;color:var(--colorpicker-text, var(--text-default));font-size:var(--colorpicker-font-size, var(--font-size-3));outline:none;cursor:pointer}.ds-color-picker__input::placeholder{color:var(--colorpicker-placeholder, var(--text-muted))}.ds-color-picker__input:disabled{cursor:not-allowed}.ds-color-picker__actions{display:flex;align-items:center;gap:var(--space-1)}.ds-color-picker__action{display:flex;align-items:center;justify-content:center;width:var(--colorpicker-action-size, 24px);height:var(--colorpicker-action-size, 24px);padding:0;background:transparent;border:none;border-radius:var(--radius-1);color:var(--colorpicker-icon, var(--text-muted));cursor:pointer;transition:background-color var(--duration-fast, .15s) ease,color var(--duration-fast, .15s) ease}.ds-color-picker__action:hover:not(:disabled){background:var(--colorpicker-action-hover-bg, var(--surface-hover));color:var(--text-default)}.ds-color-picker__action:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.ds-color-picker__action:disabled{opacity:.5;cursor:not-allowed}.ds-color-picker__action--clear{color:var(--colorpicker-clear-icon, var(--text-muted))}.ds-color-picker__action--clear:hover:not(:disabled){color:var(--error)}.ds-color-picker--sm .ds-color-picker__trigger{padding:var(--colorpicker-padding-sm, var(--space-1) var(--space-2));height:var(--colorpicker-height-sm, 32px)}.ds-color-picker--sm .ds-color-picker__preview{width:var(--colorpicker-preview-size-sm, 20px);height:var(--colorpicker-preview-size-sm, 20px)}.ds-color-picker--sm .ds-color-picker__input{font-size:var(--colorpicker-font-size-sm, var(--font-size-2))}.ds-color-picker--sm .ds-color-picker__action{width:var(--colorpicker-action-size-sm, 20px);height:var(--colorpicker-action-size-sm, 20px);font-size:var(--font-size-2)}.ds-color-picker--md .ds-color-picker__trigger{padding:var(--colorpicker-padding-md, var(--space-2));height:var(--colorpicker-height-md, 40px)}.ds-color-picker--md .ds-color-picker__preview{width:var(--colorpicker-preview-size-md, 28px);height:var(--colorpicker-preview-size-md, 28px)}.ds-color-picker--md .ds-color-picker__input{font-size:var(--colorpicker-font-size-md, var(--font-size-3))}.ds-color-picker--md .ds-color-picker__action{width:var(--colorpicker-action-size-md, 24px);height:var(--colorpicker-action-size-md, 24px);font-size:var(--font-size-3)}.ds-color-picker--lg .ds-color-picker__trigger{padding:var(--colorpicker-padding-lg, var(--space-3));height:var(--colorpicker-height-lg, 48px)}.ds-color-picker--lg .ds-color-picker__preview{width:var(--colorpicker-preview-size-lg, 36px);height:var(--colorpicker-preview-size-lg, 36px)}.ds-color-picker--lg .ds-color-picker__input{font-size:var(--colorpicker-font-size-lg, var(--font-size-4))}.ds-color-picker--lg .ds-color-picker__action{width:var(--colorpicker-action-size-lg, 28px);height:var(--colorpicker-action-size-lg, 28px);font-size:var(--font-size-4)}.ds-color-picker--focused .ds-color-picker__trigger{border-color:var(--color-primary);box-shadow:0 0 0 3px var(--colorpicker-focus-shadow, rgba(59, 130, 246, .25))}.ds-color-picker--open .ds-color-picker__trigger{border-color:var(--color-primary)}.ds-color-picker--disabled{opacity:.6;pointer-events:none;cursor:not-allowed}\n"] }]
12896
+ }], ctorParameters: () => [{ type: i1$3.Overlay }, { type: i0.ElementRef }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], showAlpha: [{ type: i0.Input, args: [{ isSignal: true, alias: "showAlpha", required: false }] }], presetColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "presetColors", required: false }] }], format: [{ type: i0.Input, args: [{ isSignal: true, alias: "format", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], allowClear: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowClear", required: false }] }], showRecentColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRecentColors", required: false }] }], maxRecentColors: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxRecentColors", required: false }] }], colorChange: [{ type: i0.Output, args: ["colorChange"] }] } });
12897
+
11434
12898
  /*
11435
12899
  * Components barrel export
11436
12900
  */
@@ -12002,5 +13466,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
12002
13466
  * Generated bundle index. Do not edit.
12003
13467
  */
12004
13468
 
12005
- export { AUTOCOMPLETE_POSITIONS, BUTTON_APPEARANCE_OPTIONS, BUTTON_SIZE_OPTIONS, BUTTON_VARIANT_OPTIONS, DROPDOWN_POSITIONS, DsAccordion, DsAlert, DsAvatar, DsBadge, DsBreadcrumb, DsButton, DsCalendar, DsCard, DsCarousel, DsCheckbox, DsChip, DsCombobox, DsContainer, DsDatePicker, DsDivider, DsDrawer, DsDropdown, DsEmpty, DsFileUpload, DsI18nService, DsInputField, DsInputTextarea, DsMenu, DsModalComponent, DsNotificationContainerComponent, DsNotificationItemComponent, DsNotificationService, DsPagination, DsPasswordStrength, DsPopover, DsPopoverComponent, DsProgressBar, DsRadioGroup, DsRating, DsSearchInput, DsSelect, DsSkeleton, DsSlider, DsStepper, DsTable, DsTabs, DsTimePicker, DsTimeline, DsToastComponent, DsToastContainerComponent, DsToastService, DsToggle, DsTooltip, DsTooltipComponent, DsTransfer, DsTree, IconRegistryService, POPOVER_POSITIONS, PrimitiveBadge, PrimitiveButton, PrimitiveCheckbox, PrimitiveInput, PrimitiveRadio, PrimitiveTextarea, PrimitiveToggle, TOOLTIP_POSITIONS, buildButtonArgTypes, buildButtonArgs, createSizeRender, createVariantRender };
13469
+ export { AUTOCOMPLETE_POSITIONS, BUTTON_APPEARANCE_OPTIONS, BUTTON_SIZE_OPTIONS, BUTTON_VARIANT_OPTIONS, DROPDOWN_POSITIONS, DsAccordion, DsAlert, DsAvatar, DsBadge, DsBreadcrumb, DsButton, DsCalendar, DsCard, DsCarousel, DsCheckbox, DsChip, DsColorPicker, DsCombobox, DsContainer, DsDatePicker, DsDivider, DsDrawer, DsDropdown, DsEmpty, DsFileUpload, DsI18nService, DsInputField, DsInputNumber, DsInputTextarea, DsMenu, DsModalComponent, DsNotificationContainerComponent, DsNotificationItemComponent, DsNotificationService, DsPagination, DsPasswordStrength, DsPopover, DsPopoverComponent, DsProgressBar, DsRadioGroup, DsRating, DsSearchInput, DsSegmentedControl, DsSelect, DsSkeleton, DsSlider, DsStepper, DsTable, DsTabs, DsTimePicker, DsTimeline, DsToastComponent, DsToastContainerComponent, DsToastService, DsToggle, DsTooltip, DsTooltipComponent, DsTransfer, DsTree, IconRegistryService, POPOVER_POSITIONS, PrimitiveBadge, PrimitiveButton, PrimitiveCheckbox, PrimitiveInput, PrimitiveRadio, PrimitiveTextarea, PrimitiveToggle, TOOLTIP_POSITIONS, buildButtonArgTypes, buildButtonArgs, createSizeRender, createVariantRender };
12006
13470
  //# sourceMappingURL=kksdev-ds-angular.mjs.map