UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

359 lines (355 loc) • 13.9 kB
// ***************************************************************************** // Copyright (C) 2019 Ericsson and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** /** * Namespace for the decoration data and the styling refinements for the decorated widgets. */ export namespace WidgetDecoration { /** * CSS styles for the decorators. */ export namespace Styles { export const CAPTION_HIGHLIGHT_CLASS = 'theia-caption-highlight'; export const CAPTION_PREFIX_CLASS = 'theia-caption-prefix'; export const CAPTION_SUFFIX_CLASS = 'theia-caption-suffix'; export const ICON_WRAPPER_CLASS = 'theia-icon-wrapper'; export const DECORATOR_SIZE_CLASS = 'theia-decorator-size'; export const DECORATOR_SIDEBAR_SIZE_CLASS = 'theia-decorator-sidebar-size'; export const TOP_RIGHT_CLASS = 'theia-top-right'; export const BOTTOM_RIGHT_CLASS = 'theia-bottom-right'; export const BOTTOM_RIGHT_SIDEBAR_CLASS = 'theia-bottom-right-sidebar'; export const BOTTOM_LEFT_CLASS = 'theia-bottom-left'; export const TOP_LEFT_CLASS = 'theia-top-left'; } /** * For the sake of simplicity, we have merged the `font-style`, `font-weight`, and the `text-decoration` together. */ export type FontStyle = 'normal' | 'bold' | 'italic' | 'oblique' | 'underline' | 'line-through'; /** * A string that could be: * * - one of the browser colors, (E.g.: `blue`, `red`, `magenta`), * - the case insensitive hexadecimal color code, (for instance, `#ee82ee`, `#20B2AA`, `#f09` ), or * - either the `rgb()` or the `rgba()` functions. * * For more details, see: https://developer.mozilla.org/en-US/docs/Web/CSS/color_value. * * Note, it is highly recommended to use one of the predefined colors of Theia, so the desired color will * look nice with both the `light` and the `dark` theme too. */ export type Color = string; /** * Encapsulates styling information of the font. */ export interface FontData { /** * Zero to any font style. */ readonly style?: FontStyle | FontStyle[]; /** * The color of the font. */ readonly color?: Color; } /** * Arbitrary information that has to be shown either before or after the caption as a prefix or a suffix. */ export interface CaptionAffix { /** * The text content of the prefix or the suffix. */ readonly data: string; /** * Font data for customizing the prefix of the suffix. */ readonly fontData?: FontData; } export interface BaseTailDecoration { /** * Optional tooltip for the tail decoration. */ readonly tooltip?: string; } /** * Unlike caption suffixes, tail decorations appears right-aligned after the caption and the caption suffixes (is any). */ export interface TailDecoration extends BaseTailDecoration { /** * The text content of the tail decoration. */ readonly data: string; /** * Font data for customizing the content. */ readonly fontData?: FontData; } export namespace TailDecoration { /** * Combines all fields of all `TailDecoration` variants */ export type AnyPartial = Partial<TailDecoration & TailDecorationIcon & TailDecorationIconClass>; /** * Represents any permissible concrete `TailDecoration` variation. */ export type AnyConcrete = TailDecoration | TailDecorationIcon | TailDecorationIconClass; export function isDotDecoration(decoration: AnyPartial): decoration is TailDecorationIcon { return decoration.icon === 'circle'; } } export interface TailDecorationIcon extends BaseTailDecoration { /** * This should be the name of the Font Awesome icon with out the `fa fa-` prefix, just the name, for instance `paw`. * For the existing icons, see here: https://fontawesome.com/v4.7.0/icons/. */ readonly icon: string; /** * The color of the icon. */ readonly color?: Color; } export interface TailDecorationIconClass extends BaseTailDecoration { /** * This should be the entire Font Awesome class array, for instance ['fa', 'fa-paw'] * For the existing icons, see here: https://fontawesome.com/v4.7.0/icons/. */ readonly iconClass: string[]; /** * The color of the icon. */ readonly color?: Color; } /** * Enumeration for the quadrant to overlay the image on. */ export enum IconOverlayPosition { /** * Overlays the top right quarter of the original image. */ TOP_RIGHT, /** * Overlays the bottom right of the original image. */ BOTTOM_RIGHT, /** * Overlays the bottom left segment of the original image. */ BOTTOM_LEFT, /** * Occupies the top left quarter of the original icon. */ TOP_LEFT } export namespace IconOverlayPosition { /** * Returns with the CSS class style for the enum. */ export function getStyle(position: IconOverlayPosition, inSideBar?: boolean): string { switch (position) { case IconOverlayPosition.TOP_RIGHT: return WidgetDecoration.Styles.TOP_RIGHT_CLASS; case IconOverlayPosition.BOTTOM_RIGHT: return inSideBar ? WidgetDecoration.Styles.BOTTOM_RIGHT_SIDEBAR_CLASS : WidgetDecoration.Styles.BOTTOM_RIGHT_CLASS; case IconOverlayPosition.BOTTOM_LEFT: return WidgetDecoration.Styles.BOTTOM_LEFT_CLASS; case IconOverlayPosition.TOP_LEFT: return WidgetDecoration.Styles.TOP_LEFT_CLASS; } } } /** * A shape that can be optionally rendered behind the overlay icon. Can be used to further refine colors. */ export interface IconOverlayBackground { /** * Either `circle` or `square`. */ readonly shape: 'circle' | 'square'; /** * The color of the background shape. */ readonly color?: Color; } /** * Has not effect if the widget being decorated has no associated icon. */ export interface BaseOverlay { /** * The position where the decoration will be placed on the top of the original icon. */ readonly position: IconOverlayPosition; /** * The color of the overlaying icon. If not specified, then the default icon color will be used. */ readonly color?: Color; /** * The optional background color of the overlay icon. */ readonly background?: IconOverlayBackground; } export interface IconOverlay extends BaseOverlay { /** * This should be the name of the Font Awesome icon with out the `fa fa-` prefix, just the name, for instance `paw`. * For the existing icons, see here: https://fontawesome.com/v4.7.0/icons/. */ readonly icon: string; } export interface IconClassOverlay extends BaseOverlay { /** * This should be the entire Font Awesome class array, for instance ['fa', 'fa-paw'] * For the existing icons, see here: https://fontawesome.com/v4.7.0/icons/. */ readonly iconClass: string[]; } /** * The caption highlighting with the highlighted ranges and an optional background color. */ export interface CaptionHighlight { /** * The ranges to highlight in the caption. */ readonly ranges: CaptionHighlight.Range[]; /** * The optional color of the text data that is being highlighted. Falls back to the default `mark` color values defined under a widget segment class. */ readonly color?: Color; /** * The optional background color of the text data that is being highlighted. */ readonly backgroundColor?: Color; } export namespace CaptionHighlight { /** * A pair of offset and length that has to be highlighted as a range. */ export interface Range { /** * Zero based offset of the highlighted region. */ readonly offset: number; /** * The length of the highlighted region. */ readonly length: number; } export namespace Range { /** * `true` if the `arg` is contained in the range. The ranges are closed ranges, hence the check is inclusive. */ export function contains(arg: number, range: Range): boolean { return arg >= range.offset && arg <= (range.offset + range.length); } } /** * The result of a caption splitting based on the highlighting information. */ export interface Fragment { /** * The text data of the fragment. */ readonly data: string; /** * Has to be highlighted if defined. */ readonly highlight?: true; } /** * Splits the `caption` argument based on the ranges from the `highlight` argument. */ export function split(caption: string, highlight: CaptionHighlight): Fragment[] { const result: Fragment[] = []; const ranges = highlight.ranges.slice(); const containerOf = (index: number) => ranges.findIndex(range => Range.contains(index, range)); let data = ''; for (let i = 0; i < caption.length; i++) { const containerIndex = containerOf(i); if (containerIndex === -1) { data += caption[i]; } else { if (data.length > 0) { result.push({ data }); } const { length } = ranges.splice(containerIndex, 1).shift()!; result.push({ data: caption.substring(i, i + length), highlight: true }); data = ''; i = i + length - 1; } } if (data.length > 0) { result.push({ data }); } if (ranges.length !== 0) { throw new Error('Error occurred when splitting the caption. There was a mismatch between the caption and the corresponding highlighting ranges.'); } return result; } } /** * Encapsulates styling information that has to be applied on the widget which we decorate. */ export interface Data { /** * The higher number has higher priority. If not specified, treated as `0`. * When multiple decorators are available for the same item, and decoration data cannot be merged together, * then the higher priority item will be applied on the decorated element and the lower priority will be ignored. */ readonly priority?: number; /** * The font data for the caption. */ readonly fontData?: FontData; /** * The background color of the entire row. */ readonly backgroundColor?: Color; /** * Optional, leading prefixes right before the caption. */ readonly captionPrefixes?: CaptionAffix[]; /** * Suffixes that might come after the caption as an additional information. */ readonly captionSuffixes?: CaptionAffix[]; /** * Optional right-aligned decorations that appear after the widget caption and after the caption suffixes (is any). */ readonly tailDecorations?: Array<TailDecoration | TailDecorationIcon | TailDecorationIconClass>; /** * Custom tooltip for the decorated item. Tooltip will be appended to the original tooltip, if any. */ readonly tooltip?: string; /** * Sets the color of the icon. Ignored if the decorated item has no icon. */ readonly iconColor?: Color; /** * Has not effect if given, but the widget does not have an associated image. */ readonly iconOverlay?: IconOverlay | IconClassOverlay; /** * An array of ranges to highlight the caption. */ readonly highlight?: CaptionHighlight; /** * A count badge for widgets. */ readonly badge?: number; } export namespace Data { /** * Compares the decoration data based on the priority. Lowest priorities come first (i.e. left.priority - right.priority). */ export const comparePriority = (left: Data, right: Data): number => (left.priority || 0) - (right.priority || 0); } }