novo-elements
Version:
1 lines • 124 kB
Source Map (JSON)
{"version":3,"file":"novo-elements-elements-common.mjs","sources":["../../../projects/novo-elements/src/elements/common/theme/theme-options.ts","../../../projects/novo-elements/src/elements/common/directives/accent.directive.ts","../../../projects/novo-elements/src/elements/common/directives/bg.directive.ts","../../../projects/novo-elements/src/elements/common/directives/border.directive.ts","../../../projects/novo-elements/src/elements/common/directives/color.directive.ts","../../../projects/novo-elements/src/elements/common/directives/fill.directive.ts","../../../projects/novo-elements/src/elements/common/directives/flex.directive.ts","../../../projects/novo-elements/src/elements/common/directives/space.directive.ts","../../../projects/novo-elements/src/elements/common/directives/switch-cases.directive.ts","../../../projects/novo-elements/src/elements/common/directives/theme.directive.ts","../../../projects/novo-elements/src/elements/common/directives/visible.directive.ts","../../../projects/novo-elements/src/elements/common/novo-template/novo-template.directive.ts","../../../projects/novo-elements/src/elements/common/selection/pseudo-checkbox/pseudo-checkbox.component.ts","../../../projects/novo-elements/src/elements/common/selection/index.ts","../../../projects/novo-elements/src/elements/common/mixins/disabled.mixin.ts","../../../projects/novo-elements/src/elements/common/option/option-parent.ts","../../../projects/novo-elements/src/elements/common/option/optgroup.component.ts","../../../projects/novo-elements/src/elements/common/option/optgroup.component.html","../../../projects/novo-elements/src/elements/common/option/option.component.ts","../../../projects/novo-elements/src/elements/common/option/option.component.html","../../../projects/novo-elements/src/elements/common/option/index.ts","../../../projects/novo-elements/src/elements/common/typography/base/base-text.component.ts","../../../projects/novo-elements/src/elements/common/typography/caption/caption.component.ts","../../../projects/novo-elements/src/elements/common/typography/label/label.component.ts","../../../projects/novo-elements/src/elements/common/typography/link/link.component.ts","../../../projects/novo-elements/src/elements/common/typography/text/text.component.ts","../../../projects/novo-elements/src/elements/common/typography/title/title.component.ts","../../../projects/novo-elements/src/elements/common/common.module.ts","../../../projects/novo-elements/src/elements/common/error/error-options.ts","../../../projects/novo-elements/src/elements/common/mixins/color.mixin.ts","../../../projects/novo-elements/src/elements/common/mixins/error-state.mixin.ts","../../../projects/novo-elements/src/elements/common/mixins/overlay.mixin.ts","../../../projects/novo-elements/src/elements/common/mixins/required.mixin.ts","../../../projects/novo-elements/src/elements/common/mixins/size.mixin.ts","../../../projects/novo-elements/src/elements/common/mixins/tab-index.mixin.ts","../../../projects/novo-elements/src/elements/common/overlay/Overlay.ts","../../../projects/novo-elements/src/elements/common/overlay/Overlay.module.ts","../../../projects/novo-elements/src/elements/common/novo-elements-elements-common.ts"],"sourcesContent":["import { EventEmitter, Injectable } from '@angular/core';\nimport { Observable, of } from 'rxjs';\n\nexport class NovoThemeOptions {\n themeName: string;\n}\nexport interface ThemeChangeEvent {\n themeName: string;\n options?: NovoThemeOptions;\n}\n\n@Injectable({\n providedIn: 'root',\n})\nexport class NovoTheme {\n private _defaultTheme: NovoThemeOptions = { themeName: 'modern-light' };\n private _currentTheme: NovoThemeOptions;\n\n onThemeChange: EventEmitter<ThemeChangeEvent> = new EventEmitter<ThemeChangeEvent>();\n\n /** Name of the theme being used. defaults to `modern-light` */\n get themeName() {\n return this._currentTheme?.themeName || this._defaultTheme.themeName;\n }\n set themeName(value: string) {\n this._currentTheme = { themeName: value };\n this.changeTheme(this._currentTheme);\n }\n\n public use(options: NovoThemeOptions): Observable<any> {\n // future: don't change the theme if the theme given is already selected\n this.changeTheme(options);\n // this might become async in future\n return of(options);\n }\n\n /**\n * Changes the current theme\n */\n private changeTheme(theme: NovoThemeOptions): void {\n this._currentTheme = theme;\n this.onThemeChange.emit({ themeName: theme.themeName, options: theme });\n }\n}\n\n/* FUTURE THOUGHTS */\n/**\n getComputedStyle(document.documentElement)\n .getPropertyValue('--my-variable-name'); // #999999\n\n document.documentElement.style\n .setProperty('--my-variable-name', 'pink');\n*/\n","import { ChangeDetectorRef, Directive, HostBinding, Input, OnDestroy } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { NovoTheme, ThemeChangeEvent } from '../theme/theme-options';\n\n@Directive({\n selector: '[accent]',\n standalone: false,\n})\nexport class AccentColorDirective implements OnDestroy {\n private subscription: Subscription;\n\n @Input() accent: string;\n\n @HostBinding('class')\n get hb_textColor() {\n // Support legacy classic theme... for now\n if (this.theme.themeName === 'classic') {\n return `novo-theme-${this.accent}`;\n }\n return `novo-accent-${this.accent}`;\n }\n\n constructor(private theme: NovoTheme, protected cdr: ChangeDetectorRef) {\n this.subscription = this.theme.onThemeChange.subscribe((event: ThemeChangeEvent) => {\n this.cdr.markForCheck();\n });\n }\n\n ngOnDestroy(): void {\n this.subscription.unsubscribe();\n }\n}\n","import { Directive, ElementRef, HostBinding, Input } from '@angular/core';\n\n@Directive({\n selector: '[bg]',\n standalone: false,\n})\nexport class BackgroundColorDirective {\n @Input() bg: string;\n\n @HostBinding('class')\n get hb_bgColor() {\n return isValidColor(this.bg) ? 'novo-background-custom' : `novo-background-${this.bg}`;\n }\n @HostBinding('style.background-color')\n get hb_bgStyle() {\n return isValidColor(this.bg) ? this.bg : null;\n }\n\n constructor(private el: ElementRef) {}\n}\n\nfunction isValidColor(color: string) {\n return color.startsWith('#') || color.startsWith('rgb');\n}\n","import { Directive, ElementRef, HostBinding, Input } from '@angular/core';\n@Directive({\n selector: '[border], [bb], [borderBottom], [bt], [borderTop], [bl], [borderLeft], [br], [borderRight], [bx], [borderX], [by], [borderY]',\n standalone: false,\n})\nexport class BorderDirective {\n @Input() borderStyle = 'solid';\n @Input() borderColor = '#eaecef';\n @Input() borderWidth = 1;\n\n @Input() border: string;\n @Input() borderLeft: string;\n @Input() bl: string;\n @Input() borderRight: string;\n @Input() br: string;\n @Input() borderTop: string;\n @Input() bt: string;\n @Input() borderBottom: string;\n @Input() bb: string;\n @Input() borderX: string;\n @Input() bx: string;\n @Input() borderY: string;\n @Input() by: string;\n\n @HostBinding('class') get hb_border() {\n return `border-${this.border}`;\n }\n @HostBinding('style.border-left') get hb_border_left() {\n return this.borderLeft || this.bl || this.bx || this.borderX;\n }\n @HostBinding('style.border-right') get hb_border_right() {\n return this.borderRight || this.bt || this.bx || this.borderX;\n }\n @HostBinding('style.border-top') get hb_border_top() {\n return this.borderTop || this.bt || this.by || this.borderY;\n }\n @HostBinding('style.border-bottom') get hb_border_bottom() {\n return this.borderBottom || this.bt || this.by || this.borderY;\n }\n\n constructor(private el: ElementRef) {}\n}\n","import { Directive, ElementRef, HostBinding, Input } from '@angular/core';\n\n@Directive({\n selector: '[txc]',\n standalone: false,\n})\nexport class TextColorDirective {\n @Input() txc: string;\n\n @HostBinding('class')\n get hb_textColor() {\n return isValidColor(this.txc) ? 'novo-text-custom' : `novo-text-${this.txc}`;\n }\n @HostBinding('style.color')\n get hb_textStyle() {\n return isValidColor(this.txc) ? this.txc : null;\n }\n\n constructor(private el: ElementRef) {}\n}\n\nfunction isValidColor(color: string) {\n return color.startsWith('#') || color.startsWith('rgb');\n}\n","import { Directive, ElementRef, HostBinding, Input } from '@angular/core';\n\n@Directive({\n selector: '[fill]',\n standalone: false,\n})\nexport class FillColorDirective {\n @Input() fill: string;\n\n @HostBinding('class')\n get hb_textColor() {\n return `novo-fill-${this.fill}`;\n }\n\n constructor(private el: ElementRef) {}\n}\n","import { Directive, ElementRef, HostBinding, Input, Renderer2 } from '@angular/core';\n\n@Directive({\n selector: '[flex]',\n standalone: false,\n})\nexport class FlexDirective {\n private _flex: string;\n\n @HostBinding('style.flex')\n @Input()\n public get flex(): string {\n return this._flex;\n }\n\n public set flex(value: string) {\n if (!value) {\n this._flex = '1 1 auto';\n } else {\n this._flex = value;\n }\n }\n\n constructor(private readonly el: ElementRef, private readonly renderer: Renderer2) {\n }\n}\n","import { Directive, HostBinding, Input } from '@angular/core';\nimport { spacing } from 'novo-design-tokens';\n/*\nProp\tCSS Property\tTheme Field\nm, margin\tmargin\tspace\nmt, marginTop\tmargin-top\tspace\nmr, marginRight\tmargin-right\tspace\nmb, marginBottom\tmargin-bottom\tspace\nml, marginLeft\tmargin-left\tspace\nmx\tmargin-left and margin-right\tspace\nmy\tmargin-top and margin-bottom\tspace\np, padding\tpadding\tspace\npt, paddingTop\tpadding-top\tspace\npr, paddingRight\tpadding-right\tspace\npb, paddingBottom\tpadding-bottom\tspace\npl, paddingLeft\tpadding-left\tspace\npx\tpadding-left and padding-right\tspace\npy\tpadding-top and padding-bottom\tspace\n*/\n\n/*\n// Selectors generated with the following code\nconst directions = ['Top', 'Right', 'Bottom', 'Left', 'X', 'Y'];\nconst abbrDirections = directions.map((d) => d.slice(0, 1).toLowerCase());\nconst marginAttrs = [\n '[m]',\n '[margin]',\n ...directions.map((dir) => `[margin${dir}]`),\n ...abbrDirections.map((dir) => `[m${dir}]`),\n];\nconst paddingAttrs = [\n '[p]',\n '[padding]',\n ...directions.map((dir) => `[padding${dir}]`),\n ...abbrDirections.map((dir) => `[p${dir}]`),\n];\n\nconst selectors = [...marginAttrs, ...paddingAttrs];\n*/\n\nexport const getSpacingToken = (value: string) => {\n if (Object.keys(spacing).includes(value)) {\n return spacing[value];\n }\n // TODO: Maybe Validate Value ie.(rem, px)\n return value;\n};\n\n@Directive({\n selector: '[m],[margin],[marginTop],[marginRight],[marginBottom],[marginLeft],[marginX],[marginY],[mt],[mr],[mb],[ml],[mx],[my]',\n standalone: false,\n})\nexport class MarginDirective {\n // Margin\n @Input() margin: string;\n @Input() m: string;\n @Input() marginLeft: string;\n @Input() ml: string;\n @Input() marginRight: string;\n @Input() mr: string;\n @Input() marginTop: string;\n @Input() mt: string;\n @Input() marginBottom: string;\n @Input() mb: string;\n @Input() marginX: string;\n @Input() mx: string;\n @Input() marginY: string;\n @Input() my: string;\n\n @HostBinding('class') get hb_margin() {\n return `margin-${this.margin || this.m}`;\n }\n\n @HostBinding('style.margin-left') get hb_margin_left() {\n return getSpacingToken(this.marginLeft || this.ml || this.mx || this.marginX);\n }\n @HostBinding('style.margin-right') get hb_margin_right() {\n return getSpacingToken(this.marginRight || this.mr || this.mx || this.marginX);\n }\n @HostBinding('style.margin-top') get hb_margin_top() {\n return getSpacingToken(this.marginTop || this.mt || this.my || this.marginY);\n }\n @HostBinding('style.margin-bottom') get hb_margin_bottom() {\n return getSpacingToken(this.marginBottom || this.mb || this.my || this.marginY);\n }\n}\n\n@Directive({\n selector: '[p],[padding],[paddingTop],[paddingRight],[paddingBottom],[paddingLeft],[paddingX],[paddingY],[pt],[pr],[pb],[pl],[px],[py]',\n standalone: false,\n})\nexport class PaddingDirective {\n // Padding\n @Input() padding: string;\n @Input() p: string;\n @Input() paddingLeft: string;\n @Input() pl: string;\n @Input() paddingRight: string;\n @Input() pr: string;\n @Input() paddingTop: string;\n @Input() pt: string;\n @Input() paddingBottom: string;\n @Input() pb: string;\n @Input() paddingX: string;\n @Input() px: string;\n @Input() paddingY: string;\n @Input() py: string;\n\n @HostBinding('class') get hb_padding() {\n return `padding-${this.padding || this.p}`;\n }\n\n @HostBinding('style.padding-left') get hb_padding_left() {\n return getSpacingToken(this.paddingLeft || this.pl || this.px || this.paddingX);\n }\n @HostBinding('style.padding-right') get hb_padding_right() {\n return getSpacingToken(this.paddingRight || this.pr || this.px || this.paddingX);\n }\n @HostBinding('style.padding-top') get hb_padding_top() {\n return getSpacingToken(this.paddingTop || this.pt || this.py || this.paddingY);\n }\n @HostBinding('style.padding-bottom') get hb_padding_bottom() {\n return getSpacingToken(this.paddingBottom || this.pb || this.py || this.paddingY);\n }\n}\n\n@Directive({\n selector: '[gap]',\n standalone: false,\n})\nexport class GapDirective {\n @Input() gap: string;\n\n @HostBinding('style.gap')\n get hb_gap() {\n return getSpacingToken(this.gap);\n }\n}\n","import { NgSwitch } from '@angular/common';\nimport { Directive, DoCheck, Host, Input, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';\n\n@Directive({\n selector: '[novoSwitchCases]',\n standalone: false,\n})\nexport class SwitchCasesDirective implements OnInit, DoCheck {\n private ngSwitch: any;\n private _created = false;\n\n @Input()\n novoSwitchCases: any[];\n\n constructor(private viewContainer: ViewContainerRef, private templateRef: TemplateRef<Object>, @Host() ngSwitch: NgSwitch) {\n this.ngSwitch = ngSwitch;\n }\n\n ngOnInit() {\n (this.novoSwitchCases || []).forEach(() => this.ngSwitch._addCase());\n }\n\n ngDoCheck() {\n let enforce = false;\n (this.novoSwitchCases || []).forEach((value) => (enforce = this.ngSwitch._matchCase(value) || enforce));\n this.enforceState(enforce);\n }\n\n enforceState(created: boolean) {\n if (created && !this._created) {\n this._created = true;\n this.viewContainer.createEmbeddedView(this.templateRef);\n } else if (!created && this._created) {\n this._created = false;\n this.viewContainer.clear();\n }\n }\n}\n","import { Directive, ElementRef, HostBinding, Input } from '@angular/core';\n\n@Directive({\n selector: '[theme]',\n standalone: false,\n})\nexport class ThemeColorDirective {\n @Input() theme: string;\n\n @HostBinding('class')\n get hb_textColor() {\n return `novo-theme-${this.theme}`;\n }\n\n constructor(private el: ElementRef) {}\n}\n","import { Directive, ElementRef, HostBinding, Input } from '@angular/core';\nimport { BooleanInput } from 'novo-elements/utils';\n\n@Directive({\n selector: '[visible]',\n standalone: false,\n})\nexport class VisibleDirective {\n @BooleanInput()\n @Input()\n @HostBinding('class')\n visible: boolean;\n\n @HostBinding('class')\n get hb_visibility() {\n return this.visible ? '' : 'novo-visibility-hidden';\n }\n\n constructor(private el: ElementRef) {}\n}\n","import { Directive, Input, TemplateRef } from '@angular/core';\n\n@Directive({\n selector: '[novoTemplate]',\n standalone: false,\n})\nexport class NovoTemplate {\n @Input() type: string;\n @Input('novoTemplate') name: string;\n\n constructor(public template: TemplateRef<any>) {}\n\n getType(): string {\n return this.name;\n }\n}\n","import { ChangeDetectionStrategy, Component, Inject, Input, Optional, ViewEncapsulation } from '@angular/core';\nimport { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations';\n\n/**\n * Possible states for a pseudo checkbox.\n * @docs-private\n */\nexport type NovoPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate';\nexport type NovoPseudoCheckboxShape = 'box' | 'circle' | 'line';\n\n/**\n * Component that shows a simplified checkbox without including any kind of \"real\" checkbox.\n * Meant to be used when the checkbox is purely decorative and a large number of them will be\n * included, such as for the options in a multi-select. Uses no SVGs or complex animations.\n * Note that theming is meant to be handled by the parent element, e.g.\n * `novo-primary .novo-pseudo-checkbox`.\n *\n * Note that this component will be completely invisible to screen-reader users. This is *not*\n * interchangeable with `<novo-checkbox>` and should *not* be used if the user would directly\n * interact with the checkbox. The pseudo-checkbox should only be used as an implementation detail\n * of more complex components that appropriately handle selected / checked state.\n * @docs-private\n */\n@Component({\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n selector: 'novo-pseudo-checkbox',\n styleUrls: ['pseudo-checkbox.component.scss'],\n template: ` <i\n [class.bhi-checkbox-empty]=\"state === 'unchecked' && shape === 'box'\"\n [class.bhi-checkbox-filled]=\"state === 'checked' && shape === 'box'\"\n [class.bhi-checkbox-indeterminate]=\"state === 'indeterminate' && shape === 'box'\"\n [class.bhi-circle-o]=\"state === 'unchecked' && shape === 'circle'\"\n [class.bhi-check-circle-filled]=\"state === 'checked' && shape === 'circle'\"\n [class.bhi-circle]=\"state === 'indeterminate' && shape === 'circle'\"\n [class.bhi-box-empty]=\"state === 'unchecked' && shape === 'line'\"\n [class.bhi-check]=\"state === 'checked' && shape === 'line'\"\n [class.bhi-box-minus-o]=\"state === 'indeterminate' && shape === 'line'\"\n ></i>`,\n host: {\n class: 'novo-pseudo-checkbox',\n '[class.novo-pseudo-checkbox-indeterminate]': 'state === \"indeterminate\"',\n '[class.novo-pseudo-checkbox-checked]': 'state === \"checked\"',\n '[class.novo-pseudo-checkbox-disabled]': 'disabled',\n '[class._novo-animation-noopable]': '_animationMode === \"NoopAnimations\"',\n },\n standalone: false,\n})\nexport class NovoPseudoCheckbox {\n /** Display state of the checkbox. */\n @Input() state: NovoPseudoCheckboxState = 'unchecked';\n /** Display state of the checkbox. */\n @Input() shape: NovoPseudoCheckboxShape = 'box';\n /** Whether the checkbox is disabled. */\n @Input() disabled: boolean = false;\n\n constructor(@Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode?: string) {}\n}\n","import { NgModule } from '@angular/core';\nimport { NovoPseudoCheckbox } from './pseudo-checkbox/pseudo-checkbox.component';\n\n@NgModule({\n imports: [],\n exports: [NovoPseudoCheckbox],\n declarations: [NovoPseudoCheckbox],\n})\nexport class NovoPseudoCheckboxModule {}\n\nexport * from './pseudo-checkbox/pseudo-checkbox.component';\n","import { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Constructor } from './constructor';\n\n/** @docs-private */\nexport interface CanDisable {\n /** Whether the component is disabled. */\n disabled: boolean;\n}\n\n/** @docs-private */\nexport type CanDisableCtor = Constructor<CanDisable>;\n\n/** Mixin to augment a directive with a `disabled` property. */\nexport function mixinDisabled<T extends Constructor<{}>>(base: T): CanDisableCtor & T {\n return class extends base {\n protected _disabled: boolean = false;\n\n get disabled() {\n return this._disabled;\n }\n set disabled(value: any) {\n this._disabled = coerceBooleanProperty(value);\n }\n\n constructor(...args: any[]) {\n super(...args);\n }\n };\n}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * Describes a parent component that manages a list of options.\n * Contains properties that the options can inherit.\n * @docs-private\n */\nexport interface NovoOptionParentComponent {\n multiple?: boolean;\n inertGroups?: boolean;\n}\n\n/**\n * Injection token used to provide the parent component to options.\n */\nexport const NOVO_OPTION_PARENT_COMPONENT = new InjectionToken<NovoOptionParentComponent>('NOVO_OPTION_PARENT_COMPONENT');\n","import { BooleanInput } from '@angular/cdk/coercion';\nimport { ChangeDetectionStrategy, Component, Directive, Inject, InjectionToken, Optional, ViewEncapsulation } from '@angular/core';\nimport { CanDisable, CanDisableCtor, mixinDisabled } from '../mixins/disabled.mixin';\nimport { NovoOptionParentComponent, NOVO_OPTION_PARENT_COMPONENT } from './option-parent';\n\n// Notes on the accessibility pattern used for `novo-optgroup`.\n// The option group has two different \"modes\": regular and novoInert. The regular mode uses the\n// recommended a11y pattern which has `role=\"group\"` on the group element with `aria-labelledby`\n// pointing to the label. This works for `novo-select`, but it seems to hit a bug for autocomplete\n// under VoiceOver where the group doesn't get read out at all. The bug appears to be that if\n// there's __any__ a11y-related attribute on the group (e.g. `role` or `aria-labelledby`),\n// VoiceOver on Safari won't read it out.\n// We've introduced the `novoInert` mode as a workaround. Under this mode, all a11y attributes are\n// removed from the group, and we get the screen reader to read out the group label by mirroring it\n// inside an invisible element in the option. This is sub-optimal, because the screen reader will\n// repeat the group label on each navigation, whereas the default pattern only reads the group when\n// the user enters a new group. The following alternate approaches were considered:\n// 1. Reading out the group label using the `LiveAnnouncer` solves the problem, but we can't control\n// when the text will be read out so sometimes it comes in too late or never if the user\n// navigates quickly.\n// 2. `<novo-option aria-describedby=\"groupLabel\"` - This works on Safari, but VoiceOver in Chrome\n// won't read out the description at all.\n// 3. `<novo-option aria-labelledby=\"optionLabel groupLabel\"` - This works on Chrome, but Safari\n// doesn't read out the text at all. Furthermore, on\n\n// Boilerplate for applying mixins to NovoOptgroup.\n@Directive()\nexport class NovoOptgroupBase implements CanDisable {\n disabled: boolean;\n\n /** Label for the option group. */\n label: string;\n\n /** Unique id for the underlying label. */\n _labelId: string = `novo-optgroup-label-${_uniqueOptgroupIdCounter++}`;\n\n /** Whether the group is in novoInert a11y mode. */\n _novoInert: boolean;\n}\nexport const NovoOptgroupMixinBase: CanDisableCtor & typeof NovoOptgroupBase = mixinDisabled(NovoOptgroupBase);\n\n// Counter for unique group ids.\nlet _uniqueOptgroupIdCounter = 0;\n\n/**\n * Injection token that can be used to reference instances of `NovoOptgroup`. It serves as\n * alternative token to the actual `NovoOptgroup` class which could cause unnecessary\n * retention of the class and its component metadata.\n */\nexport const NOVO_OPTGROUP = new InjectionToken<NovoOptgroup>('NovoOptgroup');\n\n/**\n * Component that is used to group instances of `novo-option`.\n */\n@Component({\n selector: 'novo-optgroup',\n exportAs: 'novoOptgroup',\n templateUrl: 'optgroup.component.html',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n inputs: ['disabled', 'label'],\n styleUrls: ['optgroup.component.scss'],\n host: {\n class: 'novo-optgroup',\n '[attr.role]': '_novoInert ? null : \"group\"',\n '[attr.aria-disabled]': '_novoInert ? null : disabled.toString()',\n '[attr.aria-labelledby]': '_novoInert ? null : _labelId',\n '[class.novo-optgroup-disabled]': 'disabled',\n },\n providers: [{ provide: NOVO_OPTGROUP, useExisting: NovoOptgroup }],\n standalone: false,\n})\nexport class NovoOptgroup extends NovoOptgroupMixinBase {\n constructor(@Inject(NOVO_OPTION_PARENT_COMPONENT) @Optional() parent?: NovoOptionParentComponent) {\n super();\n this._novoInert = parent?.inertGroups ?? false;\n }\n\n static ngAcceptInputType_disabled: BooleanInput;\n}\n","<span *ngIf=\"label\" class=\"novo-optgroup-label\" aria-hidden=\"true\" [id]=\"_labelId\">{{ label }}</span>\n<ng-content select=\"novo-option, ng-container, novo-divider, cdk-virtual-scroll-viewport\"></ng-content>","import { FocusableOption, FocusOptions, FocusOrigin } from '@angular/cdk/a11y';\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { hasModifierKey } from '@angular/cdk/keycodes';\nimport {\n AfterViewChecked,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n Directive,\n ElementRef,\n EventEmitter,\n Inject,\n Input,\n OnDestroy,\n Optional,\n Output,\n QueryList,\n ViewEncapsulation,\n} from '@angular/core';\nimport { fromEvent, Subject, Subscription } from 'rxjs';\nimport { BooleanInput, Key } from 'novo-elements/utils';\nimport { NovoOptgroup, NovoOptgroupBase, NOVO_OPTGROUP } from './optgroup.component';\nimport { NovoOptionParentComponent, NOVO_OPTION_PARENT_COMPONENT } from './option-parent';\n\n/**\n * Option IDs need to be unique across components, so this counter exists outside of\n * the component definition.\n */\nlet _uniqueIdCounter = 0;\n\n/** Event object emitted by NovoOption when selected or deselected. */\nexport class NovoOptionSelectionChange {\n constructor(\n /** Reference to the option that emitted the event. */\n public source: NovoOptionBase,\n /** Whether the change in the option's value was a result of a user action. */\n public isUserInput = false,\n ) {}\n}\n\n@Directive()\nexport class NovoOptionBase implements FocusableOption, AfterViewChecked, OnDestroy {\n private _selected = false;\n private _active = false;\n private _disabled = false;\n private _mostRecentViewValue = '';\n private _clickCapture: Subscription;\n private _clickPassive: Subscription;\n\n /** TODO: deprecate maybe, check support for table headers */\n @BooleanInput()\n @Input()\n keepOpen: boolean = false;\n\n @BooleanInput()\n @Input()\n novoInert: boolean = false;\n\n @BooleanInput()\n @Input()\n allowSelection = true;\n\n // When selected, use a particular string for display instead of what was used to select it\n @Input()\n customViewValue: string = '';\n\n /** If there is no parent then nothing is managing the selection. */\n get selectable() {\n return this.allowSelection && this._parent;\n }\n\n /** Whether the wrapping component is in multiple selection mode. */\n get multiple() {\n return this._parent && this._parent.multiple;\n }\n\n /** The form value of the option. */\n @Input() value: any;\n\n /** The unique ID of the option. */\n @Input() id: string = `novo-option-${_uniqueIdCounter++}`;\n\n /** Whether the option is disabled. */\n @Input()\n get disabled() {\n return (this.group && this.group.disabled) || this._disabled;\n }\n set disabled(value: any) {\n this._disabled = coerceBooleanProperty(value);\n }\n\n @Input()\n get selected() {\n return this._selected;\n }\n set selected(value: any) {\n this._selected = coerceBooleanProperty(value);\n }\n\n /** Event emitted when the option is selected or deselected. */\n @Output() readonly onSelectionChange = new EventEmitter<NovoOptionSelectionChange>();\n\n /** Emits when the state of the option changes and any parents have to be notified. */\n readonly _stateChanges = new Subject<void>();\n\n constructor(\n private _element: ElementRef<HTMLElement>,\n private _changeDetectorRef: ChangeDetectorRef,\n @Optional() @Inject(NOVO_OPTION_PARENT_COMPONENT) private _parent: NovoOptionParentComponent,\n @Optional() @Inject(NOVO_OPTGROUP) readonly group: NovoOptgroupBase,\n ) {\n // (click) is overridden when defined by user.\n this._clickCapture = fromEvent<MouseEvent>(this._element.nativeElement, 'click', { capture: true }).subscribe((evt: MouseEvent) => {\n this._handleDisabledClick(evt);\n });\n this._clickPassive = fromEvent<MouseEvent>(this._element.nativeElement, 'click').subscribe((evt: MouseEvent) => {\n setTimeout(() => this._handlePassiveClick(evt));\n });\n }\n\n /**\n * Whether or not the option is currently active and ready to be selected.\n * An active option displays styles as if it is focused, but the\n * focus is actually retained somewhere else. This comes in handy\n * for components like autocomplete where focus must remain on the input.\n */\n get active(): boolean {\n return this._active;\n }\n\n /**\n * The displayed value of the option. It is necessary to show the selected option in the\n * select's trigger.\n */\n get viewValue(): string {\n return this.customViewValue || (this._getHostElement().textContent || '').trim();\n }\n\n /** Selects the option. */\n select(): void {\n if (!this._selected) {\n this._selected = true;\n this._changeDetectorRef.markForCheck();\n }\n }\n\n /** Deselects the option. */\n deselect(): void {\n if (this._selected) {\n this._selected = false;\n this._changeDetectorRef.markForCheck();\n }\n }\n\n /** Sets focus onto this option. */\n focus(_origin?: FocusOrigin, options?: FocusOptions): void {\n // Note that we aren't using `_origin`, but we need to keep it because some internal consumers\n // use `NovoOption` in a `FocusKeyManager` and we need it to match `FocusableOption`.\n const element = this._getHostElement();\n\n if (typeof element.focus === 'function') {\n element.focus(options);\n }\n }\n\n /**\n * This method sets display styles on the option to make it appear\n * active. This is used by the ActiveDescendantKeyManager so key\n * events will display the proper options as active on arrow key events.\n */\n setActiveStyles(): void {\n if (!this._active) {\n this._active = true;\n this._changeDetectorRef.markForCheck();\n }\n }\n\n /**\n * This method removes display styles on the option that made it appear\n * active. This is used by the ActiveDescendantKeyManager so key\n * events will display the proper options as active on arrow key events.\n */\n setInactiveStyles(): void {\n if (this._active) {\n this._active = false;\n this._changeDetectorRef.markForCheck();\n }\n }\n\n /** Gets the label to be used when determining whether the option should be focused. */\n getLabel(): string {\n return this.viewValue;\n }\n\n _handleDisabledClick(event: MouseEvent) {\n if (this.disabled) {\n event.preventDefault();\n event.stopPropagation();\n event.stopImmediatePropagation();\n }\n }\n\n _handlePassiveClick(event: MouseEvent) {\n if (!this.novoInert) {\n this._selectViaInteraction();\n }\n }\n\n /** Ensures the option is selected when activated from the keyboard. */\n _handleKeydown(event: KeyboardEvent): void {\n if (event.target instanceof HTMLInputElement && event.key === Key.Enter) {\n this._emitSelectionChangeEvent(!this.keepOpen);\n } else if (\n !(event.target instanceof HTMLInputElement) &&\n (event.key === Key.Enter || event.key === Key.Space) &&\n !hasModifierKey(event)\n ) {\n this._selectViaInteraction();\n // Prevent the page from scrolling down and form submits.\n event.preventDefault();\n }\n }\n\n /**\n * `Selects the option while indicating the selection came from the user. Used to\n * determine if the select's view -> model callback should be invoked.`\n */\n _selectViaInteraction(): void {\n if (!this.disabled) {\n this._selected = this.multiple ? !this._selected : true;\n this._changeDetectorRef.markForCheck();\n this._emitSelectionChangeEvent(!this.keepOpen);\n }\n }\n\n /**\n * Force a click event\n */\n _clickViaInteraction(): void {\n if (!this.disabled) {\n this._element.nativeElement.click();\n }\n }\n\n /**\n * Gets the `aria-selected` value for the option. We explicitly omit the `aria-selected`\n * attribute from single-selection, unselected options. Including the `aria-selected=\"false\"`\n * attributes adds a significant amount of noise to screen-reader users without providing useful\n * information.\n */\n _getAriaSelected(): boolean | null {\n return this.selected || (this.multiple ? false : null);\n }\n\n /** Returns the correct tabindex for the option depending on disabled state. */\n _getTabIndex(): string {\n return this.disabled ? '-1' : '0';\n }\n\n /** Gets the host DOM element. */\n _getHostElement(): HTMLElement {\n return this._element.nativeElement;\n }\n\n ngAfterViewChecked() {\n // Since parent components could be using the option's label to display the selected values\n // (e.g. `novo-select`) and they don't have a way of knowing if the option's label has changed\n // we have to check for changes in the DOM ourselves and dispatch an event. These checks are\n // relatively cheap, however we still limit them only to selected options in order to avoid\n // hitting the DOM too often.\n if (this._selected) {\n const viewValue = this.viewValue;\n\n if (viewValue !== this._mostRecentViewValue) {\n this._mostRecentViewValue = viewValue;\n this._stateChanges.next();\n }\n }\n }\n\n ngOnDestroy() {\n this._stateChanges.complete();\n this._clickCapture.unsubscribe();\n this._clickPassive.unsubscribe();\n }\n\n /** Emits the selection change event. */\n private _emitSelectionChangeEvent(isUserInput = false): void {\n this.onSelectionChange.emit(new NovoOptionSelectionChange(this, isUserInput));\n }\n}\n\n/**\n * Single option inside of a `<novo-select>` element.\n */\n@Component({\n selector: 'novo-option',\n exportAs: 'novoOption',\n host: {\n role: 'option',\n '[id]': 'id',\n '[attr.tabindex]': '_getTabIndex()',\n '[attr.aria-selected]': '_getAriaSelected()',\n '[attr.aria-disabled]': 'disabled.toString()',\n '[class.novo-active]': 'active',\n '[class.novo-selected]': 'selectable && selected',\n '[class.novo-option-multiple]': 'multiple',\n '[class.novo-option-disabled]': 'disabled',\n '[class.novo-option-inert]': 'novoInert',\n '(keydown)': '_handleKeydown($event)',\n class: 'novo-option novo-focus-indicator',\n },\n inputs: ['selected', 'keepOpen', 'novoInert', 'value', 'disabled'],\n styleUrls: ['option.component.scss'],\n templateUrl: 'option.component.html',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n standalone: false,\n})\nexport class NovoOption extends NovoOptionBase {\n constructor(\n element: ElementRef<HTMLElement>,\n changeDetectorRef: ChangeDetectorRef,\n @Optional() @Inject(NOVO_OPTION_PARENT_COMPONENT) parent: NovoOptionParentComponent,\n @Optional() @Inject(NOVO_OPTGROUP) group: NovoOptgroup,\n ) {\n super(element, changeDetectorRef, parent, group);\n }\n}\n\n/**\n * Counts the amount of option group labels that precede the specified option.\n * @param optionIndex Index of the option at which to start counting.\n * @param options Flat list of all of the options.\n * @param optionGroups Flat list of all of the option groups.\n * @docs-private\n */\nexport function _countGroupLabelsBeforeOption(\n optionIndex: number,\n options: QueryList<NovoOption>,\n optionGroups: QueryList<NovoOptgroup>,\n): number {\n if (optionGroups.length) {\n const optionsArray = options.toArray();\n const groups = optionGroups.toArray();\n let groupCounter = 0;\n\n for (let i = 0; i < optionIndex + 1; i++) {\n if (optionsArray[i].group && optionsArray[i].group === groups[groupCounter]) {\n groupCounter++;\n }\n }\n\n return groupCounter;\n }\n\n return 0;\n}\n\n/**\n * Determines the position to which to scroll a panel in order for an option to be into view.\n * @param optionOffset Offset of the option from the top of the panel.\n * @param optionHeight Height of the options.\n * @param currentScrollPosition Current scroll position of the panel.\n * @param panelHeight Height of the panel.\n * @docs-private\n */\nexport function _getOptionScrollPosition(\n optionOffset: number,\n optionHeight: number,\n currentScrollPosition: number,\n panelHeight: number,\n): number {\n if (optionOffset < currentScrollPosition) {\n return optionOffset;\n }\n\n if (optionOffset + optionHeight > currentScrollPosition + panelHeight) {\n return Math.max(0, optionOffset - panelHeight + optionHeight);\n }\n\n return currentScrollPosition;\n}\n","<novo-pseudo-checkbox *ngIf=\"selectable && multiple\" class=\"novo-option-pseudo-checkbox\"\n [state]=\"selected ? 'checked' : 'unchecked'\" [disabled]=\"disabled\"></novo-pseudo-checkbox>\n\n<span class=\"novo-option-text\">\n <ng-content></ng-content>\n</span>\n\n<novo-pseudo-checkbox *ngIf=\"selectable && !multiple && selected\" class=\"novo-option-pseudo-checkbox\" state=\"checked\"\n shape=\"line\"\n [disabled]=\"disabled\"></novo-pseudo-checkbox>\n\n<ng-content select=\"[novoSuffix]\"></ng-content>\n<!-- See a11y notes inside optgroup.ts for context behind this element. -->\n<span class=\"cdk-visually-hidden\" *ngIf=\"group && group._novoInert\">({{ group.label }})</span>","import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { NovoPseudoCheckboxModule } from '../selection/index';\nimport { NovoOptgroup } from './optgroup.component';\nimport { NovoOption } from './option.component';\n\n@NgModule({\n imports: [CommonModule, NovoPseudoCheckboxModule],\n exports: [NovoOption, NovoOptgroup],\n declarations: [NovoOption, NovoOptgroup],\n})\nexport class NovoOptionModule {}\n\nexport * from './optgroup.component';\nexport * from './option-parent';\nexport * from './option.component';\n","import { Directive, ElementRef, HostBinding, Input } from '@angular/core';\nimport { BooleanInput } from 'novo-elements/utils';\nimport { TypographyLength, TypographySize, TypographyWeight } from '../text.types';\n\n@Directive()\nexport class NovoBaseTextElement {\n @Input()\n size: TypographySize;\n @Input()\n weight: TypographyWeight;\n @Input()\n lineLength: TypographyLength;\n @Input()\n color: string;\n\n @HostBinding('class')\n get hb_classBinding(): string {\n return [\n this.color ? `text-color-${this.color}` : null,\n this.lineLength ? `text-length-${this.lineLength}` : null,\n this.size ? `text-size-${this.size}` : null,\n this.weight ? `text-weight-${this.weight}` : null,\n ]\n .filter(Boolean)\n .join(' ');\n }\n\n @HostBinding('class.text-disabled')\n @Input()\n @BooleanInput()\n disabled: boolean;\n\n @HostBinding('class.text-color-empty')\n @Input()\n @BooleanInput()\n muted: boolean;\n\n @HostBinding('class.text-color-negative')\n @Input()\n @BooleanInput()\n error: boolean;\n\n @HostBinding('class.margin-before')\n @Input()\n @BooleanInput()\n marginBefore: boolean;\n\n @HostBinding('class.margin-after')\n @Input()\n @BooleanInput()\n marginAfter: boolean;\n\n @HostBinding('class.text-capitialize')\n @Input()\n @BooleanInput()\n capitialize: boolean;\n\n @HostBinding('class.text-uppercase')\n @Input()\n @BooleanInput()\n uppercase: boolean;\n\n @HostBinding('class.text-nowrap')\n @Input()\n @BooleanInput()\n nowrap: boolean;\n\n @HostBinding('class.text-ellipsis')\n @Input()\n @BooleanInput()\n ellipsis: boolean;\n\n @HostBinding('class.text-size-smaller')\n @Input()\n @BooleanInput()\n smaller: boolean;\n\n @HostBinding('class.text-size-larger')\n @Input()\n @BooleanInput()\n larger: boolean;\n\n @HostBinding('class.text-weight-thin')\n @Input()\n @BooleanInput()\n thin: boolean;\n\n @HostBinding('class.text-weight-lighter')\n @Input()\n @BooleanInput()\n lighter: boolean;\n\n @HostBinding('class.text-weight-light')\n @Input()\n @BooleanInput()\n light: boolean;\n\n @HostBinding('class.text-weight-medium')\n @Input()\n @BooleanInput()\n medium: boolean;\n\n @HostBinding('class.text-weight-bold')\n @Input()\n @BooleanInput()\n bold: boolean;\n\n @HostBinding('class.text-weight-bolder')\n @Input()\n @BooleanInput()\n bolder: boolean;\n\n @HostBinding('class.text-weight-extrabold')\n @Input()\n @BooleanInput()\n extrabold: boolean;\n\n constructor(public element: ElementRef) {}\n\n get nativeElement() {\n return this.element.nativeElement;\n }\n}\n","// NG2\nimport { Component } from '@angular/core';\nimport { NovoBaseTextElement } from '../base/base-text.component';\n\n/**\n * Tag Example\n * <novo-title size=\"sm\" disabled>Label</novo-title\n * <novo-title small disabled>Label</novo-title>\n * <novo-title large disabled>Label</novo-title>\n * <novo-title error>Label</novo-title>\n * <novo-title muted>Label</novo-title>\n * <novo-title class=\"tc-grapefruit\">Label</novo-title>\n * <novo-title color=\"grapefruit\">Label</novo-title>\n */\n\n@Component({\n selector: 'novo-caption,[novo-caption]',\n template: ' <ng-content></ng-content> ',\n styleUrls: ['./caption.scss'],\n host: {\n class: 'novo-caption',\n },\n standalone: false,\n})\nexport class NovoCaption extends NovoBaseTextElement {}\n","// NG2\nimport { Component, HostBinding, input, OnInit } from '@angular/core';\nimport { NovoBaseTextElement } from '../base/base-text.component';\n\n/**\n * Tag Example\n * <novo-label size=\"sm\" disabled>Label</novo-label\n * <novo-label small disabled>Label</novo-label>\n * <novo-label large disabled>Label</novo-label>\n * <novo-label error>Label</novo-label>\n * <novo-label muted>Label</novo-label>\n * <novo-label class=\"tc-grapefruit\">Label</novo-label>\n * <novo-label color=\"grapefruit\">Label</novo-label>\n */\n\nlet nextId = 0;\n\n@Component({\n selector: 'novo-label,[novo-label]',\n template: ' <ng-content></ng-content> ',\n styleUrls: ['./label.scss'],\n host: {\n class: 'novo-label',\n },\n standalone: false,\n})\nexport class NovoLabel extends NovoBaseTextElement implements OnInit{\n @HostBinding('attr.id')\n public id: string;\n\n inputId = input(null, { alias: 'id' });\n\n ngOnInit() {\n this.id = this.inputId() || `novo-label-${++nextId}`;\n }\n}\n\n","// NG2\nimport { Component, Input, ViewEncapsulation } from '@angular/core';\nimport { NovoBaseTextElement } from '../base/base-text.component';\n\n/**\n * Tag Example\n * <novo-text size=\"small\" disabled>Label</novo-text\n * <novo-text small disabled>Label</novo-text>\n * <novo-text large disabled>Label</novo-text>\n * <novo-text error>Label</novo-text>\n * <novo-text muted>Label</novo-text>\n * <novo-text class=\"tc-grapefruit\">Label</novo-text>\n * <novo-text color=\"grapefruit\">Label</novo-text>\n */\n\n@Component({\n selector: 'novo-link',\n template: '<a [attr.href]=\"href\"><ng-content></ng-content></a>',\n styleUrls: ['./link.scss'],\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'novo-link',\n },\n standalone: false,\n})\nexport class NovoLink extends NovoBaseTextElement {\n @Input()\n href: string;\n}\n","// NG2\nimport { Component, HostBinding, Input, ViewEncapsulation } from '@angular/core';\nimport { BooleanInput } from 'novo-elements/utils';\nimport { NovoBaseTextElement } from '../base/base-text.component';\n\n/**\n * Tag Example\n * <novo-text size=\"small\" disabled>Label</novo-text\n * <novo-text small disabled>Label</novo-text>\n * <novo-text large disabled>Label</novo-text>\n * <novo-text error>Label</novo-text>\n * <novo-text muted>Label</novo-text>\n * <novo-text class=\"tc-grapefruit\">Label</novo-text>\n * <novo-text color=\"grapefruit\">Label</novo-text>\n */\n\n@Component({\n selector: 'novo-text,[novo-text]',\n template: ' <ng-content></ng-content> ',\n styleUrls: ['./text.scss'],\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'novo-text',\n },\n standalone: false,\n})\nexport class NovoText extends NovoBaseTextElement {\n @HostBinding('class.text-block')\n @Input()\n @BooleanInput()\n block: boolean;\n}\n","// NG2\nimport { Component } from '@angular/core';\nimport { NovoBaseTextElement } from '../base/base-text.component';\nimport { TypographyWeight } from '../text.types';\n\n/**\n * Tag Example\n * <novo-title size=\"sm\" disabled>Label</novo-title\n * <novo-title small disabled>Label</novo-title>\n * <novo-title large disabled>Label</novo-title>\n * <novo-title error>Label</novo-title>\n * <novo-title muted>Label</novo-title>\n * <novo-title class=\"tc-grapefruit\">Label</novo-title>\n * <novo-title color=\"grapefruit\">Label</novo-title>\n */\n\n@Component({\n selector: 'novo-title,[novo-title]',\n template: ' <ng-content></ng-content> ',\n styleUrls: ['./title.scss'],\n host: {\n class: 'novo-title',\n },\n standalone: false,\n})\nexport class NovoTitle extends NovoBaseTextElement {\n weight: TypographyWeight = 'medium';\n}\n","import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { AccentColorDirective } from './directives/accent.directive';\nimport { BackgroundColorDirective } from './directives/bg.directive';\nimport { BorderDirective } from './directives/border.directive';\nimport { TextColorDirective } from './directives/color.directive';\nimport { FillColorDirective } from './directives/fill.directive';\nimport { FlexDirective } from './directives/flex.directive';\nimport { GapDirective, MarginDirective, PaddingDirective } from './directives/space.directive';\nimport { SwitchCasesDirective } from './directives/switch-cases.directive';\nimport { ThemeColorDirective } from './directives/theme.directive';\nimport { VisibleDirective } from './directives/visible.directive';\nimport { NovoTemplate } from './novo-template/novo-template.directive';\nimport { NovoOptionModule } from './option';\nimport { NovoCaption } from './typography/caption/caption.component';\nimport { NovoLabel } from './typography/label/label.component';\nimport { NovoLink } from './typography/link/link.component';\nimport { NovoText } from './typography/text/text.component';\nimport { NovoTitle } from './typography/title/title.component';\n\n@NgModule({\n imports: [CommonModule, NovoOptionModule],\n exports: [\n NovoTemplate,\n NovoText,\n NovoTitle,\n NovoCaption,\n NovoLabel,\n NovoLink,\n MarginDirective,\n PaddingDirective,\n BackgroundColorDirective,\n TextColorDirective,\n BorderDirective,\n GapDirective,\n AccentColorDirective,\n FillColorDirective,\n FlexDirective,\n ThemeColorDirective,\n SwitchCasesDirective,\n VisibleDirective,\n ],\n declarations: [\n NovoTemplate,\n NovoText,\n NovoTitle,\n NovoCaption,\n NovoLabel,\n NovoLink,\n MarginDirective,\n PaddingDirective,\n BackgroundColorDirective,\n TextColorDirective,\n BorderDirective,\n GapDirective,\n AccentColorDirective,\n FillColorDirective,\n FlexDirective,\n ThemeColorDirective,\n SwitchCasesDirective,\n VisibleDirective,\n ],\n})\nexport class NovoCommonModule {}\n","import { Injectable } from '@angular/core';\nimport { FormControl, FormGroupDirective, NgForm } from '@angular/forms';\n\n/** Error state matcher that matches when a control is invalid and dirty. */\n@Injectable()\nexport class ShowOnDirtyErrorStateMatcher implements ErrorStateMatcher {\n isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {\n return !!(control && control.invalid && (control.dirty || (form && form.submitted)));\n }\n}\n\n/** Provider that defines how form controls behave with regards to displaying error messages. */\n@Injectable({ providedIn: 'root' })\nexport class ErrorStateMatcher {\n isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {\n return !!(control && control.invalid && (control.touched || (form && form.submitted)));\n }\n}\n","import { Constructor } from './constructor';\nimport { HasElementRef } from './types';\n\n/** @docs-private */\nexport interface CanColor {\n /** Theme color palette for the component. */\n color: ThemePalette;\n\n /** Default color to fall back to if no value is set. */\n defaultColor: ThemePalette | undefined;\n}\n\n/** @docs-private */\nexport type CanColorCtor = Constructor<CanColor>;\n\n/** Possible color palette values. */\nexport type ThemePalette = 'primary' | 'accent' | 'warn' | undefined;\n\n/** Mixin to augment a directive with a `color` property. */\nexport function mixinColor<T extends Constructor<HasElementRef>>(base: T, defaultColor?: ThemePalette): CanColorCtor & T {\n return class extends base {\n private _color: ThemePalette;\n defaultColor = defaultColor;\n\n get color(): ThemePalette {\n return this._color;\n }\n set color(value: ThemePalette) {\n const colorPalette = value || this.defaultColor;\n\n if (colorPalette !== this._color) {\n if (this._color) {\n this._elementRef.nativeElement.classList.remove(`novo-color-${this._color}`);\n }\n if (colorPalette) {\n this._elementRef.nativeElement.classList.add(`novo-color-${colorPalette}`);\n }\n\n this._color = colorPalette;\n }\n }\n\n constructor(...args: any[]) {\n super(...args);\n\n // Set the default color that can be specified from the mixin.\n this.color = defaultColor;