Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
@twnd/ux / button / button.ts
Size: Mime:
/**
 * @license
 * FOURBURNER CONFIDENTIAL
 * Unpublished Copyright (C) 2021 FourBurner Technologies, Inc. All Rights Reserved.
 *
 * NOTICE: All information contained herein is, and remains the property of FOURBURNER TECHNOLOGIES,
 * INC. The intellectual and technical concepts contained herein are proprietary to FOURBURNER
 * TECHNOLOGIES, INC. and may be covered by U.S. and Foreign Patents, patents in process, and are
 * protected by trade secret or copyright law. Dissemination of this information or reproduction of
 * this material is strictly forbidden unless prior written permission is obtained from FOURBURNER
 * TECHNOLOGIES, INC. Access to the source code contained herein is hereby forbidden to anyone
 * except current FOURBURNER TECHNOLOGIES, INC. employees, managers or contractors who have executed
 * Confidentiality and Non-disclosure agreements explicitly covering such access.
 *
 * The copyright notice above does not evidence any actual or intended publication or disclosure of
 * this source code, which includes information that is confidential and/or proprietary, and is a
 * trade secret, of FOURBURNER TECHNOLOGIES, INC. ANY REPRODUCTION, MODIFICATION, DISTRIBUTION,
 * PUBLIC PERFORMANCE, OR PUBLIC DISPLAY OF OR THROUGH USE OF THIS SOURCE CODE WITHOUT THE EXPRESS
 * WRITTEN CONSENT OF FOURBURNER TECHNOLOGIES, INC. IS STRICTLY PROHIBITED, AND IN VIOLATION OF
 * APPLICABLE LAWS AND INTERNATIONAL TREATIES. THE RECEIPT OR POSSESSION OF THIS SOURCE CODE AND/OR
 * RELATED INFORMATION DOES NOT CONVEY OR IMPLY ANY RIGHTS TO REPRODUCE, DISCLOSE OR DISTRIBUTE ITS
 * CONTENTS, OR TO MANUFACTURE, USE, OR SELL ANYTHING THAT IT MAY DESCRIBE, IN WHOLE OR IN PART.
 */

import {FocusMonitor, FocusableOption, FocusOrigin} from '@angular/cdk/a11y';
import {
  ChangeDetectionStrategy,
  Component,
  ElementRef,
  OnDestroy,
  ViewChild,
  ViewEncapsulation,
  Optional,
  Inject,
  Input,
  AfterViewInit,
} from '@angular/core';
import {
  CanColor,
  CanDisable,
  CanDisableRipple,
  TWNDRipple,
mixinColor,
  mixinDisabled,
  mixinDisableRipple,
} from '@twnd/ux/core';
import {ANIMATION_MODULE_TYPE} from '@angular/platform-browser/animations';

/** Default color palette for round buttons (twnd-fab and twnd-mini-fab) */
const DEFAULT_ROUND_BUTTON_COLOR = 'accent';

/**
 * List of classes to add to TWNDButton instances based on host attributes to
 * style as different variants.
 */
const BUTTON_HOST_ATTRIBUTES = [
  'twnd-button',
  'twnd-flat-button',
  'twnd-icon-button',
  'twnd-raised-button',
  'twnd-stroked-button',
  'twnd-mini-fab',
  'twnd-fab',
];

// Boilerplate for applying mixins to TWNDButton.
const _TWNDButtonBase = mixinColor(
  mixinDisabled(
    mixinDisableRipple(
      class {
        constructor(public _elementRef: ElementRef) {}
      },
      ),
    ),
);

/**
 * TWND UX design button.
 */

/* clang-format off */
@Component({
  selector : `button[twnd-button], button[twnd-raised-button], button[twnd-icon-button],
              button[twnd-fab], button[twnd-mini-fab], button[twnd-stroked-button],
              button[twnd-flat-button]`,
  exportAs : 'twndButton',
  host : {
    '[attr.disabled]' : 'disabled || null',
    '[class._twnd-animation-noopable]' : '_animationMode === "NoopAnimations"',
    // Add a class for disabled button styling instead of the using attribute
    // selector or pseudo-selector.  This allows users to create focusabled
    // disabled buttons without recreating the styles.
    '[class.twnd-button-disabled]' : 'disabled',
    'class' : 'twnd-focus-indicator',
  },
  templateUrl : 'button.html',
  inputs : [ 'disabled', 'disableRipple', 'color' ],
  encapsulation : ViewEncapsulation.None,
  changeDetection : ChangeDetectionStrategy.OnPush,
})
/* clang-format on */


