IconElement.ts 4.28 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

import module = require('module');
Benjamin Franzke's avatar
Benjamin Franzke committed
15
16
17
18
import {html, css, unsafeCSS, LitElement, TemplateResult, CSSResult} from 'lit';
import {customElement, property} from 'lit/decorators';
import {unsafeHTML} from 'lit/directives/unsafe-html';
import {until} from 'lit/directives/until';
19
20
21
22
import {Sizes, States, MarkupIdentifiers} from '../Enum/IconTypes';
import Icons = require('../Icons');
import 'TYPO3/CMS/Backend/Element/SpinnerElement';

Benjamin Franzke's avatar
Benjamin Franzke committed
23
24
25
26
27
28
29
30
const iconUnifyModifier = 0.86;
const iconSize = (identifier: CSSResult, size: number) => css`
  :host([size=${identifier}]),
  :host([raw]) .icon-size-${identifier} {
    font-size: ${size}px;
  }
`;

31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
 * Module: TYPO3/CMS/Backend/Element/IconElement
 *
 * @example
 * <typo3-backend-icon identifier="data-view-page" size="small"></typo3-backend-icon>
 */
@customElement('typo3-backend-icon')
export class IconElement extends LitElement {
  @property({type: String}) identifier: string;
  @property({type: String, reflect: true}) size: Sizes = Sizes.default;
  @property({type: String}) state: States = States.default;
  @property({type: String}) overlay: string = null;
  @property({type: String}) markup: MarkupIdentifiers = MarkupIdentifiers.inline;

  /**
   * @internal Usage of `raw` attribute is discouraged due to security implications.
   *
   * The `raw` attribute value will be rendered unescaped into DOM as raw html (.innerHTML = raw).
   * That means it is the responsibility of the callee to ensure the HTML string does not contain
   * user supplied strings.
   * This attribute should therefore only be used to preserve backwards compatibility,
   * and must not be used in new code or with user supplied strings.
   * Use `identifier` attribute if ever possible instead.
   */
  @property({type: String}) raw?: string = null;

Benjamin Franzke's avatar
Benjamin Franzke committed
57
58
59
60
61
62
63
64
  static styles = [
    css`
      :host {
        display: flex;
        font-size: 1em;
        width: 1em;
        height: 1em;
        line-height: 0;
65
66
      }

Benjamin Franzke's avatar
Benjamin Franzke committed
67
68
69
70
71
72
73
74
75
76
77
78
      typo3-backend-spinner {
        font-size: 1em;
      }
      .icon {
        position: relative;
        display: block;
        overflow: hidden;
        white-space: nowrap;
        height: 1em;
        width: 1em;
        line-height: 1;
      }
79

Benjamin Franzke's avatar
Benjamin Franzke committed
80
81
82
83
84
85
86
      .icon svg,
      .icon img {
        display: block;
        height: 1em;
        width: 1em;
        transform: translate3d(0, 0, 0);
      }
87

Benjamin Franzke's avatar
Benjamin Franzke committed
88
89
90
91
      .icon * {
        display: block;
        line-height: inherit;
      }
92

Benjamin Franzke's avatar
Benjamin Franzke committed
93
94
95
96
97
98
99
100
101
102
103
      .icon-markup {
        position: absolute;
        display: flex;
        justify-content: center;
        align-items: center;
        text-align: center;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
      }
104

Benjamin Franzke's avatar
Benjamin Franzke committed
105
106
107
108
109
110
111
      .icon-overlay {
        position: absolute;
        bottom: 0;
        right: 0;
        font-size: 0.6875em;
        text-align: center;
      }
112

Benjamin Franzke's avatar
Benjamin Franzke committed
113
114
115
      .icon-color {
        fill: currentColor;
      }
116

Benjamin Franzke's avatar
Benjamin Franzke committed
117
118
119
      .icon-state-disabled .icon-markup {
        opacity: .5;
      }
120

Benjamin Franzke's avatar
Benjamin Franzke committed
121
122
123
124
      .icon-unify {
        font-size: ${iconUnifyModifier}em;
        line-height: ${1 / iconUnifyModifier};
      }
125

Benjamin Franzke's avatar
Benjamin Franzke committed
126
127
128
      .icon-spin .icon-markup {
        animation: icon-spin 2s infinite linear;
      }
129

Benjamin Franzke's avatar
Benjamin Franzke committed
130
131
132
      @keyframes icon-spin {
        0% {
          transform: rotate(0deg);
133
134
        }

Benjamin Franzke's avatar
Benjamin Franzke committed
135
136
137
138
139
140
141
142
143
144
        100% {
          transform: rotate(360deg);
        }
      }
    `,
    iconSize(unsafeCSS(Sizes.small), 16),
    iconSize(unsafeCSS(Sizes.default), 32),
    iconSize(unsafeCSS(Sizes.large), 48),
    iconSize(unsafeCSS(Sizes.mega), 64),
  ];
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163

  public render(): TemplateResult {
    if (this.raw) {
      return html`${unsafeHTML(this.raw)}`;
    }

    if (!this.identifier) {
      return html``;
    }

    const icon = Icons.getIcon(this.identifier, this.size, this.overlay, this.state, this.markup)
      .then((markup: string) => {
        return html`
          ${unsafeHTML(markup)}
        `;
      });
    return html`${until(icon, html`<typo3-backend-spinner></typo3-backend-spinner>`)}`;
  }
}