From f315950b27d41c07b7449bf5e43848f38d55bdac Mon Sep 17 00:00:00 2001 From: "Nichols, Kieran" Date: Mon, 18 Dec 2023 08:50:15 -0500 Subject: [PATCH] chore: update popover to use latest token patterns --- .../pages/button-toggle/button-toggle.scss | 9 +- src/lib/core/utils/position-utils.ts | 17 ++-- src/lib/overlay/overlay-adapter.ts | 26 +++--- src/lib/popover/_animations.scss | 2 +- src/lib/popover/_configuration.scss | 51 ----------- src/lib/popover/_core.scss | 59 ++++++------ src/lib/popover/_token-utils.scss | 26 ++++++ src/lib/popover/_variables.scss | 0 src/lib/popover/index.scss | 1 + src/lib/popover/popover.scss | 89 +++++++++++-------- 10 files changed, 146 insertions(+), 134 deletions(-) delete mode 100644 src/lib/popover/_configuration.scss create mode 100644 src/lib/popover/_token-utils.scss delete mode 100644 src/lib/popover/_variables.scss create mode 100644 src/lib/popover/index.scss diff --git a/src/dev/pages/button-toggle/button-toggle.scss b/src/dev/pages/button-toggle/button-toggle.scss index d5c7aaa3b..c16c3ab12 100644 --- a/src/dev/pages/button-toggle/button-toggle.scss +++ b/src/dev/pages/button-toggle/button-toggle.scss @@ -2,6 +2,10 @@ @use '../../../lib/button-toggle/button-toggle'; @use '../../../lib/core/styles/theme'; +section:not(:last-of-type) { + margin-block-end: 32px; +} + #toolbar-card { display: inline-block; --forge-card-padding: 0; @@ -23,11 +27,14 @@ .legacy-button-toggle-group { @include button-toggle-group.provide-theme(( gap: 1px, - padding: 0 + padding: 0, + outline-color: theme.variable(primary), + outline-color-active: theme.variable(primary) )); forge-button-toggle { @include button-toggle.provide-theme(( + color: theme.variable(primary), selected-color: theme.variable(on-primary), selected-background: theme.variable(primary), focus-indicator-offset: 2px diff --git a/src/lib/core/utils/position-utils.ts b/src/lib/core/utils/position-utils.ts index 5accee6f7..073e3558b 100644 --- a/src/lib/core/utils/position-utils.ts +++ b/src/lib/core/utils/position-utils.ts @@ -26,7 +26,7 @@ export type PositionStrategy = Strategy; export interface IPositionElementResult { x: number; y: number; - visibility: 'visible' | 'hidden'; + hidden: boolean; placement: PositionPlacement; arrow?: MiddlewareData['arrow']; } @@ -133,14 +133,12 @@ export async function positionElementAsync({ } const { x, y, placement: finalPlacement, middlewareData } = await computePosition(targetElement, element, { strategy, placement, middleware }); - const visibility = middlewareData.hide?.referenceHidden ? 'hidden' : 'visible'; // Should we apply the position information to the element? if (apply) { const styles: Partial = { left: transform ? '0' : `${x}px`, - top: transform ? '0' : `${y}px`, - visibility + top: transform ? '0' : `${y}px` }; if (transform) { @@ -152,12 +150,19 @@ export async function positionElementAsync({ } Object.assign(element.style, styles); + + // We use `display` here to ensure that any child overlays are also hidden + if (middlewareData.hide?.referenceHidden) { + element.style.display = 'none'; + } else { + element.style.removeProperty('display'); + } } return { x, y, - visibility, + hidden: middlewareData.hide?.referenceHidden ?? false, placement: finalPlacement, arrow: middlewareData.arrow }; @@ -175,7 +180,7 @@ export const topLayerMiddleware = (): Middleware => ({ const diffCoords = { x: 0, y: 0 }; try { - onTopLayer = onTopLayer || floating.matches(':popover-open'); + onTopLayer = onTopLayer || floating.matches(':popover-open'); } catch {} try { onTopLayer = onTopLayer || floating.matches(':open'); diff --git a/src/lib/overlay/overlay-adapter.ts b/src/lib/overlay/overlay-adapter.ts index 31762c882..604e45388 100644 --- a/src/lib/overlay/overlay-adapter.ts +++ b/src/lib/overlay/overlay-adapter.ts @@ -4,7 +4,14 @@ import { BaseAdapter, IBaseAdapter } from '../core/base/base-adapter'; import { locateTargetHeuristic, replaceElement } from '../core/utils/utils'; import { positionElementAsync } from '../core/utils/position-utils'; import { IOverlayComponent } from './overlay'; -import { CAN_USE_POPOVER, IOverlayOffset, OverlayPlacement, OverlayPositionStrategy, OverlayToggleEvent, OVERLAY_CONSTANTS } from './overlay-constants'; +import { + CAN_USE_POPOVER, + IOverlayOffset, + OverlayPlacement, + OverlayPositionStrategy, + OverlayToggleEvent, + OVERLAY_CONSTANTS +} from './overlay-constants'; export interface IOverlayAdapter extends IBaseAdapter { setOpen(value: boolean): void; @@ -67,7 +74,7 @@ export class OverlayAdapter extends BaseAdapter implements IO this._rootElement.style.removeProperty('top'); this._rootElement.style.removeProperty('left'); - this._rootElement.style.removeProperty('visibility'); + this._rootElement.style.removeProperty('display'); this._component.removeAttribute(OVERLAY_CONSTANTS.attributes.POSITION_PLACEMENT); } } @@ -117,14 +124,16 @@ export class OverlayAdapter extends BaseAdapter implements IO this._component.setAttribute(OVERLAY_CONSTANTS.attributes.POSITION_PLACEMENT, result.placement); } - // Position our optional arrow element + // Position the optional arrow element if (this._component.arrowElement && result.arrow) { const { x: arrowX, y: arrowY } = result.arrow; const arrowLen = this._component.arrowElement.offsetWidth; + const { borderWidth = '0' } = getComputedStyle(this._component.arrowElement); + const arrowBoxAdjust = parseFloat(borderWidth); Object.assign(this._component.arrowElement.style, { top: arrowY != null ? `${arrowY}px` : '', left: arrowX != null ? `${arrowX}px` : '', - [staticSide as string]: `${-arrowLen / 2}px` + [staticSide as string]: `${(-arrowLen / 2) - arrowBoxAdjust}px` }); } }); @@ -144,10 +153,7 @@ export class OverlayAdapter extends BaseAdapter implements IO } public addDialogLightDismissListener(listener: EventListener | (() => void)): void { - if (this._dialogLightDismissCleanup) { - this.removeDialogLightDismissListener(); - } - + this.removeDialogLightDismissListener?.(); this._rootElement.addEventListener('cancel', listener); const backdropClickListener = ({ clientX, clientY }: PointerEvent): void => { @@ -169,9 +175,7 @@ export class OverlayAdapter extends BaseAdapter implements IO } public addCustomLightDismissListener(listener: () => void): void { - if (this._lightDismissCleanup) { - this.removeCustomLightDismissListener(); - } + this.removeCustomLightDismissListener?.(); this._initializeLightDismiss(listener); } diff --git a/src/lib/popover/_animations.scss b/src/lib/popover/_animations.scss index 99d6e45ea..b7324fa17 100644 --- a/src/lib/popover/_animations.scss +++ b/src/lib/popover/_animations.scss @@ -13,7 +13,7 @@ @keyframes slidein { from { opacity: 0; - transform: translateX(var(--_slidein-x)) translateY(var(--_slidein-y)); + transform: translateX(var(--_popover-slidein-x)) translateY(var(--_popover-slidein-y)); } to { diff --git a/src/lib/popover/_configuration.scss b/src/lib/popover/_configuration.scss deleted file mode 100644 index f493be879..000000000 --- a/src/lib/popover/_configuration.scss +++ /dev/null @@ -1,51 +0,0 @@ -@use '../core/styles/tokens/popover/tokens'; - -@mixin base { - --_popover-background-color: #{tokens.get(background-color)}; - --_popover-border-radius: #{tokens.get(border-radius)}; - --_popover-box-shadow: #{tokens.get(box-shadow)}; - --_popover-border-width: #{tokens.get(border-width)}; - --_popover-border-style: #{tokens.get(border-style)}; - --_popover-border-color: #{tokens.get(border-color)}; -} - -@mixin arrow { - --_popover-arrow-size: #{tokens.get(arrow-size)}; - --_popover-arrow-height: #{tokens.get(arrow-height)}; - --_popover-arrow-width: #{tokens.get(arrow-width)}; - --_popover-arrow-background-color: #{tokens.get(arrow-background-color)}; - // --_popover-arrow-clip-path: #{tokens.get(arrow-clip-path)}; - --_popover-arrow-top-rotation: #{tokens.get(arrow-top-rotation)}; - --_popover-arrow-right-rotation: #{tokens.get(arrow-right-rotation)}; - --_popover-arrow-bottom-rotation: #{tokens.get(arrow-bottom-rotation)}; - --_popover-arrow-left-rotation: #{tokens.get(arrow-left-rotation)}; - - --_popover-arrow-translate-x: 0; - --_popover-arrow-translate-y: 0; - --_popover-arrow-rotation: 0; -} - -@mixin animation-base { - --_popover-animation-timing: #{tokens.get(animation-timing)}; -} - -@mixin zoom { - --_popover-zoom-duration: #{tokens.get(zoom-duration)}; - --_popover-zoom-timing: #{tokens.get(zoom-timing)}; - - --_popover-zoomin-origin: 50% 50% 0; -} - -@mixin slide { - --_popover-slide-duration: #{tokens.get(slide-duration)}; - --_popover-slide-timing: #{tokens.get(slide-timing)}; - --_popover-slide-offset: #{tokens.get(slide-offset)}; - - --_popover-slidein-x: 0; - --_popover-slidein-y: 0; -} - -@mixin fade { - --_popover-fade-duration: #{tokens.get(fade-duration)}; - --_popover-fade-timing: #{tokens.get(fade-timing)}; -} diff --git a/src/lib/popover/_core.scss b/src/lib/popover/_core.scss index c36b2acc3..3539507e1 100644 --- a/src/lib/popover/_core.scss +++ b/src/lib/popover/_core.scss @@ -1,54 +1,59 @@ -@use './variables'; -@use '../core/styles/utils'; -@use '../core/styles/tokens/popover/tokens'; +@use './token-utils' as *; -@mixin provide-theme($theme) { - @include utils.provide(tokens.$tokens, $theme, popover); -} +@forward './token-utils'; @mixin base { - background-color: var(--_popover-background-color); - border-radius: var(--_popover-border-radius); - box-shadow: var(--_popover-box-shadow); - border: var(--_popover-border-width) var(--_popover-border-style) var(--_popover-border-color); position: relative; + + background-color: #{token(background-color)}; + + border-radius: #{token(border-radius)}; + box-shadow: #{token(box-shadow)}; + border-width: #{token(border-width)}; + border-style: #{token(border-style)}; + border-color: #{token(border-color)}; } @mixin arrow { position: absolute; - height: var(--_popover-arrow-height); - width: var(--_popover-arrow-width); - background-color: var(--_popover-arrow-background-color); - box-shadow: var(--_popover-box-shadow); - border: var(--_popover-border-width) var(--_popover-border-style) var(--_popover-border-color); + + background-color: #{token(arrow-background-color)}; + + height: #{token(arrow-height)}; + width: #{token(arrow-width)}; + box-shadow: #{token(box-shadow)}; + border-width: #{token(border-width)}; + border-style: #{token(border-style)}; + border-color: #{token(border-color)}; + transform: - translate(var(--_popover-arrow-translate-x), var(--_popover-arrow-translate-y)) - rotate(var(--_popover-arrow-rotation)); + translate(#{token(arrow-translate-x, custom)}, #{token(arrow-translate-y, custom)}) + rotate(#{token(arrow-rotation, custom)}); clip-path: var( --_popover-arrow-clip-path, polygon( - calc(var(--_popover-border-width) * -1) calc(var(--_popover-border-width) * -1), - calc(100% + var(--_popover-border-width)) calc(var(--_popover-border-width) * -1), - calc(100% + var(--_popover-border-width)) calc(100% + var(--_popover-border-width)) + calc(#{token(border-width)} * -1) calc(#{token(border-width)} * -1), + calc(100% + #{token(border-width)}) calc(#{token(border-width)} * -1), + calc(100% + #{token(border-width)}) calc(100% + #{token(border-width)}) ) ); } @mixin zoom-base { - animation-duration: var(--_popover-zoom-duration); - animation-timing-function: var(--_popover-zoom-timing); + animation-duration: #{token(zoom-duration)}; + animation-timing-function: #{token(zoom-timing)}; animation-name: zoomin; - transform-origin: var(--_popover-zoomin-origin); + transform-origin: #{token(zoomin-origin, custom)}; } @mixin slide-base { - animation-duration: var(--_popover-slide-duration); - animation-timing-function: var(--_popover-slide-timing); + animation-duration: #{token(slide-duration)}; + animation-timing-function: #{token(slide-timing)}; animation-name: slidein; } @mixin fade-base { - animation-duration: var(--_popover-fade-duration); - animation-timing-function: var(--_popover-fade-timing); + animation-duration: #{token(fade-duration)}; + animation-timing-function: #{token(fade-timing)}; animation-name: fadein; } diff --git a/src/lib/popover/_token-utils.scss b/src/lib/popover/_token-utils.scss new file mode 100644 index 000000000..ccbe47bce --- /dev/null +++ b/src/lib/popover/_token-utils.scss @@ -0,0 +1,26 @@ +@use '../core/styles/utils'; +@use '../core/styles/tokens/popover/tokens'; +@use '../core/styles/tokens/token-utils'; + +$_module: popover; +$_tokens: tokens.$tokens; + +@mixin provide-theme($theme) { + @include token-utils.provide-theme($_module, $_tokens, $theme); +} + +@function token($name, $type: token) { + @return token-utils.token($_module, $_tokens, $name, $type); +} + +@function declare($token) { + @return token-utils.declare($_module, $token); +} + +@mixin override($token, $token-or-value, $type: token) { + @include token-utils.override($_module, $_tokens, $token, $token-or-value, $type); +} + +@mixin tokens($includes: null, $excludes: null) { + @include token-utils.tokens($_module, $_tokens, $includes, $excludes); +} diff --git a/src/lib/popover/_variables.scss b/src/lib/popover/_variables.scss deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/lib/popover/index.scss b/src/lib/popover/index.scss new file mode 100644 index 000000000..98a38c0d9 --- /dev/null +++ b/src/lib/popover/index.scss @@ -0,0 +1 @@ +@forward './core'; diff --git a/src/lib/popover/popover.scss b/src/lib/popover/popover.scss index b80bcd1e2..8eb3054e8 100644 --- a/src/lib/popover/popover.scss +++ b/src/lib/popover/popover.scss @@ -1,8 +1,11 @@ -@use './core'; -@use './configuration'; +@use './core' as *; @use './animations'; @use '../overlay'; +// +// Host +// + :host { display: contents; } @@ -11,42 +14,54 @@ display: none; } -/// -/// Base styles -/// +// +// Base +// .forge-popover { - @include configuration.base; - @include core.base; -} + @include tokens; -/// -/// Dialog styles -/// + #{declare(arrow-translate-x)}: 0; + #{declare(arrow-translate-y)}: 0; + #{declare(arrow-rotation)}: 0; -:host([dialog]) { - forge-overlay { - @include overlay.provide-theme(( - backdrop-fade-duration: 1000ms - )); - } + --_popover-slidein-x: 0; + --_popover-slidein-y: 0; + + --_popover-zoomin-origin: 50% 50% 0; } -:host([open][dialog][modal]) { - forge-overlay::part(container)::backdrop { - backdrop-filter: blur(1px); - background-color: rgba(0, 0, 0, 0.24); - } +.forge-popover { + @include base; } -/// -/// Arrow styles -/// +// +// Dialog +// + +// :host([dialog]) { +// forge-overlay { +// @include overlay.provide-theme(( +// backdrop-fade-duration: 1000ms +// )); +// } +// } + +// :host([open][dialog][modal]) { +// forge-overlay::part(container)::backdrop { +// backdrop-filter: blur(1px); +// background-color: rgba(0, 0, 0, 0.24); +// } +// } + +// +// Arrow +// :host([arrow]) { .arrow { - @include configuration.arrow; - @include core.arrow; + // @include configuration.arrow; + @include arrow; } forge-overlay[position-placement^=top] { @@ -78,21 +93,21 @@ } } -/// -/// Animation styles -/// +// +// Animation +// :host(:not([animation-type=none])) { .forge-popover { - @include configuration.animation-base; + // @include configuration.animation-base; } } :host(:not([animation-type])), :host([animation-type=zoom]) { .forge-popover { - @include configuration.zoom; - @include core.zoom-base; + // @include configuration.zoom; + @include zoom-base; } forge-overlay[open] { @@ -180,8 +195,8 @@ :host([animation-type=slide]) { .forge-popover { - @include configuration.slide; - @include core.slide-base; + // @include configuration.slide; + @include slide-base; } forge-overlay[open] { @@ -213,7 +228,7 @@ :host([animation-type=fade]) { .forge-popover { - @include configuration.fade; - @include core.fade-base; + // @include configuration.fade; + @include fade-base; } }