export class TWNDButton extends _TWNDButtonBase implements AfterViewInit, OnDestroy, CanDisable,
                                                           CanColor, CanDisableRipple,
                                                           FocusableOption
{
  /** Whether the button is round. */
  readonly isRoundButton: boolean = this._hasHostAttributes('twnd-fab', 'twnd-mini-fab');

  /** Whether the button is icon button. */
  readonly isIconButton: boolean = this._hasHostAttributes('twnd-icon-button');

  /** Reference to the TWNDRipple instance of the button. */
  @ViewChild(TWNDRipple) ripple: TWNDRipple;

  constructor(
    elementRef: ElementRef,
    private _focusMonitor: FocusMonitor,
    @Optional() @Inject(ANIMATION_MODULE_TYPE) public _animationMode: string,
  )
  {
    super(elementRef);

    // For each of the variant selectors that is present in the button's host
    // attributes, add the correct corresponding class.
    for (const attr of BUTTON_HOST_ATTRIBUTES) {
      if (this._hasHostAttributes(attr)) {
        (this._getHostElement() as HTMLElement).classList.add(attr);
      }
    }

    // Add a class that applies to all buttons. This makes it easier to target if somebody
    // wants to target all TWND UX buttons. We do it here rather than `host` to ensure that
    // the class is applied to derived classes.
    elementRef.nativeElement.classList.add('twnd-button-base');

    if (this.isRoundButton) {
      this.color = DEFAULT_ROUND_BUTTON_COLOR;
    }
  }

  ngAfterViewInit()
  {
    this._focusMonitor.monitor(this._elementRef, true);
  }

  ngOnDestroy()
  {
    this._focusMonitor.stopMonitoring(this._elementRef);
  }

  /** Focuses the button. */
  focus(origin?: FocusOrigin, options?: FocusOptions): void
  {
    if (origin) {
      this._focusMonitor.focusVia(this._getHostElement(), origin, options);
    } else {
      this._getHostElement().focus(options);
    }
  }

  _getHostElement()
  {
    return this._elementRef.nativeElement;
  }

  _isRippleDisabled()
  {
    return this.disableRipple || this.disabled;
  }

  /** Gets whether the button has one of the given attributes. */
  _hasHostAttributes(...attributes: string[])
  {
    return attributes.some(attribute => this._getHostElement().hasAttribute(attribute));
  }
}

/**
 * TWND UX anchor button.
 */
@Component({
  /* clang-format off */
  selector : `a[twnd-button], a[twnd-raised-button], a[twnd-icon-button], a[twnd-fab],
              a[twnd-mini-fab], a[twnd-stroked-button], a[twnd-flat-button]`,
  exportAs : 'twndButton, twndAnchor',
  host : {
    // Note that we ignore the user-specified tabindex when it's disabled for
    // consistency with the `twnd-button` applied on native buttons where even
    // though they have an index, they're not tabbable.
    '[attr.tabindex]' : 'disabled ? -1 : (tabIndex || 0)',
    '[attr.disabled]' : 'disabled || null',
    '[attr.aria-disabled]' : 'disabled.toString()',
    '(click)' : '_haltDisabledEvents($event)',
    '[class._twnd-animation-noopable]' : '_animationMode === "NoopAnimations"',
    '[class.twnd-button-disabled]' : 'disabled',
    'class' : 'twnd-focus-indicator',
  },
  inputs : [ 'disabled', 'disableRipple', 'color' ],
  templateUrl : 'button.html',
  encapsulation : ViewEncapsulation.None,
  changeDetection : ChangeDetectionStrategy.OnPush,
  /* clang-format on */
})
export class TWNDAnchor extends TWNDButton
{
  /** Tabindex of the button. */
  @Input() tabIndex: number;

  constructor(
    focusMonitor: FocusMonitor,
    elementRef: ElementRef,
    @Optional() @Inject(ANIMATION_MODULE_TYPE) animationMode: string,
  )
  {
    super(elementRef, focusMonitor, animationMode);
  }

  _haltDisabledEvents(event: Event)
  {
    // A disabled button shouldn't apply any actions
    if (this.disabled) {
      event.preventDefault();
      event.stopImmediatePropagation();
    }
  }
}