From dd93dd4f0a8124fa3f679bee69558f5bc3b5c22d Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Mon, 16 Jul 2018 09:48:35 +0100 Subject: [PATCH 1/4] Fixing bad property name. --- .../Output/custom-els/TwoUp/index.ts | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/components/Output/custom-els/TwoUp/index.ts b/src/components/Output/custom-els/TwoUp/index.ts index c5dc080a1..77e032536 100644 --- a/src/components/Output/custom-els/TwoUp/index.ts +++ b/src/components/Output/custom-els/TwoUp/index.ts @@ -1,15 +1,13 @@ import * as styles from './styles.css'; import { PointerTracker, Pointer } from '../../../../lib/PointerTracker'; -const legacyClipCompat = 'legacy-clip-compat'; +const legacyClipCompatAttr = 'legacy-clip-compat'; /** * A split view that the user can adjust. The first child becomes * the left-hand side, and the second child becomes the right-hand side. */ export default class TwoUp extends HTMLElement { - static get observedAttributes () { return [legacyClipCompat]; } - private readonly _handle = document.createElement('div'); /** * The position of the split in pixels. @@ -52,7 +50,7 @@ export default class TwoUp extends HTMLElement { }); } - connectedCallback () { + connectedCallback() { this._childrenChange(); if (!this._everConnected) { // Set the initial position of the handle. @@ -69,22 +67,22 @@ export default class TwoUp extends HTMLElement { * If true, this element works in browsers that don't support clip-path (Edge). * However, this means you'll have to set the height of this element manually. */ - get noClipPathCompat () { - return this.hasAttribute(legacyClipCompat); + get legacyClipCompat() { + return this.hasAttribute(legacyClipCompatAttr); } - set noClipPathCompat (val: boolean) { + set legacyClipCompat(val: boolean) { if (val) { - this.setAttribute(legacyClipCompat, ''); + this.setAttribute(legacyClipCompatAttr, ''); } else { - this.removeAttribute(legacyClipCompat); + this.removeAttribute(legacyClipCompatAttr); } } /** * Called when element's child list changes */ - private _childrenChange () { + private _childrenChange() { // Ensure the handle is the last child. // The CSS depends on this. if (this.lastElementChild !== this._handle) { @@ -103,7 +101,7 @@ export default class TwoUp extends HTMLElement { this._setPosition(); } - private _setPosition () { + private _setPosition() { this.style.setProperty('--split-point', `${this._position}px`); } } From 9aff12322bd371a1af18da40c53e19f84a9144c3 Mon Sep 17 00:00:00 2001 From: Jake Archibald Date: Mon, 16 Jul 2018 10:42:11 +0100 Subject: [PATCH 2/4] Allowing two-up to work vertically at smaller widths. --- .../Output/custom-els/TwoUp/index.ts | 51 +++++++++++++++---- .../custom-els/TwoUp/missing-types.d.ts | 7 ++- .../Output/custom-els/TwoUp/styles.css | 29 +++++++++++ src/components/Output/index.tsx | 36 +++++++++---- 4 files changed, 104 insertions(+), 19 deletions(-) diff --git a/src/components/Output/custom-els/TwoUp/index.ts b/src/components/Output/custom-els/TwoUp/index.ts index 77e032536..0dc5bc8c0 100644 --- a/src/components/Output/custom-els/TwoUp/index.ts +++ b/src/components/Output/custom-els/TwoUp/index.ts @@ -2,12 +2,15 @@ import * as styles from './styles.css'; import { PointerTracker, Pointer } from '../../../../lib/PointerTracker'; const legacyClipCompatAttr = 'legacy-clip-compat'; +const verticalAttr = 'vertical'; /** * A split view that the user can adjust. The first child becomes * the left-hand side, and the second child becomes the right-hand side. */ export default class TwoUp extends HTMLElement { + static get observedAttributes() { return [verticalAttr]; } + private readonly _handle = document.createElement('div'); /** * The position of the split in pixels. @@ -53,16 +56,26 @@ export default class TwoUp extends HTMLElement { connectedCallback() { this._childrenChange(); if (!this._everConnected) { - // Set the initial position of the handle. - requestAnimationFrame(() => { - const bounds = this.getBoundingClientRect(); - this._position = bounds.width / 2; - this._setPosition(); - }); + this._resetPosition(); this._everConnected = true; } } + attributeChangedCallback(name: string) { + if (name === verticalAttr) { + this._resetPosition(); + } + } + + private _resetPosition() { + // Set the initial position of the handle. + requestAnimationFrame(() => { + const bounds = this.getBoundingClientRect(); + this._position = (this.vertical ? bounds.height : bounds.width) / 2; + this._setPosition(); + }); + } + /** * If true, this element works in browsers that don't support clip-path (Edge). * However, this means you'll have to set the height of this element manually. @@ -79,6 +92,21 @@ export default class TwoUp extends HTMLElement { } } + /** + * Split vertically rather than horizontally. + */ + get vertical() { + return this.hasAttribute(verticalAttr); + } + + set vertical(val: boolean) { + if (val) { + this.setAttribute(verticalAttr, ''); + } else { + this.removeAttribute(verticalAttr); + } + } + /** * Called when element's child list changes */ @@ -93,11 +121,16 @@ export default class TwoUp extends HTMLElement { /** * Called when a pointer moves. */ - private _pointerChange (startPoint: Pointer, currentPoint: Pointer) { + private _pointerChange(startPoint: Pointer, currentPoint: Pointer) { + const pointAxis = this.vertical ? 'clientY' : 'clientX'; + const dimensionAxis = this.vertical ? 'height' : 'width'; const bounds = this.getBoundingClientRect(); - this._position = this._positionOnPointerStart + (currentPoint.clientX - startPoint.clientX); + + this._position = this._positionOnPointerStart + + (currentPoint[pointAxis] - startPoint[pointAxis]); + // Clamp position to element bounds. - this._position = Math.max(0, Math.min(this._position, bounds.width)); + this._position = Math.max(0, Math.min(this._position, bounds[dimensionAxis])); this._setPosition(); } diff --git a/src/components/Output/custom-els/TwoUp/missing-types.d.ts b/src/components/Output/custom-els/TwoUp/missing-types.d.ts index ebc916bd5..6801af744 100644 --- a/src/components/Output/custom-els/TwoUp/missing-types.d.ts +++ b/src/components/Output/custom-els/TwoUp/missing-types.d.ts @@ -9,8 +9,13 @@ interface Window { Touch: typeof Touch; } +interface TwoUpAttributes extends JSX.HTMLAttributes { + 'vertical'?: boolean; + 'legacy-clip-compat'?: boolean; +} + declare namespace JSX { interface IntrinsicElements { - 'two-up': HTMLAttributes; + 'two-up': TwoUpAttributes; } } diff --git a/src/components/Output/custom-els/TwoUp/styles.css b/src/components/Output/custom-els/TwoUp/styles.css index 3463ec1bd..fb6677d63 100644 --- a/src/components/Output/custom-els/TwoUp/styles.css +++ b/src/components/Output/custom-els/TwoUp/styles.css @@ -36,6 +36,17 @@ two-up[legacy-clip-compat] > :not(.twoUpHandle) { border-radius: 20px; } +two-up[vertical] .twoUpHandle { + width: auto; + height: 10px; + transform: translateY(var(--split-point)) translateY(-50%); +} + +two-up[vertical] .twoUpHandle::after { + width: 40px; + height: 80px; +} + two-up > :nth-child(1):not(.twoUpHandle) { -webkit-clip-path: inset(0 calc(100% - var(--split-point)) 0 0); clip-path: inset(0 calc(100% - var(--split-point)) 0 0); @@ -46,6 +57,16 @@ two-up > :nth-child(2):not(.twoUpHandle) { clip-path: inset(0 0 0 var(--split-point)); } +two-up[vertical] > :nth-child(1):not(.twoUpHandle) { + -webkit-clip-path: inset(0 0 calc(100% - var(--split-point)) 0); + clip-path: inset(0 0 calc(100% - var(--split-point)) 0); +} + +two-up[vertical] > :nth-child(2):not(.twoUpHandle) { + -webkit-clip-path: inset(var(--split-point) 0 0 0); + clip-path: inset(var(--split-point) 0 0 0); +} + /* Even in legacy-clip-compat, prefer clip-path if it's supported. It performs way better in Safari. @@ -58,4 +79,12 @@ two-up > :nth-child(2):not(.twoUpHandle) { two-up[legacy-clip-compat] > :nth-child(2):not(.twoUpHandle) { clip: rect(auto auto auto var(--split-point)); } + + two-up[vertical][legacy-clip-compat] > :nth-child(1):not(.twoUpHandle) { + clip: rect(auto auto var(--split-point) auto); + } + + two-up[vertical][legacy-clip-compat] > :nth-child(2):not(.twoUpHandle) { + clip: rect(var(--split-point) auto auto auto); + } } diff --git a/src/components/Output/index.tsx b/src/components/Output/index.tsx index 88884ec30..e00cbe1f6 100644 --- a/src/components/Output/index.tsx +++ b/src/components/Output/index.tsx @@ -6,21 +6,31 @@ import * as style from './style.scss'; import { bind, drawBitmapToCanvas, linkRef } from '../../lib/util'; import { twoUpHandle } from './custom-els/TwoUp/styles.css'; -type Props = { - leftImg: ImageBitmap, - rightImg: ImageBitmap, -}; +interface Props { + leftImg: ImageBitmap; + rightImg: ImageBitmap; +} -type State = {}; +interface State { + verticalTwoUp: boolean; +} export default class Output extends Component { - state: State = {}; + widthQuery = window.matchMedia('(min-width: 500px)'); + state: State = { + verticalTwoUp: !this.widthQuery.matches, + }; canvasLeft?: HTMLCanvasElement; canvasRight?: HTMLCanvasElement; pinchZoomLeft?: PinchZoom; pinchZoomRight?: PinchZoom; retargetedEvents = new WeakSet(); + constructor() { + super(); + this.widthQuery.addListener(this.onMobileWidthChange); + } + componentDidMount() { if (this.canvasLeft) { drawBitmapToCanvas(this.canvasLeft, this.props.leftImg); @@ -39,8 +49,15 @@ export default class Output extends Component { } } - shouldComponentUpdate(nextProps: Props) { - return this.props.leftImg !== nextProps.leftImg || this.props.rightImg !== nextProps.rightImg; + shouldComponentUpdate(nextProps: Props, nextState: State) { + return this.props.leftImg !== nextProps.leftImg || + this.props.rightImg !== nextProps.rightImg || + this.state.verticalTwoUp !== nextState.verticalTwoUp; + } + + @bind + onMobileWidthChange() { + this.setState({ verticalTwoUp: !this.widthQuery.matches }); } @bind @@ -80,10 +97,11 @@ export default class Output extends Component { this.pinchZoomLeft.dispatchEvent(clonedEvent); } - render({ leftImg, rightImg }: Props, { }: State) { + render({ leftImg, rightImg }: Props, { verticalTwoUp }: State) { return (
Date: Mon, 16 Jul 2018 16:05:26 +0100 Subject: [PATCH 3/4] Switching to orientation attr --- .../Output/custom-els/TwoUp/index.ts | 27 +++++++++---------- .../custom-els/TwoUp/missing-types.d.ts | 4 ++- .../Output/custom-els/TwoUp/styles.css | 12 ++++----- src/components/Output/index.tsx | 2 +- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/components/Output/custom-els/TwoUp/index.ts b/src/components/Output/custom-els/TwoUp/index.ts index 0dc5bc8c0..371cd82b3 100644 --- a/src/components/Output/custom-els/TwoUp/index.ts +++ b/src/components/Output/custom-els/TwoUp/index.ts @@ -2,14 +2,14 @@ import * as styles from './styles.css'; import { PointerTracker, Pointer } from '../../../../lib/PointerTracker'; const legacyClipCompatAttr = 'legacy-clip-compat'; -const verticalAttr = 'vertical'; +const orientationAttr = 'orientation'; /** * A split view that the user can adjust. The first child becomes * the left-hand side, and the second child becomes the right-hand side. */ export default class TwoUp extends HTMLElement { - static get observedAttributes() { return [verticalAttr]; } + static get observedAttributes() { return [orientationAttr]; } private readonly _handle = document.createElement('div'); /** @@ -62,7 +62,7 @@ export default class TwoUp extends HTMLElement { } attributeChangedCallback(name: string) { - if (name === verticalAttr) { + if (name === orientationAttr) { this._resetPosition(); } } @@ -71,7 +71,7 @@ export default class TwoUp extends HTMLElement { // Set the initial position of the handle. requestAnimationFrame(() => { const bounds = this.getBoundingClientRect(); - this._position = (this.vertical ? bounds.height : bounds.width) / 2; + this._position = (this.orientation === 'vertical' ? bounds.height : bounds.width) / 2; this._setPosition(); }); } @@ -95,16 +95,15 @@ export default class TwoUp extends HTMLElement { /** * Split vertically rather than horizontally. */ - get vertical() { - return this.hasAttribute(verticalAttr); + get orientation(): TwoUpOrientation { + const value = this.getAttribute(orientationAttr); + + if (value === 'vertical') return value; + return 'horizontal'; } - set vertical(val: boolean) { - if (val) { - this.setAttribute(verticalAttr, ''); - } else { - this.removeAttribute(verticalAttr); - } + set orientation(val: TwoUpOrientation) { + this.setAttribute(orientationAttr, val); } /** @@ -122,8 +121,8 @@ export default class TwoUp extends HTMLElement { * Called when a pointer moves. */ private _pointerChange(startPoint: Pointer, currentPoint: Pointer) { - const pointAxis = this.vertical ? 'clientY' : 'clientX'; - const dimensionAxis = this.vertical ? 'height' : 'width'; + const pointAxis = this.orientation === 'vertical' ? 'clientY' : 'clientX'; + const dimensionAxis = this.orientation === 'vertical' ? 'height' : 'width'; const bounds = this.getBoundingClientRect(); this._position = this._positionOnPointerStart + diff --git a/src/components/Output/custom-els/TwoUp/missing-types.d.ts b/src/components/Output/custom-els/TwoUp/missing-types.d.ts index 6801af744..599b3f668 100644 --- a/src/components/Output/custom-els/TwoUp/missing-types.d.ts +++ b/src/components/Output/custom-els/TwoUp/missing-types.d.ts @@ -9,8 +9,10 @@ interface Window { Touch: typeof Touch; } +type TwoUpOrientation = 'horizontal' | 'vertical'; + interface TwoUpAttributes extends JSX.HTMLAttributes { - 'vertical'?: boolean; + 'orientation'?: TwoUpOrientation; 'legacy-clip-compat'?: boolean; } diff --git a/src/components/Output/custom-els/TwoUp/styles.css b/src/components/Output/custom-els/TwoUp/styles.css index fb6677d63..19e547b33 100644 --- a/src/components/Output/custom-els/TwoUp/styles.css +++ b/src/components/Output/custom-els/TwoUp/styles.css @@ -36,13 +36,13 @@ two-up[legacy-clip-compat] > :not(.twoUpHandle) { border-radius: 20px; } -two-up[vertical] .twoUpHandle { +two-up[orientation='vertical'] .twoUpHandle { width: auto; height: 10px; transform: translateY(var(--split-point)) translateY(-50%); } -two-up[vertical] .twoUpHandle::after { +two-up[orientation='vertical'] .twoUpHandle::after { width: 40px; height: 80px; } @@ -57,12 +57,12 @@ two-up > :nth-child(2):not(.twoUpHandle) { clip-path: inset(0 0 0 var(--split-point)); } -two-up[vertical] > :nth-child(1):not(.twoUpHandle) { +two-up[orientation='vertical'] > :nth-child(1):not(.twoUpHandle) { -webkit-clip-path: inset(0 0 calc(100% - var(--split-point)) 0); clip-path: inset(0 0 calc(100% - var(--split-point)) 0); } -two-up[vertical] > :nth-child(2):not(.twoUpHandle) { +two-up[orientation='vertical'] > :nth-child(2):not(.twoUpHandle) { -webkit-clip-path: inset(var(--split-point) 0 0 0); clip-path: inset(var(--split-point) 0 0 0); } @@ -80,11 +80,11 @@ two-up[vertical] > :nth-child(2):not(.twoUpHandle) { clip: rect(auto auto auto var(--split-point)); } - two-up[vertical][legacy-clip-compat] > :nth-child(1):not(.twoUpHandle) { + two-up[orientation='vertical'][legacy-clip-compat] > :nth-child(1):not(.twoUpHandle) { clip: rect(auto auto var(--split-point) auto); } - two-up[vertical][legacy-clip-compat] > :nth-child(2):not(.twoUpHandle) { + two-up[orientation='vertical'][legacy-clip-compat] > :nth-child(2):not(.twoUpHandle) { clip: rect(var(--split-point) auto auto auto); } } diff --git a/src/components/Output/index.tsx b/src/components/Output/index.tsx index e00cbe1f6..99cdaff39 100644 --- a/src/components/Output/index.tsx +++ b/src/components/Output/index.tsx @@ -101,7 +101,7 @@ export default class Output extends Component { return (
Date: Tue, 17 Jul 2018 10:33:08 +0100 Subject: [PATCH 4/4] Fixing type and getter/setter behaviour --- src/components/Output/custom-els/TwoUp/index.ts | 6 +++++- src/components/Output/custom-els/TwoUp/missing-types.d.ts | 4 +--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/Output/custom-els/TwoUp/index.ts b/src/components/Output/custom-els/TwoUp/index.ts index 371cd82b3..7ba144f8a 100644 --- a/src/components/Output/custom-els/TwoUp/index.ts +++ b/src/components/Output/custom-els/TwoUp/index.ts @@ -4,6 +4,8 @@ import { PointerTracker, Pointer } from '../../../../lib/PointerTracker'; const legacyClipCompatAttr = 'legacy-clip-compat'; const orientationAttr = 'orientation'; +type TwoUpOrientation = 'horizontal' | 'vertical'; + /** * A split view that the user can adjust. The first child becomes * the left-hand side, and the second child becomes the right-hand side. @@ -98,7 +100,9 @@ export default class TwoUp extends HTMLElement { get orientation(): TwoUpOrientation { const value = this.getAttribute(orientationAttr); - if (value === 'vertical') return value; + // This mirrors the behaviour of input.type, where setting just sets the attribute, but getting + // returns the value only if it's valid. + if (value && value.toLowerCase() === 'vertical') return 'vertical'; return 'horizontal'; } diff --git a/src/components/Output/custom-els/TwoUp/missing-types.d.ts b/src/components/Output/custom-els/TwoUp/missing-types.d.ts index 599b3f668..fde547bd7 100644 --- a/src/components/Output/custom-els/TwoUp/missing-types.d.ts +++ b/src/components/Output/custom-els/TwoUp/missing-types.d.ts @@ -9,10 +9,8 @@ interface Window { Touch: typeof Touch; } -type TwoUpOrientation = 'horizontal' | 'vertical'; - interface TwoUpAttributes extends JSX.HTMLAttributes { - 'orientation'?: TwoUpOrientation; + 'orientation'?: string; 'legacy-clip-compat'?: boolean; }