@lifecorner/angular-ui-kit 3.27.1 → 3.27.2
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.
- package/fesm2022/lifecorner-angular-ui-kit-chat.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-chat.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-datepicker.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-datepicker.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-rich-text-editor.mjs +4 -4
- package/fesm2022/lifecorner-angular-ui-kit-rich-text-editor.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-select.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-select.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs.map +1 -1
- package/package.json +1 -1
- package/src/styles/focus-indicators.spec.ts +6 -3
- package/src/styles/theme-contrast.spec.ts +102 -0
- package/src/styles/touch-targets-contrast.spec.ts +4 -1
|
@@ -387,7 +387,7 @@ var SelectComponent = class SelectComponent {
|
|
|
387
387
|
}],
|
|
388
388
|
ngImport: i0,
|
|
389
389
|
template: "<div class=\"lc-select-wrapper\">\n <div\n #selectTrigger\n [class]=\"selectClasses()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n >\n <div class=\"lc-select__value\">\n <span [class.lc-select__placeholder]=\"!selectedLabel()\">\n {{ displayValue() }}\n </span>\n </div>\n\n <div class=\"lc-select__icons\">\n @if (loading()) {\n <svg\n class=\"lc-select__spinner\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n } @else if (value() && !isDisabled() && !multiple()) {\n <button\n type=\"button\"\n class=\"lc-select__clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n\n <svg\n class=\"lc-select__chevron\"\n [class.lc-select__chevron--open]=\"isOpen()\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Dropdown Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"selectTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div #dropdownPanel class=\"lc-select__dropdown\" [class.lc-select__dropdown--open]=\"isOpen()\">\n @if (searchable()) {\n <div class=\"lc-select__search\">\n <input\n type=\"text\"\n class=\"lc-select__search-input\"\n [placeholder]=\"searchPlaceholder()\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"searchAriaLabel() || (ariaLabel() ? 'Search ' + ariaLabel() : 'Search options')\"\n [(ngModel)]=\"searchQuery\"\n (keydown)=\"onKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div\n class=\"lc-select__options\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-multiselectable]=\"multiple() ? 'true' : null\"\n >\n @if (filteredOptions().length === 0) {\n <div\n class=\"lc-select__option lc-select__option--no-results\"\n role=\"option\"\n aria-disabled=\"true\"\n aria-selected=\"false\"\n >\n {{ noOptionsLabel() }}\n </div>\n } @else {\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays on the trigger/search, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-select__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(option) ? 'true' : 'false'\"\n [attr.aria-disabled]=\"option.disabled ? 'true' : null\"\n [class.lc-select__option--selected]=\"isSelected(option)\"\n [class.lc-select__option--highlighted]=\"highlightedIndex() === i\"\n [class.lc-select__option--disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n >\n @if (multiple()) {\n <!-- Purely visual: the option itself carries the selected state (role=option\n + aria-selected); the checkbox is inert so clicks land on the option. -->\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n class=\"lc-select__checkbox\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n />\n }\n <span class=\"lc-select__option-label\">{{ option.label }}</span>\n @if (isSelected(option) && !multiple()) {\n <svg\n class=\"lc-select__check\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n }\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-select__error\" [id]=\"selectId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-select__helper\" [id]=\"selectId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n",
|
|
390
|
-
styles: [".lc-select-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-select{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface-2);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:pointer;-webkit-user-select:none;user-select:none}.lc-select:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus){border-color:var(--color-text-secondary)}.lc-select:focus,.lc-select:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-select.lc-select--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-8);font-size:var(--size-interactive-xs-font-size)}.lc-select.lc-select--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-9);font-size:var(--size-interactive-sm-font-size)}.lc-select.lc-select--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-md-font-size)}.lc-select.lc-select--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-lg-font-size)}.lc-select.lc-select--filled{background-color:var(--color-surface-sunken);border-color:
|
|
390
|
+
styles: [".lc-select-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-select{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface-2);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:pointer;-webkit-user-select:none;user-select:none}.lc-select:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus){border-color:var(--color-text-secondary)}.lc-select:focus,.lc-select:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-select.lc-select--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-8);font-size:var(--size-interactive-xs-font-size)}.lc-select.lc-select--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-9);font-size:var(--size-interactive-sm-font-size)}.lc-select.lc-select--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-md-font-size)}.lc-select.lc-select--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-lg-font-size)}.lc-select.lc-select--filled{background-color:var(--color-surface-sunken);border-color:var(--color-field-border)}.lc-select.lc-select--filled:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-text-secondary)}.lc-select.lc-select--filled:focus,.lc-select.lc-select--filled:focus-visible{background-color:var(--color-surface);border-color:var(--color-primary-500)}.lc-select.lc-select--error{border-color:var(--color-error-600)}.lc-select.lc-select--error:focus,.lc-select.lc-select--error:focus-visible{outline-color:var(--color-error-600);border-color:var(--color-error-600)}.lc-select.lc-select--disabled{background-color:var(--color-surface-muted);border-color:var(--color-border);cursor:not-allowed;opacity:.6}.lc-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-select__placeholder{color:var(--color-text-secondary)}.lc-select__icons{position:absolute;right:var(--spacing-3);display:flex;align-items:center;gap:var(--spacing-1);flex-shrink:0;pointer-events:none}.lc-select__icons button{pointer-events:auto}.lc-select__spinner{width:1.25rem;height:1.25rem;color:var(--color-text-secondary);animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.lc-select__clear{position:relative;display:var(--lc-select-clear-display, flex);align-items:center;justify-content:center;width:1.5rem;height:1.5rem;margin:-.125rem;padding:.125rem;background:none;background-clip:content-box;border:none;border-radius:calc(var(--border-radius-sm) + .125rem);color:var(--lc-select-clear-fg, var(--color-text-secondary));cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-select__clear:hover{color:var(--lc-select-clear-hover-fg, var(--color-text-primary));background-color:var(--lc-select-clear-hover-bg, var(--color-surface-hover))}.lc-select__clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0}.lc-select__clear svg{width:1rem;height:1rem}.lc-select__chevron{width:1.25rem;height:1.25rem;color:var(--color-text-secondary);transition:transform var(--animation-duration-base) var(--animation-timing-ease)}.lc-select__chevron.lc-select__chevron--open{transform:rotate(180deg)}.lc-select__dropdown{position:absolute;z-index:1000;margin-top:var(--spacing-1);padding:var(--lc-density-padding-xs, var(--spacing-2));background-color:var(--color-surface);background-image:var(--gradient-surface);border:1px solid var(--color-border-strong);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-4);min-width:200px;max-height:320px;overflow-y:auto;opacity:0;transform:translateY(-8px);transition:all var(--animation-duration-base) var(--animation-timing-ease);pointer-events:none}.lc-select__dropdown.lc-select__dropdown--open{opacity:1;transform:translateY(0);pointer-events:auto}.lc-select__dropdown::-webkit-scrollbar{width:8px}.lc-select__dropdown::-webkit-scrollbar-track{background:var(--color-surface-sunken);border-radius:var(--border-radius-md)}.lc-select__dropdown::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:var(--border-radius-md)}.lc-select__dropdown::-webkit-scrollbar-thumb:hover{background:var(--color-border-strong)}.lc-select__search{padding:var(--lc-density-padding-xs, var(--spacing-2));border-bottom:1px solid var(--color-border);margin-bottom:var(--spacing-2)}.lc-select__search-input{width:100%;padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-md);outline:none;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-select__search-input:focus{border-color:var(--color-primary-500)}.lc-select__search-input::placeholder{color:var(--color-text-secondary)}.lc-select__options{list-style:none;padding:0;margin:0}.lc-select__option{display:flex;align-items:center;padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));font-size:var(--font-size-sm);color:var(--color-text-primary);background:none;border:none;border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease);text-align:left;width:100%}.lc-select__option:hover:not(.lc-select__option--disabled){background-color:var(--color-surface-hover)}.lc-select__option.lc-select__option--selected{font-weight:var(--font-weight-semibold);color:var(--color-primary-600);background-color:var(--color-primary-50)}.lc-select__option.lc-select__option--highlighted{background-color:var(--color-surface-hover);outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-select__option.lc-select__option--disabled{color:var(--color-text-disabled);cursor:not-allowed;opacity:.5}.lc-select__option-label{flex:1}.lc-select__check{width:1rem;height:1rem;margin-left:var(--spacing-2);flex-shrink:0;color:var(--color-primary-600)}.lc-select__checkbox{margin-right:var(--spacing-2);width:1rem;height:1rem;pointer-events:none}.lc-select__empty{padding:var(--lc-density-padding-md, var(--spacing-4));text-align:center;font-size:var(--font-size-sm);color:var(--color-text-secondary)}.lc-select__error{font-size:var(--font-size-xs);color:var(--color-error-600);margin-top:var(--spacing-1)}.lc-select__helper{font-size:var(--font-size-xs);color:var(--color-text-secondary);margin-top:var(--spacing-1)}@media(forced-colors:active){.lc-select__option.lc-select__option--highlighted{outline-color:Highlight}.lc-select__clear:focus-visible{outline-color:Highlight}}\n"],
|
|
391
391
|
dependencies: [
|
|
392
392
|
{
|
|
393
393
|
kind: "ngmodule",
|
|
@@ -483,7 +483,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
483
483
|
multi: true
|
|
484
484
|
}],
|
|
485
485
|
template: "<div class=\"lc-select-wrapper\">\n <div\n #selectTrigger\n [class]=\"selectClasses()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n >\n <div class=\"lc-select__value\">\n <span [class.lc-select__placeholder]=\"!selectedLabel()\">\n {{ displayValue() }}\n </span>\n </div>\n\n <div class=\"lc-select__icons\">\n @if (loading()) {\n <svg\n class=\"lc-select__spinner\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n } @else if (value() && !isDisabled() && !multiple()) {\n <button\n type=\"button\"\n class=\"lc-select__clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n\n <svg\n class=\"lc-select__chevron\"\n [class.lc-select__chevron--open]=\"isOpen()\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Dropdown Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"selectTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div #dropdownPanel class=\"lc-select__dropdown\" [class.lc-select__dropdown--open]=\"isOpen()\">\n @if (searchable()) {\n <div class=\"lc-select__search\">\n <input\n type=\"text\"\n class=\"lc-select__search-input\"\n [placeholder]=\"searchPlaceholder()\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"searchAriaLabel() || (ariaLabel() ? 'Search ' + ariaLabel() : 'Search options')\"\n [(ngModel)]=\"searchQuery\"\n (keydown)=\"onKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div\n class=\"lc-select__options\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-multiselectable]=\"multiple() ? 'true' : null\"\n >\n @if (filteredOptions().length === 0) {\n <div\n class=\"lc-select__option lc-select__option--no-results\"\n role=\"option\"\n aria-disabled=\"true\"\n aria-selected=\"false\"\n >\n {{ noOptionsLabel() }}\n </div>\n } @else {\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays on the trigger/search, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-select__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(option) ? 'true' : 'false'\"\n [attr.aria-disabled]=\"option.disabled ? 'true' : null\"\n [class.lc-select__option--selected]=\"isSelected(option)\"\n [class.lc-select__option--highlighted]=\"highlightedIndex() === i\"\n [class.lc-select__option--disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n >\n @if (multiple()) {\n <!-- Purely visual: the option itself carries the selected state (role=option\n + aria-selected); the checkbox is inert so clicks land on the option. -->\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n class=\"lc-select__checkbox\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n />\n }\n <span class=\"lc-select__option-label\">{{ option.label }}</span>\n @if (isSelected(option) && !multiple()) {\n <svg\n class=\"lc-select__check\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n }\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-select__error\" [id]=\"selectId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-select__helper\" [id]=\"selectId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n",
|
|
486
|
-
styles: [".lc-select-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-select{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface-2);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:pointer;-webkit-user-select:none;user-select:none}.lc-select:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus){border-color:var(--color-text-secondary)}.lc-select:focus,.lc-select:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-select.lc-select--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-8);font-size:var(--size-interactive-xs-font-size)}.lc-select.lc-select--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-9);font-size:var(--size-interactive-sm-font-size)}.lc-select.lc-select--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-md-font-size)}.lc-select.lc-select--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-lg-font-size)}.lc-select.lc-select--filled{background-color:var(--color-surface-sunken);border-color:
|
|
486
|
+
styles: [".lc-select-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-select{position:relative;display:flex;align-items:center;justify-content:space-between;width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface-2);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:pointer;-webkit-user-select:none;user-select:none}.lc-select:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus){border-color:var(--color-text-secondary)}.lc-select:focus,.lc-select:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-select.lc-select--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-8);font-size:var(--size-interactive-xs-font-size)}.lc-select.lc-select--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-9);font-size:var(--size-interactive-sm-font-size)}.lc-select.lc-select--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-md-font-size)}.lc-select.lc-select--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-lg-font-size)}.lc-select.lc-select--filled{background-color:var(--color-surface-sunken);border-color:var(--color-field-border)}.lc-select.lc-select--filled:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-text-secondary)}.lc-select.lc-select--filled:focus,.lc-select.lc-select--filled:focus-visible{background-color:var(--color-surface);border-color:var(--color-primary-500)}.lc-select.lc-select--error{border-color:var(--color-error-600)}.lc-select.lc-select--error:focus,.lc-select.lc-select--error:focus-visible{outline-color:var(--color-error-600);border-color:var(--color-error-600)}.lc-select.lc-select--disabled{background-color:var(--color-surface-muted);border-color:var(--color-border);cursor:not-allowed;opacity:.6}.lc-select__value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-select__placeholder{color:var(--color-text-secondary)}.lc-select__icons{position:absolute;right:var(--spacing-3);display:flex;align-items:center;gap:var(--spacing-1);flex-shrink:0;pointer-events:none}.lc-select__icons button{pointer-events:auto}.lc-select__spinner{width:1.25rem;height:1.25rem;color:var(--color-text-secondary);animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.lc-select__clear{position:relative;display:var(--lc-select-clear-display, flex);align-items:center;justify-content:center;width:1.5rem;height:1.5rem;margin:-.125rem;padding:.125rem;background:none;background-clip:content-box;border:none;border-radius:calc(var(--border-radius-sm) + .125rem);color:var(--lc-select-clear-fg, var(--color-text-secondary));cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-select__clear:hover{color:var(--lc-select-clear-hover-fg, var(--color-text-primary));background-color:var(--lc-select-clear-hover-bg, var(--color-surface-hover))}.lc-select__clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0}.lc-select__clear svg{width:1rem;height:1rem}.lc-select__chevron{width:1.25rem;height:1.25rem;color:var(--color-text-secondary);transition:transform var(--animation-duration-base) var(--animation-timing-ease)}.lc-select__chevron.lc-select__chevron--open{transform:rotate(180deg)}.lc-select__dropdown{position:absolute;z-index:1000;margin-top:var(--spacing-1);padding:var(--lc-density-padding-xs, var(--spacing-2));background-color:var(--color-surface);background-image:var(--gradient-surface);border:1px solid var(--color-border-strong);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-4);min-width:200px;max-height:320px;overflow-y:auto;opacity:0;transform:translateY(-8px);transition:all var(--animation-duration-base) var(--animation-timing-ease);pointer-events:none}.lc-select__dropdown.lc-select__dropdown--open{opacity:1;transform:translateY(0);pointer-events:auto}.lc-select__dropdown::-webkit-scrollbar{width:8px}.lc-select__dropdown::-webkit-scrollbar-track{background:var(--color-surface-sunken);border-radius:var(--border-radius-md)}.lc-select__dropdown::-webkit-scrollbar-thumb{background:var(--color-border);border-radius:var(--border-radius-md)}.lc-select__dropdown::-webkit-scrollbar-thumb:hover{background:var(--color-border-strong)}.lc-select__search{padding:var(--lc-density-padding-xs, var(--spacing-2));border-bottom:1px solid var(--color-border);margin-bottom:var(--spacing-2)}.lc-select__search-input{width:100%;padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-sm);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-md);outline:none;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-select__search-input:focus{border-color:var(--color-primary-500)}.lc-select__search-input::placeholder{color:var(--color-text-secondary)}.lc-select__options{list-style:none;padding:0;margin:0}.lc-select__option{display:flex;align-items:center;padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));font-size:var(--font-size-sm);color:var(--color-text-primary);background:none;border:none;border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease);text-align:left;width:100%}.lc-select__option:hover:not(.lc-select__option--disabled){background-color:var(--color-surface-hover)}.lc-select__option.lc-select__option--selected{font-weight:var(--font-weight-semibold);color:var(--color-primary-600);background-color:var(--color-primary-50)}.lc-select__option.lc-select__option--highlighted{background-color:var(--color-surface-hover);outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-select__option.lc-select__option--disabled{color:var(--color-text-disabled);cursor:not-allowed;opacity:.5}.lc-select__option-label{flex:1}.lc-select__check{width:1rem;height:1rem;margin-left:var(--spacing-2);flex-shrink:0;color:var(--color-primary-600)}.lc-select__checkbox{margin-right:var(--spacing-2);width:1rem;height:1rem;pointer-events:none}.lc-select__empty{padding:var(--lc-density-padding-md, var(--spacing-4));text-align:center;font-size:var(--font-size-sm);color:var(--color-text-secondary)}.lc-select__error{font-size:var(--font-size-xs);color:var(--color-error-600);margin-top:var(--spacing-1)}.lc-select__helper{font-size:var(--font-size-xs);color:var(--color-text-secondary);margin-top:var(--spacing-1)}@media(forced-colors:active){.lc-select__option.lc-select__option--highlighted{outline-color:Highlight}.lc-select__clear:focus-visible{outline-color:Highlight}}\n"]
|
|
487
487
|
}]
|
|
488
488
|
}],
|
|
489
489
|
propDecorators: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-select.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/select/select.component.ts","../../../../libs/angular-ui-kit/src/lib/select/select.component.html"],"sourcesContent":["import {\n Component,\n input,\n output,\n signal,\n computed,\n linkedSignal,\n ChangeDetectionStrategy,\n forwardRef,\n ElementRef,\n viewChild,\n inject,\n DOCUMENT,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\n\nexport interface SelectOption {\n value: string | number;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectOptionGroup {\n label: string;\n options: SelectOption[];\n}\n\nexport type SelectValue = string | number | string[] | number[] | null;\n\n/**\n * Select component for dropdown option selection.\n *\n * Features:\n * - Single and multiple selection modes\n * - Searchable/filterable option list\n * - Option groups with headers\n * - Loading state indicator\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Keyboard navigation support\n * - CDK overlay positioning\n * - ControlValueAccessor integration for reactive forms\n *\n * @example\n * ```html\n * <lc-select [options]=\"options\" placeholder=\"Choose\" [(ngModel)]=\"selected\" />\n * ```\n */\n@Component({\n selector: 'lc-select',\n standalone: true,\n imports: [FormsModule, OverlayModule],\n templateUrl: './select.component.html',\n styleUrl: './select.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => SelectComponent),\n multi: true,\n },\n ],\n})\nexport class SelectComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance id base; the listbox and its options derive their ids from it. */\n readonly selectId = `lc-select-${++SelectComponent.nextId}`;\n readonly listboxId = `${this.selectId}-listbox`;\n\n private readonly selectTrigger = viewChild<ElementRef<HTMLElement>>('selectTrigger');\n private readonly dropdownPanel = viewChild<ElementRef<HTMLElement>>('dropdownPanel');\n\n /**\n * Visual variant of the select\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the select\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the select is disabled\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the select is in error state\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the select is required\n */\n readonly required = input<boolean>(false);\n\n /**\n * Whether the select is in loading state\n */\n readonly loading = input<boolean>(false);\n\n /**\n * Whether the select allows searching\n */\n readonly searchable = input<boolean>(false);\n\n /**\n * Whether multiple options can be selected\n */\n readonly multiple = input<boolean>(false);\n\n /**\n * Placeholder text when no option is selected\n */\n readonly placeholder = input<string>('Select an option');\n\n /**\n * Helper text displayed below the select\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Select options (flat list or groups)\n */\n readonly options = input<SelectOption[] | SelectOptionGroup[]>([]);\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear selection');\n\n /** Placeholder of the search field (`searchable`). */\n readonly searchPlaceholder = input('Search...');\n\n /** Accessible name of the search field. Empty: \"Search \" + `ariaLabel`, or \"Search options\". */\n readonly searchAriaLabel = input('');\n\n /** Shown when the search matches no option. */\n readonly noOptionsLabel = input('No options found');\n\n /**\n * Emitted when selection changes\n */\n readonly selectionChange = output<SelectValue>();\n\n /**\n * Emitted when dropdown opens\n */\n readonly opened = output<void>();\n\n /**\n * Emitted when dropdown closes\n */\n readonly closed = output<void>();\n\n // Internal state\n readonly value = signal<SelectValue>(null);\n readonly isOpen = signal<boolean>(false);\n readonly searchQuery = signal<string>('');\n\n /** Disabled state pushed in by the forms API (setDisabledState). */\n private readonly formDisabled = signal<boolean>(false);\n\n /** Effective disabled state: the `disabled` input OR the form control's disabled state. */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly filteredOptions = computed(() => {\n const query = this.searchQuery().toLowerCase();\n const opts = this.options();\n\n if (!query || !this.searchable()) {\n return this.flattenOptions(opts);\n }\n\n return this.flattenOptions(opts).filter((opt) => opt.label.toLowerCase().includes(query));\n });\n\n /** Keyboard highlight; resets whenever the visible option list changes so it never points at a stale row. */\n readonly highlightedIndex = linkedSignal<SelectOption[], number>({\n source: this.filteredOptions,\n computation: () => -1,\n });\n\n readonly activeDescendantId = computed(() => {\n const index = this.highlightedIndex();\n return this.isOpen() && index >= 0 ? this.optionId(index) : null;\n });\n\n readonly selectedLabel = computed(() => {\n const currentValue = this.value();\n const opts = this.options();\n\n if (currentValue === null) {\n return '';\n }\n\n if (this.multiple()) {\n const values = Array.isArray(currentValue) ? currentValue : [currentValue];\n return values\n .map((val) => this.findOptionByValue(val, opts)?.label)\n .filter(Boolean)\n .join(', ');\n }\n\n const val = Array.isArray(currentValue) ? currentValue[0] : currentValue;\n return this.findOptionByValue(val ?? '', opts)?.label || '';\n });\n\n readonly displayValue = computed(() => {\n const label = this.selectedLabel();\n if (label) {\n const currentValue = this.value();\n if (this.multiple() && Array.isArray(currentValue)) {\n const count = currentValue.length;\n return count > 1 ? `${count} selected` : label;\n }\n return label;\n }\n return this.placeholder();\n });\n\n /** id of the helper/error text the trigger is described by (aria-describedby) */\n readonly describedBy = computed(() => {\n if (this.error() && this.errorMessage()) {\n return `${this.selectId}-error`;\n }\n return this.helperText() ? `${this.selectId}-helper` : null;\n });\n\n /**\n * Computed classes for the select trigger element\n */\n readonly selectClasses = computed(() => {\n const classes = ['lc-select', `lc-select--${this.variant()}`, `lc-select--${this.size()}`];\n\n if (this.isDisabled()) {\n classes.push('lc-select--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-select--error');\n }\n\n if (this.loading()) {\n classes.push('lc-select--loading');\n }\n\n if (this.isOpen()) {\n classes.push('lc-select--open');\n }\n\n return classes.join(' ');\n });\n\n // Private properties\n private readonly document = inject(DOCUMENT);\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: SelectValue) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n // Public methods\n /**\n * Id of the option at `index` in the filtered list (used for aria-activedescendant)\n */\n optionId(index: number): string {\n return `${this.selectId}-option-${index}`;\n }\n\n /**\n * Toggle dropdown open/closed\n */\n toggle(): void {\n if (this.isDisabled() || this.loading()) {\n return;\n }\n if (this.isOpen()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Open dropdown\n */\n open(): void {\n if (this.isDisabled() || this.loading() || this.isOpen()) {\n return;\n }\n this.isOpen.set(true);\n this.opened.emit();\n }\n\n /**\n * Close dropdown. Idempotent: the overlay's `detach` re-enters here after\n * `isOpen` flips, and that second call must not emit `closed` again.\n */\n close(): void {\n if (!this.isOpen()) {\n return;\n }\n // If focus is inside the panel (search input) it would fall to <body> when the\n // overlay is torn down; hand it back to the trigger first.\n this.restoreFocusFromPanel();\n this.isOpen.set(false);\n this.searchQuery.set('');\n this.highlightedIndex.set(-1);\n this.closed.emit();\n }\n\n /**\n * Select an option\n */\n selectOption(option: SelectOption): void {\n if (option.disabled) {\n return;\n }\n\n if (this.multiple()) {\n const currentValue = this.value() || [];\n const currentArray = (Array.isArray(currentValue) ? currentValue : []) as (string | number)[];\n const index = currentArray.indexOf(option.value);\n\n const newValue = (\n index > -1\n ? currentArray.filter((v) => v !== option.value) // Deselect\n : [...currentArray, option.value] // Select\n ) as SelectValue;\n this.value.set(newValue);\n this.onChange(newValue);\n this.selectionChange.emit(newValue);\n } else {\n this.value.set(option.value);\n this.onChange(option.value);\n this.selectionChange.emit(option.value);\n this.close();\n }\n }\n\n /**\n * Check if an option is selected\n */\n isSelected(option: SelectOption): boolean {\n const currentValue = this.value();\n if (this.multiple()) {\n const values = Array.isArray(currentValue) ? currentValue : [];\n return values.some((v) => v === option.value);\n }\n return currentValue === option.value;\n }\n\n /**\n * Clear selection\n */\n clear(): void {\n if (this.multiple()) {\n this.value.set([]);\n this.onChange([]);\n } else {\n this.value.set(null);\n this.onChange(null);\n }\n this.selectionChange.emit(this.value());\n }\n\n /**\n * Handle keyboard navigation (trigger and search input share this handler)\n */\n onKeyDown(event: KeyboardEvent): void {\n if (this.isDisabled() || this.loading()) {\n return;\n }\n\n switch (event.key) {\n case ' ':\n case 'Enter':\n // Space must keep typing into the search box.\n if (event.key === ' ' && this.isSearchInput(event.target)) {\n return;\n }\n if (!this.isOpen()) {\n this.open();\n } else {\n const option = this.filteredOptions()[this.highlightedIndex()];\n if (option) {\n this.selectOption(option);\n }\n }\n event.preventDefault();\n break;\n\n case 'Escape':\n if (this.isOpen()) {\n this.close();\n event.preventDefault();\n // Only this select should react; keep the key from reaching enclosing overlays.\n event.stopPropagation();\n }\n break;\n\n case 'ArrowDown':\n if (!this.isOpen()) {\n this.open();\n } else {\n const count = this.filteredOptions().length;\n if (count > 0) {\n this.highlightedIndex.set((this.highlightedIndex() + 1) % count);\n }\n }\n event.preventDefault();\n break;\n\n case 'ArrowUp':\n if (!this.isOpen()) {\n this.open();\n } else {\n const count = this.filteredOptions().length;\n if (count > 0) {\n const current = this.highlightedIndex();\n this.highlightedIndex.set(current <= 0 ? count - 1 : current - 1);\n }\n }\n event.preventDefault();\n break;\n\n case 'Home':\n if (this.isOpen() && this.filteredOptions().length > 0) {\n this.highlightedIndex.set(0);\n event.preventDefault();\n }\n break;\n\n case 'End':\n if (this.isOpen() && this.filteredOptions().length > 0) {\n this.highlightedIndex.set(this.filteredOptions().length - 1);\n event.preventDefault();\n }\n break;\n }\n }\n\n /**\n * Handle blur event\n */\n onBlur(): void {\n this.onTouched();\n }\n\n /**\n * Handle click outside\n */\n onClickOutside(): void {\n this.close();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: SelectValue): void {\n this.value.set(value);\n }\n\n registerOnChange(fn: (value: SelectValue) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n // Private helper methods\n private isSearchInput(target: EventTarget | null): boolean {\n return target instanceof HTMLInputElement;\n }\n\n private restoreFocusFromPanel(): void {\n const panel = this.dropdownPanel()?.nativeElement;\n const active = this.document.activeElement;\n if (panel && active && panel.contains(active)) {\n this.selectTrigger()?.nativeElement.focus();\n }\n }\n\n private findOptionByValue(\n value: string | number,\n options: SelectOption[] | SelectOptionGroup[],\n ): SelectOption | undefined {\n const flatOptions = this.flattenOptions(options);\n return flatOptions.find((opt) => opt.value === value);\n }\n\n private flattenOptions(options: SelectOption[] | SelectOptionGroup[]): SelectOption[] {\n if (!options || options.length === 0) {\n return [];\n }\n\n // Check if first item is a group\n const firstItem = options[0];\n if (firstItem && 'options' in firstItem) {\n return (options as SelectOptionGroup[]).flatMap((group) => group.options);\n }\n\n return options as SelectOption[];\n }\n}\n","<div class=\"lc-select-wrapper\">\n <div\n #selectTrigger\n [class]=\"selectClasses()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n >\n <div class=\"lc-select__value\">\n <span [class.lc-select__placeholder]=\"!selectedLabel()\">\n {{ displayValue() }}\n </span>\n </div>\n\n <div class=\"lc-select__icons\">\n @if (loading()) {\n <svg\n class=\"lc-select__spinner\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n } @else if (value() && !isDisabled() && !multiple()) {\n <button\n type=\"button\"\n class=\"lc-select__clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n\n <svg\n class=\"lc-select__chevron\"\n [class.lc-select__chevron--open]=\"isOpen()\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Dropdown Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"selectTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div #dropdownPanel class=\"lc-select__dropdown\" [class.lc-select__dropdown--open]=\"isOpen()\">\n @if (searchable()) {\n <div class=\"lc-select__search\">\n <input\n type=\"text\"\n class=\"lc-select__search-input\"\n [placeholder]=\"searchPlaceholder()\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"searchAriaLabel() || (ariaLabel() ? 'Search ' + ariaLabel() : 'Search options')\"\n [(ngModel)]=\"searchQuery\"\n (keydown)=\"onKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div\n class=\"lc-select__options\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-multiselectable]=\"multiple() ? 'true' : null\"\n >\n @if (filteredOptions().length === 0) {\n <div\n class=\"lc-select__option lc-select__option--no-results\"\n role=\"option\"\n aria-disabled=\"true\"\n aria-selected=\"false\"\n >\n {{ noOptionsLabel() }}\n </div>\n } @else {\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays on the trigger/search, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-select__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(option) ? 'true' : 'false'\"\n [attr.aria-disabled]=\"option.disabled ? 'true' : null\"\n [class.lc-select__option--selected]=\"isSelected(option)\"\n [class.lc-select__option--highlighted]=\"highlightedIndex() === i\"\n [class.lc-select__option--disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n >\n @if (multiple()) {\n <!-- Purely visual: the option itself carries the selected state (role=option\n + aria-selected); the checkbox is inert so clicks land on the option. -->\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n class=\"lc-select__checkbox\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n />\n }\n <span class=\"lc-select__option-label\">{{ option.label }}</span>\n @if (isSelected(option) && !multiple()) {\n <svg\n class=\"lc-select__check\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n }\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-select__error\" [id]=\"selectId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-select__helper\" [id]=\"selectId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-select.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/select/select.component.ts","../../../../libs/angular-ui-kit/src/lib/select/select.component.html"],"sourcesContent":["import {\n Component,\n input,\n output,\n signal,\n computed,\n linkedSignal,\n ChangeDetectionStrategy,\n forwardRef,\n ElementRef,\n viewChild,\n inject,\n DOCUMENT,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\n\nexport interface SelectOption {\n value: string | number;\n label: string;\n disabled?: boolean;\n}\n\nexport interface SelectOptionGroup {\n label: string;\n options: SelectOption[];\n}\n\nexport type SelectValue = string | number | string[] | number[] | null;\n\n/**\n * Select component for dropdown option selection.\n *\n * Features:\n * - Single and multiple selection modes\n * - Searchable/filterable option list\n * - Option groups with headers\n * - Loading state indicator\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Keyboard navigation support\n * - CDK overlay positioning\n * - ControlValueAccessor integration for reactive forms\n *\n * @example\n * ```html\n * <lc-select [options]=\"options\" placeholder=\"Choose\" [(ngModel)]=\"selected\" />\n * ```\n */\n@Component({\n selector: 'lc-select',\n standalone: true,\n imports: [FormsModule, OverlayModule],\n templateUrl: './select.component.html',\n styleUrl: './select.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => SelectComponent),\n multi: true,\n },\n ],\n})\nexport class SelectComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance id base; the listbox and its options derive their ids from it. */\n readonly selectId = `lc-select-${++SelectComponent.nextId}`;\n readonly listboxId = `${this.selectId}-listbox`;\n\n private readonly selectTrigger = viewChild<ElementRef<HTMLElement>>('selectTrigger');\n private readonly dropdownPanel = viewChild<ElementRef<HTMLElement>>('dropdownPanel');\n\n /**\n * Visual variant of the select\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the select\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the select is disabled\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the select is in error state\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the select is required\n */\n readonly required = input<boolean>(false);\n\n /**\n * Whether the select is in loading state\n */\n readonly loading = input<boolean>(false);\n\n /**\n * Whether the select allows searching\n */\n readonly searchable = input<boolean>(false);\n\n /**\n * Whether multiple options can be selected\n */\n readonly multiple = input<boolean>(false);\n\n /**\n * Placeholder text when no option is selected\n */\n readonly placeholder = input<string>('Select an option');\n\n /**\n * Helper text displayed below the select\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Select options (flat list or groups)\n */\n readonly options = input<SelectOption[] | SelectOptionGroup[]>([]);\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear selection');\n\n /** Placeholder of the search field (`searchable`). */\n readonly searchPlaceholder = input('Search...');\n\n /** Accessible name of the search field. Empty: \"Search \" + `ariaLabel`, or \"Search options\". */\n readonly searchAriaLabel = input('');\n\n /** Shown when the search matches no option. */\n readonly noOptionsLabel = input('No options found');\n\n /**\n * Emitted when selection changes\n */\n readonly selectionChange = output<SelectValue>();\n\n /**\n * Emitted when dropdown opens\n */\n readonly opened = output<void>();\n\n /**\n * Emitted when dropdown closes\n */\n readonly closed = output<void>();\n\n // Internal state\n readonly value = signal<SelectValue>(null);\n readonly isOpen = signal<boolean>(false);\n readonly searchQuery = signal<string>('');\n\n /** Disabled state pushed in by the forms API (setDisabledState). */\n private readonly formDisabled = signal<boolean>(false);\n\n /** Effective disabled state: the `disabled` input OR the form control's disabled state. */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly filteredOptions = computed(() => {\n const query = this.searchQuery().toLowerCase();\n const opts = this.options();\n\n if (!query || !this.searchable()) {\n return this.flattenOptions(opts);\n }\n\n return this.flattenOptions(opts).filter((opt) => opt.label.toLowerCase().includes(query));\n });\n\n /** Keyboard highlight; resets whenever the visible option list changes so it never points at a stale row. */\n readonly highlightedIndex = linkedSignal<SelectOption[], number>({\n source: this.filteredOptions,\n computation: () => -1,\n });\n\n readonly activeDescendantId = computed(() => {\n const index = this.highlightedIndex();\n return this.isOpen() && index >= 0 ? this.optionId(index) : null;\n });\n\n readonly selectedLabel = computed(() => {\n const currentValue = this.value();\n const opts = this.options();\n\n if (currentValue === null) {\n return '';\n }\n\n if (this.multiple()) {\n const values = Array.isArray(currentValue) ? currentValue : [currentValue];\n return values\n .map((val) => this.findOptionByValue(val, opts)?.label)\n .filter(Boolean)\n .join(', ');\n }\n\n const val = Array.isArray(currentValue) ? currentValue[0] : currentValue;\n return this.findOptionByValue(val ?? '', opts)?.label || '';\n });\n\n readonly displayValue = computed(() => {\n const label = this.selectedLabel();\n if (label) {\n const currentValue = this.value();\n if (this.multiple() && Array.isArray(currentValue)) {\n const count = currentValue.length;\n return count > 1 ? `${count} selected` : label;\n }\n return label;\n }\n return this.placeholder();\n });\n\n /** id of the helper/error text the trigger is described by (aria-describedby) */\n readonly describedBy = computed(() => {\n if (this.error() && this.errorMessage()) {\n return `${this.selectId}-error`;\n }\n return this.helperText() ? `${this.selectId}-helper` : null;\n });\n\n /**\n * Computed classes for the select trigger element\n */\n readonly selectClasses = computed(() => {\n const classes = ['lc-select', `lc-select--${this.variant()}`, `lc-select--${this.size()}`];\n\n if (this.isDisabled()) {\n classes.push('lc-select--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-select--error');\n }\n\n if (this.loading()) {\n classes.push('lc-select--loading');\n }\n\n if (this.isOpen()) {\n classes.push('lc-select--open');\n }\n\n return classes.join(' ');\n });\n\n // Private properties\n private readonly document = inject(DOCUMENT);\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: SelectValue) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n // Public methods\n /**\n * Id of the option at `index` in the filtered list (used for aria-activedescendant)\n */\n optionId(index: number): string {\n return `${this.selectId}-option-${index}`;\n }\n\n /**\n * Toggle dropdown open/closed\n */\n toggle(): void {\n if (this.isDisabled() || this.loading()) {\n return;\n }\n if (this.isOpen()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Open dropdown\n */\n open(): void {\n if (this.isDisabled() || this.loading() || this.isOpen()) {\n return;\n }\n this.isOpen.set(true);\n this.opened.emit();\n }\n\n /**\n * Close dropdown. Idempotent: the overlay's `detach` re-enters here after\n * `isOpen` flips, and that second call must not emit `closed` again.\n */\n close(): void {\n if (!this.isOpen()) {\n return;\n }\n // If focus is inside the panel (search input) it would fall to <body> when the\n // overlay is torn down; hand it back to the trigger first.\n this.restoreFocusFromPanel();\n this.isOpen.set(false);\n this.searchQuery.set('');\n this.highlightedIndex.set(-1);\n this.closed.emit();\n }\n\n /**\n * Select an option\n */\n selectOption(option: SelectOption): void {\n if (option.disabled) {\n return;\n }\n\n if (this.multiple()) {\n const currentValue = this.value() || [];\n const currentArray = (Array.isArray(currentValue) ? currentValue : []) as (string | number)[];\n const index = currentArray.indexOf(option.value);\n\n const newValue = (\n index > -1\n ? currentArray.filter((v) => v !== option.value) // Deselect\n : [...currentArray, option.value] // Select\n ) as SelectValue;\n this.value.set(newValue);\n this.onChange(newValue);\n this.selectionChange.emit(newValue);\n } else {\n this.value.set(option.value);\n this.onChange(option.value);\n this.selectionChange.emit(option.value);\n this.close();\n }\n }\n\n /**\n * Check if an option is selected\n */\n isSelected(option: SelectOption): boolean {\n const currentValue = this.value();\n if (this.multiple()) {\n const values = Array.isArray(currentValue) ? currentValue : [];\n return values.some((v) => v === option.value);\n }\n return currentValue === option.value;\n }\n\n /**\n * Clear selection\n */\n clear(): void {\n if (this.multiple()) {\n this.value.set([]);\n this.onChange([]);\n } else {\n this.value.set(null);\n this.onChange(null);\n }\n this.selectionChange.emit(this.value());\n }\n\n /**\n * Handle keyboard navigation (trigger and search input share this handler)\n */\n onKeyDown(event: KeyboardEvent): void {\n if (this.isDisabled() || this.loading()) {\n return;\n }\n\n switch (event.key) {\n case ' ':\n case 'Enter':\n // Space must keep typing into the search box.\n if (event.key === ' ' && this.isSearchInput(event.target)) {\n return;\n }\n if (!this.isOpen()) {\n this.open();\n } else {\n const option = this.filteredOptions()[this.highlightedIndex()];\n if (option) {\n this.selectOption(option);\n }\n }\n event.preventDefault();\n break;\n\n case 'Escape':\n if (this.isOpen()) {\n this.close();\n event.preventDefault();\n // Only this select should react; keep the key from reaching enclosing overlays.\n event.stopPropagation();\n }\n break;\n\n case 'ArrowDown':\n if (!this.isOpen()) {\n this.open();\n } else {\n const count = this.filteredOptions().length;\n if (count > 0) {\n this.highlightedIndex.set((this.highlightedIndex() + 1) % count);\n }\n }\n event.preventDefault();\n break;\n\n case 'ArrowUp':\n if (!this.isOpen()) {\n this.open();\n } else {\n const count = this.filteredOptions().length;\n if (count > 0) {\n const current = this.highlightedIndex();\n this.highlightedIndex.set(current <= 0 ? count - 1 : current - 1);\n }\n }\n event.preventDefault();\n break;\n\n case 'Home':\n if (this.isOpen() && this.filteredOptions().length > 0) {\n this.highlightedIndex.set(0);\n event.preventDefault();\n }\n break;\n\n case 'End':\n if (this.isOpen() && this.filteredOptions().length > 0) {\n this.highlightedIndex.set(this.filteredOptions().length - 1);\n event.preventDefault();\n }\n break;\n }\n }\n\n /**\n * Handle blur event\n */\n onBlur(): void {\n this.onTouched();\n }\n\n /**\n * Handle click outside\n */\n onClickOutside(): void {\n this.close();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: SelectValue): void {\n this.value.set(value);\n }\n\n registerOnChange(fn: (value: SelectValue) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n // Private helper methods\n private isSearchInput(target: EventTarget | null): boolean {\n return target instanceof HTMLInputElement;\n }\n\n private restoreFocusFromPanel(): void {\n const panel = this.dropdownPanel()?.nativeElement;\n const active = this.document.activeElement;\n if (panel && active && panel.contains(active)) {\n this.selectTrigger()?.nativeElement.focus();\n }\n }\n\n private findOptionByValue(\n value: string | number,\n options: SelectOption[] | SelectOptionGroup[],\n ): SelectOption | undefined {\n const flatOptions = this.flattenOptions(options);\n return flatOptions.find((opt) => opt.value === value);\n }\n\n private flattenOptions(options: SelectOption[] | SelectOptionGroup[]): SelectOption[] {\n if (!options || options.length === 0) {\n return [];\n }\n\n // Check if first item is a group\n const firstItem = options[0];\n if (firstItem && 'options' in firstItem) {\n return (options as SelectOptionGroup[]).flatMap((group) => group.options);\n }\n\n return options as SelectOption[];\n }\n}\n","<div class=\"lc-select-wrapper\">\n <div\n #selectTrigger\n [class]=\"selectClasses()\"\n role=\"combobox\"\n aria-haspopup=\"listbox\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [attr.tabindex]=\"isDisabled() ? -1 : 0\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n >\n <div class=\"lc-select__value\">\n <span [class.lc-select__placeholder]=\"!selectedLabel()\">\n {{ displayValue() }}\n </span>\n </div>\n\n <div class=\"lc-select__icons\">\n @if (loading()) {\n <svg\n class=\"lc-select__spinner\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n } @else if (value() && !isDisabled() && !multiple()) {\n <button\n type=\"button\"\n class=\"lc-select__clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n\n <svg\n class=\"lc-select__chevron\"\n [class.lc-select__chevron--open]=\"isOpen()\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Dropdown Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"selectTrigger\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div #dropdownPanel class=\"lc-select__dropdown\" [class.lc-select__dropdown--open]=\"isOpen()\">\n @if (searchable()) {\n <div class=\"lc-select__search\">\n <input\n type=\"text\"\n class=\"lc-select__search-input\"\n [placeholder]=\"searchPlaceholder()\"\n aria-autocomplete=\"list\"\n [attr.aria-controls]=\"listboxId\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-label]=\"searchAriaLabel() || (ariaLabel() ? 'Search ' + ariaLabel() : 'Search options')\"\n [(ngModel)]=\"searchQuery\"\n (keydown)=\"onKeyDown($event)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n }\n\n <div\n class=\"lc-select__options\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-multiselectable]=\"multiple() ? 'true' : null\"\n >\n @if (filteredOptions().length === 0) {\n <div\n class=\"lc-select__option lc-select__option--no-results\"\n role=\"option\"\n aria-disabled=\"true\"\n aria-selected=\"false\"\n >\n {{ noOptionsLabel() }}\n </div>\n } @else {\n @for (option of filteredOptions(); track option.value; let i = $index) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays on the trigger/search, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-select__option\"\n role=\"option\"\n [id]=\"optionId(i)\"\n [attr.aria-selected]=\"isSelected(option) ? 'true' : 'false'\"\n [attr.aria-disabled]=\"option.disabled ? 'true' : null\"\n [class.lc-select__option--selected]=\"isSelected(option)\"\n [class.lc-select__option--highlighted]=\"highlightedIndex() === i\"\n [class.lc-select__option--disabled]=\"option.disabled\"\n (click)=\"selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(i)\"\n >\n @if (multiple()) {\n <!-- Purely visual: the option itself carries the selected state (role=option\n + aria-selected); the checkbox is inert so clicks land on the option. -->\n <input\n type=\"checkbox\"\n [checked]=\"isSelected(option)\"\n [disabled]=\"option.disabled\"\n class=\"lc-select__checkbox\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n />\n }\n <span class=\"lc-select__option-label\">{{ option.label }}</span>\n @if (isSelected(option) && !multiple()) {\n <svg\n class=\"lc-select__check\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n }\n </div>\n }\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-select__error\" [id]=\"selectId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-select__helper\" [id]=\"selectId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n"],"mappings":"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"}
|
|
@@ -322,7 +322,7 @@ var TextareaComponent = class TextareaComponent {
|
|
|
322
322
|
}],
|
|
323
323
|
ngImport: i0,
|
|
324
324
|
template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <!-- No whitespace before the *: the gap is its margin, and it never wraps onto a line alone -->\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}@if (required() && requiredIndicator()) {<span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>}\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"renderedValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.name]=\"name() ?? null\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" [attr.role]=\"announceError() ? 'alert' : null\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n",
|
|
325
|
-
styles: [".lc-textarea-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-sm, var(--spacing-2));width:100%}.lc-textarea-label{font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-primary)}.lc-textarea{width:100%;font-family:var(--font-family-base);font-size:var(--font-size-base);line-height:var(--line-height-base);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);resize:vertical;outline:none}.lc-textarea::placeholder{color:var(--color-text-tertiary)}.lc-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--xs{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-xs);min-height:4rem}.lc-textarea--sm{padding:var(--spacing-2-5) var(--spacing-3-5);font-size:var(--font-size-sm);min-height:5rem}.lc-textarea--md{padding:var(--spacing-3) var(--spacing-4);font-size:var(--font-size-base);min-height:6rem}.lc-textarea--lg{padding:var(--spacing-3-5) var(--spacing-5);font-size:var(--font-size-lg);min-height:7rem}.lc-textarea--outline{background-color:var(--color-surface);border-color:var(--color-field-border)}.lc-textarea--outline:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus){border-color:var(--color-text-secondary)}.lc-textarea--outline:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--filled{background-color:var(--color-surface-sunken);border-color:
|
|
325
|
+
styles: [".lc-textarea-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-sm, var(--spacing-2));width:100%}.lc-textarea-label{font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-primary)}.lc-textarea{width:100%;font-family:var(--font-family-base);font-size:var(--font-size-base);line-height:var(--line-height-base);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);resize:vertical;outline:none}.lc-textarea::placeholder{color:var(--color-text-tertiary)}.lc-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--xs{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-xs);min-height:4rem}.lc-textarea--sm{padding:var(--spacing-2-5) var(--spacing-3-5);font-size:var(--font-size-sm);min-height:5rem}.lc-textarea--md{padding:var(--spacing-3) var(--spacing-4);font-size:var(--font-size-base);min-height:6rem}.lc-textarea--lg{padding:var(--spacing-3-5) var(--spacing-5);font-size:var(--font-size-lg);min-height:7rem}.lc-textarea--outline{background-color:var(--color-surface);border-color:var(--color-field-border)}.lc-textarea--outline:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus){border-color:var(--color-text-secondary)}.lc-textarea--outline:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--filled{background-color:var(--color-surface-sunken);border-color:var(--color-field-border)}.lc-textarea--filled:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-text-secondary)}.lc-textarea--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--disabled{cursor:not-allowed;opacity:.6;background-color:var(--color-surface-muted);color:var(--color-text-tertiary)}.lc-textarea--readonly{cursor:default;background-color:var(--color-surface-muted)}.lc-textarea--error{border-color:var(--color-error-600)}.lc-textarea--error:focus{border-color:var(--color-error-600);outline:2px solid var(--color-error-600);outline-offset:0;box-shadow:none}.lc-textarea--auto-resize{resize:none;overflow:hidden}.lc-textarea-helper-text{font-size:var(--font-size-xs);color:var(--color-text-secondary)}.lc-textarea-error-message{font-size:var(--font-size-xs);color:var(--color-text-error)}.lc-textarea-char-count,.lc-textarea-character-count{font-size:var(--font-size-xs);color:var(--color-text-tertiary);text-align:right}.lc-textarea-char-count--warning,.lc-textarea-character-count--warning{color:var(--color-warning-600)}.lc-textarea-char-count--error,.lc-textarea-char-count--over-limit,.lc-textarea-character-count--error,.lc-textarea-character-count--over-limit{color:var(--color-text-error)}.lc-textarea-footer{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-textarea-messages{flex:1}.lc-textarea-input-wrapper{position:relative;width:100%}.lc-textarea-required-indicator{color:var(--color-text-error);margin-inline-start:var(--spacing-1)}@media(forced-colors:active){.lc-textarea--error:focus{outline-color:Highlight}}\n"],
|
|
326
326
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
327
327
|
});
|
|
328
328
|
};
|
|
@@ -344,7 +344,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
344
344
|
multi: true
|
|
345
345
|
}],
|
|
346
346
|
template: "<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <!-- No whitespace before the *: the gap is its margin, and it never wraps onto a line alone -->\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}@if (required() && requiredIndicator()) {<span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>}\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"renderedValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.name]=\"name() ?? null\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" [attr.role]=\"announceError() ? 'alert' : null\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n",
|
|
347
|
-
styles: [".lc-textarea-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-sm, var(--spacing-2));width:100%}.lc-textarea-label{font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-primary)}.lc-textarea{width:100%;font-family:var(--font-family-base);font-size:var(--font-size-base);line-height:var(--line-height-base);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);resize:vertical;outline:none}.lc-textarea::placeholder{color:var(--color-text-tertiary)}.lc-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--xs{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-xs);min-height:4rem}.lc-textarea--sm{padding:var(--spacing-2-5) var(--spacing-3-5);font-size:var(--font-size-sm);min-height:5rem}.lc-textarea--md{padding:var(--spacing-3) var(--spacing-4);font-size:var(--font-size-base);min-height:6rem}.lc-textarea--lg{padding:var(--spacing-3-5) var(--spacing-5);font-size:var(--font-size-lg);min-height:7rem}.lc-textarea--outline{background-color:var(--color-surface);border-color:var(--color-field-border)}.lc-textarea--outline:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus){border-color:var(--color-text-secondary)}.lc-textarea--outline:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--filled{background-color:var(--color-surface-sunken);border-color:
|
|
347
|
+
styles: [".lc-textarea-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-sm, var(--spacing-2));width:100%}.lc-textarea-label{font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-text-primary)}.lc-textarea{width:100%;font-family:var(--font-family-base);font-size:var(--font-size-base);line-height:var(--line-height-base);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);resize:vertical;outline:none}.lc-textarea::placeholder{color:var(--color-text-tertiary)}.lc-textarea:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--xs{padding:var(--spacing-2) var(--spacing-3);font-size:var(--font-size-xs);min-height:4rem}.lc-textarea--sm{padding:var(--spacing-2-5) var(--spacing-3-5);font-size:var(--font-size-sm);min-height:5rem}.lc-textarea--md{padding:var(--spacing-3) var(--spacing-4);font-size:var(--font-size-base);min-height:6rem}.lc-textarea--lg{padding:var(--spacing-3-5) var(--spacing-5);font-size:var(--font-size-lg);min-height:7rem}.lc-textarea--outline{background-color:var(--color-surface);border-color:var(--color-field-border)}.lc-textarea--outline:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus){border-color:var(--color-text-secondary)}.lc-textarea--outline:focus{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--filled{background-color:var(--color-surface-sunken);border-color:var(--color-field-border)}.lc-textarea--filled:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-text-secondary)}.lc-textarea--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-textarea--disabled{cursor:not-allowed;opacity:.6;background-color:var(--color-surface-muted);color:var(--color-text-tertiary)}.lc-textarea--readonly{cursor:default;background-color:var(--color-surface-muted)}.lc-textarea--error{border-color:var(--color-error-600)}.lc-textarea--error:focus{border-color:var(--color-error-600);outline:2px solid var(--color-error-600);outline-offset:0;box-shadow:none}.lc-textarea--auto-resize{resize:none;overflow:hidden}.lc-textarea-helper-text{font-size:var(--font-size-xs);color:var(--color-text-secondary)}.lc-textarea-error-message{font-size:var(--font-size-xs);color:var(--color-text-error)}.lc-textarea-char-count,.lc-textarea-character-count{font-size:var(--font-size-xs);color:var(--color-text-tertiary);text-align:right}.lc-textarea-char-count--warning,.lc-textarea-character-count--warning{color:var(--color-warning-600)}.lc-textarea-char-count--error,.lc-textarea-char-count--over-limit,.lc-textarea-character-count--error,.lc-textarea-character-count--over-limit{color:var(--color-text-error)}.lc-textarea-footer{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--lc-density-gap-sm, var(--spacing-2))}.lc-textarea-messages{flex:1}.lc-textarea-input-wrapper{position:relative;width:100%}.lc-textarea-required-indicator{color:var(--color-text-error);margin-inline-start:var(--spacing-1)}@media(forced-colors:active){.lc-textarea--error:focus{outline-color:Highlight}}\n"]
|
|
348
348
|
}]
|
|
349
349
|
}],
|
|
350
350
|
ctorParameters: () => [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-textarea.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.ts","../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ElementRef,\n OutputRef,\n PLATFORM_ID,\n afterRenderEffect,\n computed,\n forwardRef,\n inject,\n input,\n model,\n signal,\n viewChild,\n} from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\n/** Counter for generated ids: they follow creation order, so prerendered HTML is the same in every build. */\nlet nextUniqueId = 0;\n\n/**\n * Textarea component for multi-line text input.\n *\n * Features:\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Auto-resize with configurable min/max rows\n * - Character count display with maxLength\n * - Validation error message and helper text\n * - Disabled and readonly states\n * - ControlValueAccessor integration for reactive forms\n * - Plain form posts without JavaScript: `name`, and a `value` that is\n * prerendered into the native `<textarea>`\n *\n * @example\n * ```html\n * <lc-textarea placeholder=\"Enter message\" [autoResize]=\"true\" [(ngModel)]=\"message\" />\n * <lc-textarea label=\"Message\" name=\"message\" [required]=\"true\" [value]=\"draft\" />\n * ```\n */\n@Component({\n selector: 'lc-textarea',\n standalone: true,\n imports: [],\n templateUrl: './textarea.component.html',\n styleUrl: './textarea.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => TextareaComponent),\n multi: true,\n },\n ],\n})\nexport class TextareaComponent implements ControlValueAccessor {\n private readonly textareaElement = viewChild<ElementRef<HTMLTextAreaElement>>('textarea');\n\n private readonly isServer = isPlatformServer(inject(PLATFORM_ID));\n\n /**\n * Visual variant of the textarea\n * @default 'outline'\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the textarea\n * @default 'md'\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the textarea is disabled\n * @default false\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the textarea is in error state\n * @default false\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the textarea is required\n * @default false\n */\n readonly required = input<boolean>(false);\n\n /**\n * Show the `*` after the label of a `required` field. `false` keeps the\n * required semantics (`required`, `aria-required`) without the asterisk —\n * for forms where every field is required.\n * @default true\n */\n readonly requiredIndicator = input<boolean>(true);\n\n /**\n * Deprecated, no effect (it never had one in `lc-textarea`). The `*` is\n * decorative and hidden from assistive technology, because the native\n * `required` state is announced already, in the screen reader's language; a\n * name on the `*` would make the field say \"required\" twice. Kept so\n * existing bindings compile.\n * @deprecated No effect: the native `required` state is announced instead.\n * @default 'required'\n */\n readonly requiredAriaLabel = input<string>('required');\n\n /**\n * Id of the native `<textarea>`. The label's `for`, the error\n * (`<id>-error`), the helper text (`<id>-helper`) and `aria-describedby`\n * derive from it, so an error summary can link to the field\n * (`<a href=\"#contact-message\">`) and prerendered HTML is the same in every\n * build. Unique in the document, no spaces. Unset (or empty) = a generated\n * `lc-textarea-<n>`, which follows creation order (on the server it keeps\n * counting across prerendered routes): set it on prerendered pages.\n * @default generated (lc-textarea-<n>)\n */\n readonly controlId = input<string | undefined>(undefined);\n\n /**\n * Announce the error message the moment it appears (`role=\"alert\"` on the\n * message). Set `false` when an `lc-alert` error summary above the form\n * already announces the errors (a page re-rendered after a failed submit,\n * e.g. 422), so they aren't read twice. The message stays visible, stays\n * linked through `aria-describedby` (read with the field), and the control\n * keeps `aria-invalid`.\n * @default true\n */\n readonly announceError = input<boolean>(true);\n\n /**\n * Whether the textarea is readonly\n * @default false\n */\n readonly readonly = input<boolean>(false);\n\n /**\n * Placeholder text\n * @default ''\n */\n readonly placeholder = input<string>('');\n\n /**\n * Label text displayed above the textarea\n * @default ''\n */\n readonly label = input<string>('');\n\n /**\n * Helper text displayed below the textarea\n * @default ''\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n * @default ''\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n * @default undefined\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Native `name` of the inner `<textarea>`, so a form posts the text without\n * JavaScript. Unset = no attribute. A `disabled` textarea is not posted\n * (HTML); use `readonly` to post a fixed text.\n * @default undefined\n */\n readonly name = input<string>();\n\n /**\n * Number of visible text rows\n * @default 3\n */\n readonly rows = input<number>(3);\n\n /**\n * Maximum number of characters allowed\n * @default undefined\n */\n readonly maxLength = input<number | undefined>(undefined);\n\n /**\n * Whether to show character count\n * @default false\n */\n readonly showCharacterCount = input<boolean>(false);\n\n /**\n * Whether to automatically resize based on content\n * @default false\n */\n readonly autoResize = input<boolean>(false);\n\n /**\n * Minimum number of rows for auto-resize\n * @default 3\n */\n readonly minRows = input<number>(3);\n\n /**\n * Maximum number of rows for auto-resize\n * @default undefined\n */\n readonly maxRows = input<number | undefined>(undefined);\n\n /**\n * Current text, two-way bindable (`[value]` / `[(value)]`). It pre-fills the\n * native textarea, in prerendered HTML too, so a server-rendered page can\n * keep a visitor's text. Emits `valueChange` whenever it changes: once per\n * keystroke that changes the text, and when a bound form control or code\n * sets a different text. With a form control, the control's value wins;\n * don't bind both.\n * @default ''\n */\n readonly value = model<string>('');\n\n /**\n * The model's change output as a class property, so code that subscribes to\n * it (`textarea.valueChange.subscribe(…)`, `outputToObservable(…)`) keeps\n * compiling as in 3.9. Template bindings `(valueChange)` use the model.\n */\n readonly valueChange: OutputRef<string> = this.value;\n\n /** Generated id, taken once per instance (also with `controlId`), so later ids don't shift. */\n private readonly generatedId = `lc-textarea-${nextUniqueId++}`;\n\n private readonly resolvedId = computed(() => this.controlId() || this.generatedId);\n\n /** Id of the native textarea: `controlId`, or the generated `lc-textarea-<n>`. Links label, error and helper text to it. */\n get textareaId(): string {\n return this.resolvedId();\n }\n\n /** Id of the error message: `<textareaId>-error`. */\n get errorId(): string {\n return `${this.resolvedId()}-error`;\n }\n\n /** Id of the helper text: `<textareaId>-helper`. */\n get helperId(): string {\n return `${this.resolvedId()}-helper`;\n }\n\n /**\n * The native textarea's value. On the server a leading line break gets one\n * extra `\\n`: the HTML parser drops the first line break after `<textarea>`,\n * and the server's DOM serialiser doesn't add the one the HTML\n * serialisation rules require, so the prerendered page would lose it.\n */\n protected readonly renderedValue = computed(() => {\n const value = this.value();\n return this.isServer && /^[\\r\\n]/.test(value) ? `\\n${value}` : value;\n });\n\n // Internal disabled state (for ControlValueAccessor)\n private readonly formDisabled = signal<boolean>(false);\n\n /**\n * Computed disabled state from both input and form control\n */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly currentCharacterCount = computed(() => this.value().length);\n\n readonly characterCountText = computed(() => {\n const current = this.currentCharacterCount();\n const max = this.maxLength();\n return max !== undefined ? `${current} / ${max}` : `${current}`;\n });\n\n readonly isOverLimit = computed(() => {\n const max = this.maxLength();\n return max !== undefined && this.currentCharacterCount() > max;\n });\n\n /** Whether an error message is shown (drives aria-describedby) */\n readonly showsError = computed(() => this.error() && !!this.errorMessage());\n\n /** Whether the helper text is shown (error message takes precedence) */\n readonly showsHelper = computed(() => !this.showsError() && !!this.helperText());\n\n readonly describedBy = computed(() => {\n const ids: string[] = [];\n if (this.showsError()) ids.push(this.errorId);\n if (this.showsHelper()) ids.push(this.helperId);\n return ids.length ? ids.join(' ') : null;\n });\n\n /**\n * Computed classes for the textarea element\n */\n readonly textareaClasses = computed(() => {\n const classes = ['lc-textarea', `lc-textarea--${this.variant()}`, `lc-textarea--${this.size()}`];\n\n if (this.isDisabled()) {\n classes.push('lc-textarea--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-textarea--error');\n }\n\n if (this.readonly()) {\n classes.push('lc-textarea--readonly');\n }\n\n if (this.autoResize()) {\n classes.push('lc-textarea--auto-resize');\n }\n\n return classes.join(' ');\n });\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: string) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n constructor() {\n // Re-measure after every render in which the value or the resize\n // constraints changed — this covers typing, form writes and input changes\n // without timers, and runs once the DOM already holds the new value.\n afterRenderEffect(() => {\n this.value();\n this.minRows();\n this.maxRows();\n if (this.autoResize()) {\n this.adjustHeight();\n }\n });\n }\n\n /**\n * Handle input changes\n */\n onInput(value: string): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n\n // model.set() emits `valueChange` exactly once per actual change\n this.value.set(value);\n this.onChange(value);\n }\n\n /**\n * Handle blur event\n */\n onBlur(): void {\n this.onTouched();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: string | null | undefined): void {\n this.value.set(value || '');\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n // Private helper methods\n private adjustHeight(): void {\n const textarea = this.textareaElement()?.nativeElement;\n if (!textarea) {\n return;\n }\n\n // Reset height to get accurate scrollHeight\n textarea.style.height = 'auto';\n\n const minHeight = this.rowsToHeight(textarea, this.minRows());\n const maxHeight = this.rowsToHeight(textarea, this.maxRows());\n let newHeight = textarea.scrollHeight;\n\n // Apply constraints\n if (minHeight !== undefined) {\n newHeight = Math.max(newHeight, minHeight);\n }\n if (maxHeight !== undefined) {\n newHeight = Math.min(newHeight, maxHeight);\n }\n\n textarea.style.height = `${newHeight}px`;\n }\n\n /** Pixel height for `rows` lines incl. vertical padding; undefined when it cannot be measured. */\n private rowsToHeight(textarea: HTMLTextAreaElement, rows: number | undefined): number | undefined {\n if (rows === undefined) {\n return undefined;\n }\n\n const style = getComputedStyle(textarea);\n const lineHeight = parseFloat(style.lineHeight);\n const paddingTop = parseFloat(style.paddingTop) || 0;\n const paddingBottom = parseFloat(style.paddingBottom) || 0;\n\n // 'normal' / unmeasurable line-height (e.g. jsdom) → no constraint\n if (!Number.isFinite(lineHeight)) {\n return undefined;\n }\n\n return lineHeight * rows + paddingTop + paddingBottom;\n }\n\n protected getInputValue(event: Event): string {\n return (event.target as HTMLTextAreaElement).value;\n }\n}\n","<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <!-- No whitespace before the *: the gap is its margin, and it never wraps onto a line alone -->\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}@if (required() && requiredIndicator()) {<span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>}\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"renderedValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.name]=\"name() ?? null\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" [attr.role]=\"announceError() ? 'alert' : null\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-textarea.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.ts","../../../../libs/angular-ui-kit/src/lib/textarea/textarea.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n ElementRef,\n OutputRef,\n PLATFORM_ID,\n afterRenderEffect,\n computed,\n forwardRef,\n inject,\n input,\n model,\n signal,\n viewChild,\n} from '@angular/core';\nimport { isPlatformServer } from '@angular/common';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\n/** Counter for generated ids: they follow creation order, so prerendered HTML is the same in every build. */\nlet nextUniqueId = 0;\n\n/**\n * Textarea component for multi-line text input.\n *\n * Features:\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Auto-resize with configurable min/max rows\n * - Character count display with maxLength\n * - Validation error message and helper text\n * - Disabled and readonly states\n * - ControlValueAccessor integration for reactive forms\n * - Plain form posts without JavaScript: `name`, and a `value` that is\n * prerendered into the native `<textarea>`\n *\n * @example\n * ```html\n * <lc-textarea placeholder=\"Enter message\" [autoResize]=\"true\" [(ngModel)]=\"message\" />\n * <lc-textarea label=\"Message\" name=\"message\" [required]=\"true\" [value]=\"draft\" />\n * ```\n */\n@Component({\n selector: 'lc-textarea',\n standalone: true,\n imports: [],\n templateUrl: './textarea.component.html',\n styleUrl: './textarea.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => TextareaComponent),\n multi: true,\n },\n ],\n})\nexport class TextareaComponent implements ControlValueAccessor {\n private readonly textareaElement = viewChild<ElementRef<HTMLTextAreaElement>>('textarea');\n\n private readonly isServer = isPlatformServer(inject(PLATFORM_ID));\n\n /**\n * Visual variant of the textarea\n * @default 'outline'\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the textarea\n * @default 'md'\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the textarea is disabled\n * @default false\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the textarea is in error state\n * @default false\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the textarea is required\n * @default false\n */\n readonly required = input<boolean>(false);\n\n /**\n * Show the `*` after the label of a `required` field. `false` keeps the\n * required semantics (`required`, `aria-required`) without the asterisk —\n * for forms where every field is required.\n * @default true\n */\n readonly requiredIndicator = input<boolean>(true);\n\n /**\n * Deprecated, no effect (it never had one in `lc-textarea`). The `*` is\n * decorative and hidden from assistive technology, because the native\n * `required` state is announced already, in the screen reader's language; a\n * name on the `*` would make the field say \"required\" twice. Kept so\n * existing bindings compile.\n * @deprecated No effect: the native `required` state is announced instead.\n * @default 'required'\n */\n readonly requiredAriaLabel = input<string>('required');\n\n /**\n * Id of the native `<textarea>`. The label's `for`, the error\n * (`<id>-error`), the helper text (`<id>-helper`) and `aria-describedby`\n * derive from it, so an error summary can link to the field\n * (`<a href=\"#contact-message\">`) and prerendered HTML is the same in every\n * build. Unique in the document, no spaces. Unset (or empty) = a generated\n * `lc-textarea-<n>`, which follows creation order (on the server it keeps\n * counting across prerendered routes): set it on prerendered pages.\n * @default generated (lc-textarea-<n>)\n */\n readonly controlId = input<string | undefined>(undefined);\n\n /**\n * Announce the error message the moment it appears (`role=\"alert\"` on the\n * message). Set `false` when an `lc-alert` error summary above the form\n * already announces the errors (a page re-rendered after a failed submit,\n * e.g. 422), so they aren't read twice. The message stays visible, stays\n * linked through `aria-describedby` (read with the field), and the control\n * keeps `aria-invalid`.\n * @default true\n */\n readonly announceError = input<boolean>(true);\n\n /**\n * Whether the textarea is readonly\n * @default false\n */\n readonly readonly = input<boolean>(false);\n\n /**\n * Placeholder text\n * @default ''\n */\n readonly placeholder = input<string>('');\n\n /**\n * Label text displayed above the textarea\n * @default ''\n */\n readonly label = input<string>('');\n\n /**\n * Helper text displayed below the textarea\n * @default ''\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n * @default ''\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n * @default undefined\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Native `name` of the inner `<textarea>`, so a form posts the text without\n * JavaScript. Unset = no attribute. A `disabled` textarea is not posted\n * (HTML); use `readonly` to post a fixed text.\n * @default undefined\n */\n readonly name = input<string>();\n\n /**\n * Number of visible text rows\n * @default 3\n */\n readonly rows = input<number>(3);\n\n /**\n * Maximum number of characters allowed\n * @default undefined\n */\n readonly maxLength = input<number | undefined>(undefined);\n\n /**\n * Whether to show character count\n * @default false\n */\n readonly showCharacterCount = input<boolean>(false);\n\n /**\n * Whether to automatically resize based on content\n * @default false\n */\n readonly autoResize = input<boolean>(false);\n\n /**\n * Minimum number of rows for auto-resize\n * @default 3\n */\n readonly minRows = input<number>(3);\n\n /**\n * Maximum number of rows for auto-resize\n * @default undefined\n */\n readonly maxRows = input<number | undefined>(undefined);\n\n /**\n * Current text, two-way bindable (`[value]` / `[(value)]`). It pre-fills the\n * native textarea, in prerendered HTML too, so a server-rendered page can\n * keep a visitor's text. Emits `valueChange` whenever it changes: once per\n * keystroke that changes the text, and when a bound form control or code\n * sets a different text. With a form control, the control's value wins;\n * don't bind both.\n * @default ''\n */\n readonly value = model<string>('');\n\n /**\n * The model's change output as a class property, so code that subscribes to\n * it (`textarea.valueChange.subscribe(…)`, `outputToObservable(…)`) keeps\n * compiling as in 3.9. Template bindings `(valueChange)` use the model.\n */\n readonly valueChange: OutputRef<string> = this.value;\n\n /** Generated id, taken once per instance (also with `controlId`), so later ids don't shift. */\n private readonly generatedId = `lc-textarea-${nextUniqueId++}`;\n\n private readonly resolvedId = computed(() => this.controlId() || this.generatedId);\n\n /** Id of the native textarea: `controlId`, or the generated `lc-textarea-<n>`. Links label, error and helper text to it. */\n get textareaId(): string {\n return this.resolvedId();\n }\n\n /** Id of the error message: `<textareaId>-error`. */\n get errorId(): string {\n return `${this.resolvedId()}-error`;\n }\n\n /** Id of the helper text: `<textareaId>-helper`. */\n get helperId(): string {\n return `${this.resolvedId()}-helper`;\n }\n\n /**\n * The native textarea's value. On the server a leading line break gets one\n * extra `\\n`: the HTML parser drops the first line break after `<textarea>`,\n * and the server's DOM serialiser doesn't add the one the HTML\n * serialisation rules require, so the prerendered page would lose it.\n */\n protected readonly renderedValue = computed(() => {\n const value = this.value();\n return this.isServer && /^[\\r\\n]/.test(value) ? `\\n${value}` : value;\n });\n\n // Internal disabled state (for ControlValueAccessor)\n private readonly formDisabled = signal<boolean>(false);\n\n /**\n * Computed disabled state from both input and form control\n */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly currentCharacterCount = computed(() => this.value().length);\n\n readonly characterCountText = computed(() => {\n const current = this.currentCharacterCount();\n const max = this.maxLength();\n return max !== undefined ? `${current} / ${max}` : `${current}`;\n });\n\n readonly isOverLimit = computed(() => {\n const max = this.maxLength();\n return max !== undefined && this.currentCharacterCount() > max;\n });\n\n /** Whether an error message is shown (drives aria-describedby) */\n readonly showsError = computed(() => this.error() && !!this.errorMessage());\n\n /** Whether the helper text is shown (error message takes precedence) */\n readonly showsHelper = computed(() => !this.showsError() && !!this.helperText());\n\n readonly describedBy = computed(() => {\n const ids: string[] = [];\n if (this.showsError()) ids.push(this.errorId);\n if (this.showsHelper()) ids.push(this.helperId);\n return ids.length ? ids.join(' ') : null;\n });\n\n /**\n * Computed classes for the textarea element\n */\n readonly textareaClasses = computed(() => {\n const classes = ['lc-textarea', `lc-textarea--${this.variant()}`, `lc-textarea--${this.size()}`];\n\n if (this.isDisabled()) {\n classes.push('lc-textarea--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-textarea--error');\n }\n\n if (this.readonly()) {\n classes.push('lc-textarea--readonly');\n }\n\n if (this.autoResize()) {\n classes.push('lc-textarea--auto-resize');\n }\n\n return classes.join(' ');\n });\n\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: string) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n constructor() {\n // Re-measure after every render in which the value or the resize\n // constraints changed — this covers typing, form writes and input changes\n // without timers, and runs once the DOM already holds the new value.\n afterRenderEffect(() => {\n this.value();\n this.minRows();\n this.maxRows();\n if (this.autoResize()) {\n this.adjustHeight();\n }\n });\n }\n\n /**\n * Handle input changes\n */\n onInput(value: string): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n\n // model.set() emits `valueChange` exactly once per actual change\n this.value.set(value);\n this.onChange(value);\n }\n\n /**\n * Handle blur event\n */\n onBlur(): void {\n this.onTouched();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: string | null | undefined): void {\n this.value.set(value || '');\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n // Private helper methods\n private adjustHeight(): void {\n const textarea = this.textareaElement()?.nativeElement;\n if (!textarea) {\n return;\n }\n\n // Reset height to get accurate scrollHeight\n textarea.style.height = 'auto';\n\n const minHeight = this.rowsToHeight(textarea, this.minRows());\n const maxHeight = this.rowsToHeight(textarea, this.maxRows());\n let newHeight = textarea.scrollHeight;\n\n // Apply constraints\n if (minHeight !== undefined) {\n newHeight = Math.max(newHeight, minHeight);\n }\n if (maxHeight !== undefined) {\n newHeight = Math.min(newHeight, maxHeight);\n }\n\n textarea.style.height = `${newHeight}px`;\n }\n\n /** Pixel height for `rows` lines incl. vertical padding; undefined when it cannot be measured. */\n private rowsToHeight(textarea: HTMLTextAreaElement, rows: number | undefined): number | undefined {\n if (rows === undefined) {\n return undefined;\n }\n\n const style = getComputedStyle(textarea);\n const lineHeight = parseFloat(style.lineHeight);\n const paddingTop = parseFloat(style.paddingTop) || 0;\n const paddingBottom = parseFloat(style.paddingBottom) || 0;\n\n // 'normal' / unmeasurable line-height (e.g. jsdom) → no constraint\n if (!Number.isFinite(lineHeight)) {\n return undefined;\n }\n\n return lineHeight * rows + paddingTop + paddingBottom;\n }\n\n protected getInputValue(event: Event): string {\n return (event.target as HTMLTextAreaElement).value;\n }\n}\n","<div class=\"lc-textarea-wrapper\">\n @if (label()) {\n <!-- No whitespace before the *: the gap is its margin, and it never wraps onto a line alone -->\n <label [for]=\"textareaId\" class=\"lc-textarea-label\">\n {{ label() }}@if (required() && requiredIndicator()) {<span class=\"lc-textarea-required-indicator\" aria-hidden=\"true\">*</span>}\n </label>\n }\n\n <div class=\"lc-textarea-input-wrapper\">\n <textarea\n #textarea\n [id]=\"textareaId\"\n [class]=\"textareaClasses()\"\n [value]=\"renderedValue()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"isDisabled()\"\n [readonly]=\"readonly()\"\n [required]=\"required()\"\n [attr.name]=\"name() ?? null\"\n [attr.rows]=\"autoResize() ? null : rows()\"\n [attr.maxlength]=\"maxLength() ?? null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() || null\"\n [attr.aria-invalid]=\"error() || null\"\n [attr.aria-describedby]=\"describedBy()\"\n (input)=\"onInput(getInputValue($event))\"\n (blur)=\"onBlur()\"\n ></textarea>\n </div>\n\n <div class=\"lc-textarea-footer\">\n <div class=\"lc-textarea-messages\">\n @if (showsError()) {\n <span [id]=\"errorId\" class=\"lc-textarea-error-message\" [attr.role]=\"announceError() ? 'alert' : null\">{{ errorMessage() }}</span>\n } @else if (showsHelper()) {\n <span [id]=\"helperId\" class=\"lc-textarea-helper-text\">{{ helperText() }}</span>\n }\n </div>\n\n @if (showCharacterCount()) {\n <span\n class=\"lc-textarea-character-count\"\n [class.lc-textarea-character-count--over-limit]=\"isOverLimit()\"\n aria-live=\"polite\"\n >\n {{ characterCountText() }}\n </span>\n }\n </div>\n</div>\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -177,14 +177,17 @@ describe('Focus indicators (request 042)', () => {
|
|
|
177
177
|
// they also exclude the error class (an error field kept no error border
|
|
178
178
|
// under the pointer), and the textarea/datepicker outline hover moved from
|
|
179
179
|
// --color-primary-400 (1.89:1 light) to --color-text-secondary (7.55:1).
|
|
180
|
+
// Request 044 (F-31, design D-3) changed the three filled rows on purpose:
|
|
181
|
+
// their hover border is --color-text-secondary too (it was --color-border,
|
|
182
|
+
// 1.23:1 light, or none in the textarea), the 3:1 boundary of the outline.
|
|
180
183
|
const hovers: [string, string, Record<string, string>][] = [
|
|
181
184
|
['textarea/textarea.component.scss', '.lc-textarea--outline:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus)', { 'border-color': 'var(--color-text-secondary)' }],
|
|
182
|
-
['textarea/textarea.component.scss', '.lc-textarea--filled:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)' }],
|
|
185
|
+
['textarea/textarea.component.scss', '.lc-textarea--filled:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-text-secondary)' }],
|
|
183
186
|
['datepicker/datepicker.component.scss', '.lc-datepicker:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus)', { 'border-color': 'var(--color-text-secondary)' }],
|
|
184
|
-
['datepicker/datepicker.component.scss', '.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-
|
|
187
|
+
['datepicker/datepicker.component.scss', '.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-text-secondary)' }],
|
|
185
188
|
['input/input.component.scss', '.input-container:hover:not(.input-disabled):not(.input-readonly):not(.input-invalid):not(:focus-within)', { 'border-color': 'var(--color-text-secondary)' }],
|
|
186
189
|
['select/select.component.scss', '.lc-select:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus)', { 'border-color': 'var(--color-text-secondary)' }],
|
|
187
|
-
['select/select.component.scss', '.lc-select.lc-select--filled:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-
|
|
190
|
+
['select/select.component.scss', '.lc-select.lc-select--filled:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-text-secondary)' }],
|
|
188
191
|
['search-input/search-input.component.scss', '.search-input:hover:not(.search-input--disabled):not(:focus-within)', { 'border-color': 'var(--color-text-secondary)' }],
|
|
189
192
|
['tag-input/tag-input.component.scss', '.lc-tag-input__container:hover:not(.lc-tag-input__container--focused)', { 'border-color': 'var(--color-text-secondary)' }],
|
|
190
193
|
['date-range-picker/date-range-picker.component.scss', '.lc-drp__field:hover:not(.lc-drp__field--disabled):not(:focus-within)', { 'border-color': 'var(--color-text-secondary)' }],
|