From cbcd299bd93f1d903dc407b6f1e1ac4d5cfee4f4 Mon Sep 17 00:00:00 2001 From: Hampus Date: Mon, 24 Aug 2026 12:46:51 +0200 Subject: [PATCH] fix(app): keep a child's own data-flx when wrapped in a focus ring (#1926) --- .../src/features/ui/focus_ring/FocusRing.ts | 13 ++++++---- .../ui/focus_ring/FocusRingContext.ts | 26 +++++++++---------- 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/fluxer_app/src/features/ui/focus_ring/FocusRing.ts b/fluxer_app/src/features/ui/focus_ring/FocusRing.ts index 1bb6ecc63..fdaaee160 100644 --- a/fluxer_app/src/features/ui/focus_ring/FocusRing.ts +++ b/fluxer_app/src/features/ui/focus_ring/FocusRing.ts @@ -79,7 +79,7 @@ const FocusRing = React.forwardRef(function F if (focused == null || container == null) return; focusedRef.current = focused; if (focused) { - ringContext.showElement(container, ringOptions); + ringContext.showForElement(container, ringOptions); } else if (focused === false) { ringContext.hide(); } @@ -93,11 +93,11 @@ const FocusRing = React.forwardRef(function F if (container == null) return; if (event.currentTarget === event.target) { focusedRef.current = true; - ringContext.showElement(container, ringOptions); + ringContext.showForElement(container, ringOptions); return; } setFocusWithin(true); - if (within) ringContext.showElement(container, ringOptions); + if (within) ringContext.showForElement(container, ringOptions); } function onBlur() { ringContext.hide(); @@ -121,10 +121,10 @@ const FocusRing = React.forwardRef(function F const container = ringTarget?.current; if (event.currentTarget === event.target) { focusedRef.current = true; - ringContext.showElement(container ?? event.currentTarget, ringOptions); + ringContext.showForElement(container ?? event.currentTarget, ringOptions); } else { setFocusWithin(true); - if (within) ringContext.showElement(container ?? event.currentTarget, ringOptions); + if (within) ringContext.showForElement(container ?? event.currentTarget, ringOptions); } }, [ringTarget, within, ringContext, ringOptions], @@ -149,6 +149,9 @@ const FocusRing = React.forwardRef(function F mergedChildProps.ref = mergedRef; } for (const [propKey, propValue] of Object.entries(passthroughProps as Record)) { + if (propKey === 'data-flx' && childProps['data-flx'] !== undefined) { + continue; + } if (propKey === 'className') { mergedChildProps.className = clsx(childProps.className as ClassValue, propValue as ClassValue); continue; diff --git a/fluxer_app/src/features/ui/focus_ring/FocusRingContext.ts b/fluxer_app/src/features/ui/focus_ring/FocusRingContext.ts index 4c2666a81..0b7a18f25 100644 --- a/fluxer_app/src/features/ui/focus_ring/FocusRingContext.ts +++ b/fluxer_app/src/features/ui/focus_ring/FocusRingContext.ts @@ -28,7 +28,7 @@ function parseBorderRadius(radius: string | undefined) { export class FocusRingContextManager { targetElement?: Element; - targetAncestry?: FocusRingAncestry; + ancestorChain?: FocusRingAncestry; boundingBox?: DOMRect; className?: string; offset: Offset | number = 0; @@ -40,9 +40,9 @@ export class FocusRingContextManager { this.container = element; } - showElement(element: Element, opts: FocusRingShowOpts = {}) { + showForElement(element: Element, opts: FocusRingShowOpts = {}) { this.targetElement = element; - this.targetAncestry = this.getElementAncestors(this.targetElement); + this.ancestorChain = this.collectAncestorChain(this.targetElement); this.boundingBox = undefined; this.className = opts.className; this.offset = opts.offset ?? 0; @@ -53,7 +53,7 @@ export class FocusRingContextManager { hide() { this.targetElement = undefined; - this.targetAncestry = undefined; + this.ancestorChain = undefined; this.boundingBox = undefined; this.className = undefined; this.offset = 0; @@ -65,7 +65,7 @@ export class FocusRingContextManager { return this.targetElement != null || this.boundingBox != null; } - private getElementAncestors(element?: Element): FocusRingAncestry { + private collectAncestorChain(element?: Element): FocusRingAncestry { if (element == null) return {elements: [], styles: []}; const elements: Array = []; const styles: Array = []; @@ -78,7 +78,7 @@ export class FocusRingContextManager { return {elements, styles}; } - private getNextZIndexForAncestry(ancestry: FocusRingAncestry) { + private resolveStackingLayer(ancestry: FocusRingAncestry) { for (let i = 0; i < ancestry.elements.length; i++) { const element = ancestry.elements[i]; const style = ancestry.styles[i]; @@ -89,7 +89,7 @@ export class FocusRingContextManager { return undefined; } - private getBorderRadius(ancestry: FocusRingAncestry) { + private readCornerRadii(ancestry: FocusRingAncestry) { const topLeft = parseBorderRadius(ancestry.styles[0]?.borderTopLeftRadius) ?? '0'; const topRight = parseBorderRadius(ancestry.styles[0]?.borderTopRightRadius) ?? '0'; const bottomRight = parseBorderRadius(ancestry.styles[0]?.borderBottomRightRadius) ?? '0'; @@ -100,7 +100,7 @@ export class FocusRingContextManager { return `${topLeft} ${topRight} ${bottomRight} ${bottomLeft}`; } - private makePositionFromDOMRect(rect: DOMRect) { + private computeRingBox(rect: DOMRect) { if (this.container == null) return {}; const containerRect = this.container.getBoundingClientRect(); const {scrollTop, scrollLeft} = this.container; @@ -131,17 +131,17 @@ export class FocusRingContextManager { let styles = {}; if (this.boundingBox != null) { styles = { - ...this.makePositionFromDOMRect(this.boundingBox), + ...this.computeRingBox(this.boundingBox), zIndex: this.zIndex, [FOCUS_RING_COLOR_CSS_PROPERTY]: 'var(--focus-primary)', }; } - if (this.targetElement != null && this.targetAncestry != null) { + if (this.targetElement != null && this.ancestorChain != null) { styles = { - ...this.makePositionFromDOMRect(this.targetElement.getBoundingClientRect()), - zIndex: this.zIndex ?? this.getNextZIndexForAncestry(this.targetAncestry), + ...this.computeRingBox(this.targetElement.getBoundingClientRect()), + zIndex: this.zIndex ?? this.resolveStackingLayer(this.ancestorChain), [FOCUS_RING_COLOR_CSS_PROPERTY]: 'var(--focus-primary)', - [FOCUS_RING_RADIUS_CSS_PROPERTY]: this.getBorderRadius(this.targetAncestry), + [FOCUS_RING_RADIUS_CSS_PROPERTY]: this.readCornerRadii(this.ancestorChain), }; } return styles;