blob: ac1c8581ad1e5b9df5de5901d323a7b1a4d01b1a [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
import {CrIconButtonElement} from 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
import {assert} from 'chrome://resources/js/assert_ts.js';
import {beforeNextRender, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {getTemplate} from './viewer-pen-options.html.js';
interface Color {
name: string;
color: string;
outline?: boolean;
}
const colors: Color[] = [
// row 1
{name: 'annotationColorBlack', color: '#000000'},
{name: 'annotationColorRed', color: '#ff5252'},
{name: 'annotationColorYellow', color: '#ffbc00'},
{name: 'annotationColorGreen', color: '#00c853'},
{name: 'annotationColorCyan', color: '#00b0ff'},
{name: 'annotationColorPurple', color: '#d500f9'},
{name: 'annotationColorBrown', color: '#8d6e63'},
// row 2
{name: 'annotationColorWhite', color: '#fafafa', outline: true},
{name: 'annotationColorCrimson', color: '#a52714'},
{name: 'annotationColorAmber', color: '#ee8100'},
{name: 'annotationColorAvocadoGreen', color: '#558b2f'},
{name: 'annotationColorCobaltBlue', color: '#01579b'},
{name: 'annotationColorDeepPurple', color: '#8e24aa'},
{name: 'annotationColorDarkBrown', color: '#4e342e'},
// row 3
{name: 'annotationColorDarkGrey', color: '#90a4ae'},
{name: 'annotationColorHotPink', color: '#ff4081'},
{name: 'annotationColorOrange', color: '#ff6e40'},
{name: 'annotationColorLime', color: '#aeea00'},
{name: 'annotationColorBlue', color: '#304ffe'},
{name: 'annotationColorViolet', color: '#7c4dff'},
{name: 'annotationColorTeal', color: '#1de9b6'},
// row 4
{name: 'annotationColorLightGrey', color: '#cfd8dc'},
{name: 'annotationColorLightPink', color: '#f8bbd0'},
{name: 'annotationColorLightOrange', color: '#ffccbc'},
{name: 'annotationColorLightGreen', color: '#f0f4c3'},
{name: 'annotationColorLightBlue', color: '#9fa8da'},
{name: 'annotationColorLavender', color: '#d1c4e9'},
{name: 'annotationColorLightTeal', color: '#b2dfdb'},
];
interface Size {
name: string;
size: number;
}
const sizes: Size[] = [
{name: 'annotationSize1', size: 0},
{name: 'annotationSize2', size: 0.1429},
{name: 'annotationSize3', size: 0.2857},
{name: 'annotationSize4', size: 0.4286},
{name: 'annotationSize8', size: 0.5714},
{name: 'annotationSize12', size: 0.7143},
{name: 'annotationSize16', size: 0.8571},
{name: 'annotationSize20', size: 1},
];
export interface ViewerPenOptionsElement {
$: {
colors: HTMLElement,
expand: CrIconButtonElement,
separator: HTMLElement,
};
}
// Displays a set of radio buttons to select from a predefined list of colors
// and sizes.
export class ViewerPenOptionsElement extends PolymerElement {
static get is() {
return 'viewer-pen-options';
}
static get template() {
return getTemplate();
}
static get properties() {
return {
expanded_: {
type: Boolean,
value: false,
},
selectedSize: {
type: Number,
value: 0.250,
notify: true,
},
selectedColor: {
type: String,
value: '#000000',
notify: true,
},
sizes_: {
type: Array,
value: sizes,
},
colors_: {
type: Array,
value: colors,
},
strings: Object,
};
}
selectedSize: number;
selectedColor: string;
strings: any;
private colors_: Color[];
private expanded_: boolean;
private expandAnimations_: Animation[]|null = null;
private sizes_: Size[];
private sizeChanged_(e: Event) {
this.selectedSize = Number((e.target as HTMLInputElement).value);
}
private colorChanged_(e: Event) {
this.selectedColor = (e.target as HTMLInputElement).value;
}
private toggleExpanded_() {
this.expanded_ = !this.expanded_;
this.updateExpandedState_();
}
private updateExpandedStateAndFinishAnimations_() {
this.updateExpandedState_();
assert(this.expandAnimations_);
for (const animation of this.expandAnimations_) {
animation.finish();
}
}
override connectedCallback() {
super.connectedCallback();
beforeNextRender(this, () => {
this.updateExpandedStateAndFinishAnimations_();
});
}
/**
* Updates the state of the UI to reflect the current value of `expanded`.
* Starts or reverses animations and enables/disable controls.
*/
private updateExpandedState_() {
const colors = this.$.colors;
if (!this.expandAnimations_) {
const separator = this.$.separator;
const expand = this.$.expand;
this.expandAnimations_ = [
colors.animate(
[
{height: '32px'},
{height: '188px'},
],
{
easing: 'ease-in-out',
duration: 250,
fill: 'both',
}),
separator.animate(
[
{opacity: 0},
{opacity: 1},
],
{
easing: 'ease-in-out',
duration: 250,
fill: 'both',
}),
expand.animate(
[
{transform: 'rotate(0deg)'},
{transform: 'rotate(180deg)'},
],
{
easing: 'ease-in-out',
duration: 250,
fill: 'forwards',
}),
];
}
for (const animation of this.expandAnimations_) {
// TODO(dstockwell): Ideally we would just set playbackRate,
// but there appears to be a web-animations bug that
// results in the animation getting stuck in the 'pending'
// state sometimes. See crbug.com/938857
const currentTime = animation.currentTime;
animation.cancel();
animation.playbackRate = this.expanded_ ? 1 : -1;
animation.currentTime = currentTime;
animation.play();
}
for (const input of colors.querySelectorAll('input:nth-child(n+8)')) {
input.toggleAttribute('disabled', !this.expanded_);
}
}
/** Used to determine equality in computed bindings. */
private equal_<T>(a: T, b: T): boolean {
return a === b;
}
/** Used to lookup a string in a computed binding. */
private lookup_(strings: {[key: string]: string}, name: string): string {
return strings ? strings[name] : '';
}
/**
* Used to remove focus when clicking or tapping on a styled input
* element. This is a workaround until we can use the :focus-visible
* pseudo selector.
*/
blurOnPointerDown(e: Event) {
const target = e.target as HTMLInputElement;
setTimeout(() => target.blur(), 0);
}
}
declare global {
interface HTMLElementTagNameMap {
'viewer-pen-options': ViewerPenOptionsElement;
}
}
customElements.define(ViewerPenOptionsElement.is, ViewerPenOptionsElement);