Skip to content

Commit

Permalink
fix: handle longpress and over filter overlays
Browse files Browse the repository at this point in the history
  • Loading branch information
Westbrook committed Aug 18, 2023
1 parent b650ba1 commit 483e52d
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 47 deletions.
36 changes: 29 additions & 7 deletions packages/action-button/src/ActionButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ export class ActionButton extends SizedMixin(ButtonBase, {
constructor() {
super();
this.addEventListener('click', this.onClick);
this.addEventListener('pointerdown', this.onPointerdown);
}

private onClick = (): void => {
Expand All @@ -134,10 +133,13 @@ export class ActionButton extends SizedMixin(ButtonBase, {
}
};

private onPointerdown(event: PointerEvent): void {
private handlePointerdownHoldAffordance(event: PointerEvent): void {
if (event.button !== 0) return;
this.addEventListener('pointerup', this.onPointerup);
this.addEventListener('pointercancel', this.onPointerup);
this.addEventListener('pointerup', this.handlePointerupHoldAffordance);
this.addEventListener(
'pointercancel',
this.handlePointerupHoldAffordance
);
LONGPRESS_TIMEOUT = setTimeout(() => {
this.dispatchEvent(
new CustomEvent<LongpressEvent>('longpress', {
Expand All @@ -151,10 +153,16 @@ export class ActionButton extends SizedMixin(ButtonBase, {
}, LONGPRESS_DURATION);
}

private onPointerup(): void {
private handlePointerupHoldAffordance(): void {
clearTimeout(LONGPRESS_TIMEOUT);
this.removeEventListener('pointerup', this.onPointerup);
this.removeEventListener('pointercancel', this.onPointerup);
this.removeEventListener(
'pointerup',
this.handlePointerupHoldAffordance
);
this.removeEventListener(
'pointercancel',
this.handlePointerupHoldAffordance
);
}

/**
Expand Down Expand Up @@ -258,6 +266,20 @@ export class ActionButton extends SizedMixin(ButtonBase, {
);
}
}
if (changes.has('holdAffordance')) {
if (this.holdAffordance) {
this.addEventListener(
'pointerdown',
this.handlePointerdownHoldAffordance
);
} else {
this.removeEventListener(
'pointerdown',
this.handlePointerdownHoldAffordance
);
this.handlePointerupHoldAffordance();
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/button/src/ButtonBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import buttonStyles from './button-base.css.js';
* @slot icon - icon element(s) to display at the start of the button
*/
export class ButtonBase extends ObserveSlotText(LikeAnchor(Focusable), '', [
'sp-tooltip',
'sp-overlay,sp-tooltip',
]) {
public static override get styles(): CSSResultArray {
return [buttonStyles];
Expand Down
1 change: 1 addition & 0 deletions packages/button/src/button-base.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ governing permissions and limitations under the License.
inset: 0;
}

::slotted(sp-overlay),
::slotted(sp-tooltip) {
position: absolute;
}
Expand Down
1 change: 1 addition & 0 deletions packages/overlay/src/Overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -806,6 +806,7 @@ export class Overlay extends OverlayFeatures {
return;
}
this.open = true;
this.placementController.allowPlacementUpdate = true;
this.manageOpen(false);
}

Expand Down
9 changes: 8 additions & 1 deletion packages/overlay/src/PlacementController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,19 @@ export class PlacementController implements ReactiveController {
};
}

allowPlacementUpdate = false;

updatePlacement = (): void => {
if (this.options.type !== 'modal' && this.cleanup) {
if (
!this.allowPlacementUpdate &&
this.options.type !== 'modal' &&
this.cleanup
) {
this.target.dispatchEvent(new Event('close', { bubbles: true }));
return;
}
this.computePlacement();
this.allowPlacementUpdate = false;
};

async computePlacement(): Promise<void> {
Expand Down
84 changes: 46 additions & 38 deletions packages/overlay/src/topLayerOverTransforms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License.
*/
import type { Middleware, MiddlewareState } from '@floating-ui/dom';
import { getContainingBlock, getWindow } from '@floating-ui/utils/dom';
import {
getContainingBlock,
getWindow,
isContainingBlock,
} from '@floating-ui/utils/dom';
import { VirtualTrigger } from './VirtualTrigger.js';

export const topLayerOverTransforms = (): Middleware => ({
name: 'topLayer',
Expand All @@ -22,6 +27,7 @@ export const topLayerOverTransforms = (): Middleware => ({
} = middlewareArguments;
let onTopLayer = false;
let topLayerIsFloating = false;
let withinReference = false;
const diffCoords = {
x: 0,
y: 0,
Expand All @@ -40,45 +46,47 @@ export const topLayerOverTransforms = (): Middleware => ({
/* c8 ignore next 3 */
} catch (error) {}
topLayerIsFloating = onTopLayer;
if (!onTopLayer) {
const dialogAncestorQueryEvent = new Event(
'floating-ui-dialog-test',
{ composed: true, bubbles: true }
);
floating.addEventListener(
'floating-ui-dialog-test',
(event: Event) => {
(event.composedPath() as unknown as Element[]).forEach(
(el) => {
if (el === floating || el.localName !== 'dialog')
return;
try {
onTopLayer = onTopLayer || el.matches(':modal');
// eslint-disable-next-line no-empty
/* c8 ignore next */
} catch (error) {}
}
);
},
{ once: true }
);
floating.dispatchEvent(dialogAncestorQueryEvent);
}
const dialogAncestorQueryEvent = new Event('floating-ui-dialog-test', {
composed: true,
bubbles: true,
});
floating.addEventListener(
'floating-ui-dialog-test',
(event: Event) => {
(event.composedPath() as unknown as Element[]).forEach((el) => {
withinReference = withinReference || el === reference;
if (el === floating || el.localName !== 'dialog') return;
try {
onTopLayer = onTopLayer || el.matches(':modal');
// eslint-disable-next-line no-empty
/* c8 ignore next */
} catch (error) {}
});
},
{ once: true }
);
floating.dispatchEvent(dialogAncestorQueryEvent);
let overTransforms = false;
const containingBlock = getContainingBlock(reference as Element);
if (
containingBlock !== null &&
getWindow(containingBlock) !==
(containingBlock as unknown as Window)
) {
const css = getComputedStyle(containingBlock);
overTransforms = css.transform !== 'none';
}
if (!(reference instanceof VirtualTrigger)) {
const containingBlock = isContainingBlock(reference as Element)
? (reference as Element)
: getContainingBlock(reference as Element);
if (
containingBlock !== null &&
getWindow(containingBlock) !==
(containingBlock as unknown as Window)
) {
const css = getComputedStyle(containingBlock);
overTransforms =
withinReference &&
(css.transform !== 'none' || css.filter !== 'none');
}

if (onTopLayer && overTransforms && containingBlock) {
const rect = containingBlock.getBoundingClientRect();
diffCoords.x = rect.x;
diffCoords.y = rect.y;
if (onTopLayer && overTransforms && containingBlock) {
const rect = containingBlock.getBoundingClientRect();
diffCoords.x = rect.x;
diffCoords.y = rect.y;
}
}

if (onTopLayer && topLayerIsFloating) {
Expand Down
123 changes: 123 additions & 0 deletions packages/overlay/stories/overlay-element.stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,126 @@ export const actionGroup = ({ delayed }: Properties): TemplateResult => {
</sp-overlay>
`;
};

export const actionGroupWithFilters = ({
delayed,
}: Properties): TemplateResult => {
const popoverOffset = [6, -13] as [number, number];
return html`
<style>
sp-popover sp-action-group {
padding: var(--spectrum-actiongroup-vertical-spacing-regular);
}
.root {
inset-inline-end: 3em;
inset-block-start: 3em;
}
sp-action-button {
background-image: linear-gradient(
rgba(125, 125, 125, 0.2),
rgba(125, 125, 125, 0.2)
);
background-blend-mode: multiply;
filter: brightness(1) saturate(1);
}
</style>
<sp-popover open class="root">
<sp-action-group vertical quiet emphasized selects="single">
<sp-action-button id="trigger-1" hold-affordance>
<sp-icon-anchor-select slot="icon"></sp-icon-anchor-select>
<sp-tooltip ?delayed=${delayed} self-managed>
Hover
</sp-tooltip>
<sp-overlay
trigger="trigger-1@longpress"
type="auto"
placement="right-start"
.offset=${popoverOffset}
>
<sp-popover tip>
<sp-action-group vertical quiet>
<sp-action-button>
<sp-icon-anchor-select
slot="icon"
></sp-icon-anchor-select>
</sp-action-button>
<sp-action-button>
<sp-icon-polygon-select
slot="icon"
></sp-icon-polygon-select>
</sp-action-button>
<sp-action-button>
<sp-icon-rect-select
slot="icon"
></sp-icon-rect-select>
</sp-action-button>
</sp-action-group>
</sp-popover>
</sp-overlay>
</sp-action-button>
<sp-action-button id="trigger-2" hold-affordance>
<sp-icon-polygon-select
slot="icon"
></sp-icon-polygon-select>
</sp-action-button>
<sp-action-button id="trigger-3" hold-affordance>
<sp-icon-rect-select slot="icon"></sp-icon-rect-select>
<sp-tooltip ?delayed=${delayed} self-managed>
Hover
</sp-tooltip>
</sp-action-button>
</sp-action-group>
</sp-popover>
<sp-overlay ?delayed=${delayed} trigger="trigger-2@hover">
<sp-tooltip>Hover</sp-tooltip>
</sp-overlay>
<sp-overlay
trigger="trigger-2@longpress"
type="auto"
placement="right-start"
.offset=${popoverOffset}
>
<sp-popover tip>
<sp-action-group vertical quiet>
<sp-action-button>
<sp-icon-anchor-select
slot="icon"
></sp-icon-anchor-select>
</sp-action-button>
<sp-action-button>
<sp-icon-polygon-select
slot="icon"
></sp-icon-polygon-select>
</sp-action-button>
<sp-action-button>
<sp-icon-rect-select slot="icon"></sp-icon-rect-select>
</sp-action-button>
</sp-action-group>
</sp-popover>
</sp-overlay>
<sp-overlay
trigger="trigger-3@longpress"
type="auto"
placement="right-start"
.offset=${popoverOffset}
>
<sp-popover tip>
<sp-action-group vertical quiet>
<sp-action-button>
<sp-icon-anchor-select
slot="icon"
></sp-icon-anchor-select>
</sp-action-button>
<sp-action-button>
<sp-icon-polygon-select
slot="icon"
></sp-icon-polygon-select>
</sp-action-button>
<sp-action-button>
<sp-icon-rect-select slot="icon"></sp-icon-rect-select>
</sp-action-button>
</sp-action-group>
</sp-popover>
</sp-overlay>
`;
};

0 comments on commit 483e52d

Please sign in to comment.