UNPKG

@jupyter/web-components

Version:

A component library for building extensions in Jupyter frontends.

344 lines (314 loc) 11.3 kB
// Copyright (c) Jupyter Development Team. // Copyright (c) Microsoft Corporation. // Distributed under the terms of the Modified BSD License. import { css, cssPartial } from '@microsoft/fast-element'; import { DesignToken, disabledCursor, display, focusVisible, forcedColorsStylesheetBehavior, TreeItem } from '@microsoft/fast-foundation'; import { SystemColors } from '@microsoft/fast-web-utilities'; import { accentFillFocus, accentForegroundRest, baseHeightMultiplier, bodyFont, controlCornerRadius, density, designUnit, disabledOpacity, focusStrokeWidth, neutralFillActive, neutralFillHover, neutralFillRecipe, neutralFillRest, neutralFillStealthActive, neutralFillStealthHover, neutralFillStealthRecipe, neutralFillStealthRest, neutralForegroundRest, strokeWidth, typeRampBaseFontSize, typeRampBaseLineHeight, typeRampPlus1FontSize } from '../design-tokens.js'; import { DirectionalStyleSheetBehavior, heightNumber } from '../styles/index.js'; /** * Tree item expand collapse button size CSS Partial * @public */ export const expandCollapseButtonSize = cssPartial `(((${baseHeightMultiplier} + ${density}) * 0.5 + 2) * ${designUnit})`; const ltr = css ` .expand-collapse-glyph { transform: rotate(0deg); } :host(.nested) .expand-collapse-button { left: var( --expand-collapse-button-nested-width, calc( ( ${expandCollapseButtonSize} + ((${baseHeightMultiplier} + ${density}) * 1.25) ) * -1px ) ); } :host([selected])::after { left: calc(${focusStrokeWidth} * 1px); } :host([expanded]) > .positioning-region .expand-collapse-glyph { transform: rotate(90deg); } `; const rtl = css ` .expand-collapse-glyph { transform: rotate(180deg); } :host(.nested) .expand-collapse-button { right: var( --expand-collapse-button-nested-width, calc( ( ${expandCollapseButtonSize} + ((${baseHeightMultiplier} + ${density}) * 1.25) ) * -1px ) ); } :host([selected])::after { right: calc(${focusStrokeWidth} * 1px); } :host([expanded]) > .positioning-region .expand-collapse-glyph { transform: rotate(90deg); } `; const expandCollapseHoverBehavior = DesignToken.create('tree-item-expand-collapse-hover').withDefault((target) => { const recipe = neutralFillStealthRecipe.getValueFor(target); return recipe.evaluate(target, recipe.evaluate(target).hover).hover; }); const selectedExpandCollapseHoverBehavior = DesignToken.create('tree-item-expand-collapse-selected-hover').withDefault((target) => { const baseRecipe = neutralFillRecipe.getValueFor(target); const buttonRecipe = neutralFillStealthRecipe.getValueFor(target); return buttonRecipe.evaluate(target, baseRecipe.evaluate(target).rest).hover; }); /** * Styles for Tree Item * @public */ export const treeItemStyles = (context, definition) => css ` /** * This animation exists because when tree item children are conditionally loaded * there is a visual bug where the DOM exists but styles have not yet been applied (essentially FOUC). * This subtle animation provides a ever so slight timing adjustment for loading that solves the issue. */ @keyframes treeItemLoading { 0% { opacity: 0; } 100% { opacity: 1; } } ${display('block')} :host { contain: content; position: relative; outline: none; color: ${neutralForegroundRest}; background: ${neutralFillStealthRest}; cursor: pointer; font-family: ${bodyFont}; --tree-item-nested-width: 0; } :host(:focus) > .positioning-region { outline: none; } :host(:focus) .content-region { outline: none; } :host(:${focusVisible}) .positioning-region { border-color: ${accentFillFocus}; box-shadow: 0 0 0 calc((${focusStrokeWidth} - ${strokeWidth}) * 1px) ${accentFillFocus} inset; color: ${neutralForegroundRest}; } .positioning-region { display: flex; position: relative; box-sizing: border-box; background: ${neutralFillStealthRest}; border: transparent calc(${strokeWidth} * 1px) solid; border-radius: calc(${controlCornerRadius} * 1px); height: calc((${heightNumber} + 1) * 1px); } .positioning-region::before { content: ''; display: block; width: var(--tree-item-nested-width); flex-shrink: 0; } :host(:not([disabled])) .positioning-region:hover { background: ${neutralFillStealthHover}; } :host(:not([disabled])) .positioning-region:active { background: ${neutralFillStealthActive}; } .content-region { display: inline-flex; align-items: center; white-space: nowrap; width: 100%; min-width: 0; height: calc(${heightNumber} * 1px); margin-inline-start: calc(${designUnit} * 2px + 8px); font-size: ${typeRampBaseFontSize}; line-height: ${typeRampBaseLineHeight}; font-weight: 400; } .items { /* TODO: adaptive typography https://github.com/microsoft/fast/issues/2432 */ font-size: calc(1em + (${designUnit} + 16) * 1px); } .expand-collapse-button { background: none; border: none; outline: none; /* TODO: adaptive typography https://github.com/microsoft/fast/issues/2432 */ width: calc(${expandCollapseButtonSize} * 1px); height: calc(${expandCollapseButtonSize} * 1px); padding: 0; display: flex; justify-content: center; align-items: center; cursor: pointer; margin-left: 6px; margin-right: 6px; } .expand-collapse-glyph { /* TODO: adaptive typography https://github.com/microsoft/fast/issues/2432 */ width: calc((16 + ${density}) * 1px); height: calc((16 + ${density}) * 1px); transition: transform 0.1s linear; pointer-events: none; fill: currentcolor; } .start, .end { display: flex; fill: currentcolor; } ::slotted(svg), ::slotted(jp-icon) { /* TODO: adaptive typography https://github.com/microsoft/fast/issues/2432 */ width: 16px; height: 16px; /* Something like that would do if the typography is adaptive font-size: inherit; width: ${typeRampPlus1FontSize}; height: ${typeRampPlus1FontSize}; */ } .start { /* TODO: horizontalSpacing https://github.com/microsoft/fast/issues/2766 */ margin-inline-end: calc(${designUnit} * 2px + 2px); } .end { /* TODO: horizontalSpacing https://github.com/microsoft/fast/issues/2766 */ margin-inline-start: calc(${designUnit} * 2px + 2px); } :host([expanded]) > .items { animation: treeItemLoading ease-in 10ms; animation-iteration-count: 1; animation-fill-mode: forwards; } :host([disabled]) .content-region { opacity: ${disabledOpacity}; cursor: ${disabledCursor}; } :host(.nested) .content-region { position: relative; /* Add left margin to collapse button size */ margin-inline-start: calc( ( ${expandCollapseButtonSize} + ((${baseHeightMultiplier} + ${density}) * 1.25) ) * 1px ); } :host(.nested) .expand-collapse-button { position: absolute; } :host(.nested:not([disabled])) .expand-collapse-button:hover { background: ${expandCollapseHoverBehavior}; } :host([selected]) .positioning-region { background: ${neutralFillRest}; } :host([selected]:not([disabled])) .positioning-region:hover { background: ${neutralFillHover}; } :host([selected]:not([disabled])) .positioning-region:active { background: ${neutralFillActive}; } :host([selected]:not([disabled])) .expand-collapse-button:hover { background: ${selectedExpandCollapseHoverBehavior}; } :host([selected])::after { /* The background needs to be calculated based on the selected background state for this control. We currently have no way of changing that, so setting to accent-foreground-rest for the time being */ background: ${accentForegroundRest}; border-radius: calc(${controlCornerRadius} * 1px); content: ''; display: block; position: absolute; top: calc((${heightNumber} / 4) * 1px); width: 3px; height: calc((${heightNumber} / 2) * 1px); } ::slotted(${context.tagFor(TreeItem)}) { --tree-item-nested-width: 1em; --expand-collapse-button-nested-width: calc( ( ${expandCollapseButtonSize} + ((${baseHeightMultiplier} + ${density}) * 1.25) ) * -1px ); } `.withBehaviors(new DirectionalStyleSheetBehavior(ltr, rtl), forcedColorsStylesheetBehavior(css ` :host { forced-color-adjust: none; border-color: transparent; background: ${SystemColors.Field}; color: ${SystemColors.FieldText}; } :host .content-region .expand-collapse-glyph { fill: ${SystemColors.FieldText}; } :host .positioning-region:hover, :host([selected]) .positioning-region { background: ${SystemColors.Highlight}; } :host .positioning-region:hover .content-region, :host([selected]) .positioning-region .content-region { color: ${SystemColors.HighlightText}; } :host .positioning-region:hover .content-region .expand-collapse-glyph, :host .positioning-region:hover .content-region .start, :host .positioning-region:hover .content-region .end, :host([selected]) .content-region .expand-collapse-glyph, :host([selected]) .content-region .start, :host([selected]) .content-region .end { fill: ${SystemColors.HighlightText}; } :host([selected])::after { background: ${SystemColors.Field}; } :host(:${focusVisible}) .positioning-region { border-color: ${SystemColors.FieldText}; box-shadow: 0 0 0 2px inset ${SystemColors.Field}; color: ${SystemColors.FieldText}; } :host([disabled]) .content-region, :host([disabled]) .positioning-region:hover .content-region { opacity: 1; color: ${SystemColors.GrayText}; } :host([disabled]) .content-region .expand-collapse-glyph, :host([disabled]) .content-region .start, :host([disabled]) .content-region .end, :host([disabled]) .positioning-region:hover .content-region .expand-collapse-glyph, :host([disabled]) .positioning-region:hover .content-region .start, :host([disabled]) .positioning-region:hover .content-region .end { fill: ${SystemColors.GrayText}; } :host([disabled]) .positioning-region:hover { background: ${SystemColors.Field}; } .expand-collapse-glyph, .start, .end { fill: ${SystemColors.FieldText}; } :host(.nested) .expand-collapse-button:hover { background: ${SystemColors.Field}; } :host(.nested) .expand-collapse-button:hover .expand-collapse-glyph { fill: ${SystemColors.FieldText}; } `));