diff --git a/src/features/compose/editor/plugins/link-plugin.tsx b/src/features/compose/editor/plugins/link-plugin.tsx index 175f3184f4..fac30f66c1 100644 --- a/src/features/compose/editor/plugins/link-plugin.tsx +++ b/src/features/compose/editor/plugins/link-plugin.tsx @@ -7,7 +7,16 @@ import { LinkPlugin as LexicalLinkPlugin } from '@lexical/react/LexicalLinkPlugin'; import * as React from 'react'; -import { validateUrl } from '../utils/url'; +// Source: https://stackoverflow.com/a/8234912/2013580 +const urlRegExp = new RegExp( + /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/, +); + +export const validateUrl = (url: string): boolean => { + // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://. + // Maybe show a dialog where they user can type the URL before inserting it. + return url === 'https://' || urlRegExp.test(url); +}; const LinkPlugin = (): JSX.Element => { return ; diff --git a/src/features/compose/editor/utils/get-dom-range-rect.ts b/src/features/compose/editor/utils/get-dom-range-rect.ts deleted file mode 100644 index fe6d10ad0a..0000000000 --- a/src/features/compose/editor/utils/get-dom-range-rect.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This source code is derived from code from Meta Platforms, Inc. - * and affiliates, licensed under the MIT license located in the - * LICENSE file in the /src/features/compose/editor directory. - */ - -/* eslint-disable eqeqeq */ - -export const getDOMRangeRect = ( - nativeSelection: Selection, - rootElement: HTMLElement, -): DOMRect => { - const domRange = nativeSelection.getRangeAt(0); - - let rect; - - if (nativeSelection.anchorNode === rootElement) { - let inner = rootElement; - while (inner.firstElementChild != null) { - inner = inner.firstElementChild as HTMLElement; - } - rect = inner.getBoundingClientRect(); - } else { - rect = domRange.getBoundingClientRect(); - } - - return rect; -}; diff --git a/src/features/compose/editor/utils/get-selected-node.ts b/src/features/compose/editor/utils/get-selected-node.ts deleted file mode 100644 index 2f093b9837..0000000000 --- a/src/features/compose/editor/utils/get-selected-node.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * This source code is derived from code from Meta Platforms, Inc. - * and affiliates, licensed under the MIT license located in the - * LICENSE file in the /src/features/compose/editor directory. - */ - -import { $isAtNodeEnd } from '@lexical/selection'; -import { ElementNode, RangeSelection, TextNode } from 'lexical'; - -export const getSelectedNode = ( - selection: RangeSelection, -): TextNode | ElementNode => { - const anchor = selection.anchor; - const focus = selection.focus; - const anchorNode = selection.anchor.getNode(); - const focusNode = selection.focus.getNode(); - if (anchorNode === focusNode) { - return anchorNode; - } - const isBackward = selection.isBackward(); - if (isBackward) { - return $isAtNodeEnd(focus) ? anchorNode : focusNode; - } else { - return $isAtNodeEnd(anchor) ? focusNode : anchorNode; - } -}; diff --git a/src/features/compose/editor/utils/is-html-element.ts b/src/features/compose/editor/utils/is-html-element.ts deleted file mode 100644 index f7ff6f6394..0000000000 --- a/src/features/compose/editor/utils/is-html-element.ts +++ /dev/null @@ -1,4 +0,0 @@ -const isHTMLElement = (x: unknown): x is HTMLElement => x instanceof HTMLElement; - -export default isHTMLElement; -export { isHTMLElement }; diff --git a/src/features/compose/editor/utils/point.ts b/src/features/compose/editor/utils/point.ts deleted file mode 100644 index 38e825b187..0000000000 --- a/src/features/compose/editor/utils/point.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * This source code is derived from code from Meta Platforms, Inc. - * and affiliates, licensed under the MIT license located in the - * LICENSE file in the /src/features/compose/editor directory. - */ - -class Point { - - private readonly _x: number; - private readonly _y: number; - - constructor(x: number, y: number) { - this._x = x; - this._y = y; - } - - get x(): number { - return this._x; - } - - get y(): number { - return this._y; - } - - public equals({ x, y }: Point): boolean { - return this.x === x && this.y === y; - } - - public calcDeltaXTo({ x }: Point): number { - return this.x - x; - } - - public calcDeltaYTo({ y }: Point): number { - return this.y - y; - } - - public calcHorizontalDistanceTo(point: Point): number { - return Math.abs(this.calcDeltaXTo(point)); - } - - public calcVerticalDistance(point: Point): number { - return Math.abs(this.calcDeltaYTo(point)); - } - - public calcDistanceTo(point: Point): number { - return Math.sqrt( - Math.pow(this.calcDeltaXTo(point), 2) + - Math.pow(this.calcDeltaYTo(point), 2), - ); - } - -} - -const isPoint = (x: unknown): x is Point => x instanceof Point; - -export default Point; -export { Point, isPoint }; diff --git a/src/features/compose/editor/utils/rect.ts b/src/features/compose/editor/utils/rect.ts deleted file mode 100644 index 2cccc9a601..0000000000 --- a/src/features/compose/editor/utils/rect.ts +++ /dev/null @@ -1,163 +0,0 @@ -/* eslint-disable no-dupe-class-members */ -/** - * This source code is derived from code from Meta Platforms, Inc. - * and affiliates, licensed under the MIT license located in the - * LICENSE file in the /src/features/compose/editor directory. - */ - -import { isPoint, Point } from './point'; - -type ContainsPointReturn = { - result: boolean; - reason: { - isOnTopSide: boolean; - isOnBottomSide: boolean; - isOnLeftSide: boolean; - isOnRightSide: boolean; - }; -}; - -class Rect { - - private readonly _left: number; - private readonly _top: number; - private readonly _right: number; - private readonly _bottom: number; - - constructor(left: number, top: number, right: number, bottom: number) { - const [physicTop, physicBottom] = - top <= bottom ? [top, bottom] : [bottom, top]; - - const [physicLeft, physicRight] = - left <= right ? [left, right] : [right, left]; - - this._top = physicTop; - this._right = physicRight; - this._left = physicLeft; - this._bottom = physicBottom; - } - - get top(): number { - return this._top; - } - - get right(): number { - return this._right; - } - - get bottom(): number { - return this._bottom; - } - - get left(): number { - return this._left; - } - - get width(): number { - return Math.abs(this._left - this._right); - } - - get height(): number { - return Math.abs(this._bottom - this._top); - } - - public equals({ top, left, bottom, right }: Rect): boolean { - return ( - top === this._top && - bottom === this._bottom && - left === this._left && - right === this._right - ); - } - - public contains({ x, y }: Point): ContainsPointReturn; - public contains({ top, left, bottom, right }: Rect): boolean; - public contains(target: Point | Rect): boolean | ContainsPointReturn { - if (isPoint(target)) { - const { x, y } = target; - - const isOnTopSide = y < this._top; - const isOnBottomSide = y > this._bottom; - const isOnLeftSide = x < this._left; - const isOnRightSide = x > this._right; - - const result = - !isOnTopSide && !isOnBottomSide && !isOnLeftSide && !isOnRightSide; - - return { - reason: { - isOnBottomSide, - isOnLeftSide, - isOnRightSide, - isOnTopSide, - }, - result, - }; - } else { - const { top, left, bottom, right } = target; - - return ( - top >= this._top && - top <= this._bottom && - bottom >= this._top && - bottom <= this._bottom && - left >= this._left && - left <= this._right && - right >= this._left && - right <= this._right - ); - } - } - - public intersectsWith(rect: Rect): boolean { - const { left: x1, top: y1, width: w1, height: h1 } = rect; - const { left: x2, top: y2, width: w2, height: h2 } = this; - const maxX = x1 + w1 >= x2 + w2 ? x1 + w1 : x2 + w2; - const maxY = y1 + h1 >= y2 + h2 ? y1 + h1 : y2 + h2; - const minX = x1 <= x2 ? x1 : x2; - const minY = y1 <= y2 ? y1 : y2; - return maxX - minX <= w1 + w2 && maxY - minY <= h1 + h2; - } - - public generateNewRect({ - left = this.left, - top = this.top, - right = this.right, - bottom = this.bottom, - }): Rect { - return new Rect(left, top, right, bottom); - } - - static fromLTRB( - left: number, - top: number, - right: number, - bottom: number, - ): Rect { - return new Rect(left, top, right, bottom); - } - - static fromLWTH( - left: number, - width: number, - top: number, - height: number, - ): Rect { - return new Rect(left, top, left + width, top + height); - } - - static fromPoints(startPoint: Point, endPoint: Point): Rect { - const { y: top, x: left } = startPoint; - const { y: bottom, x: right } = endPoint; - return Rect.fromLTRB(left, top, right, bottom); - } - - static fromDOM(dom: HTMLElement): Rect { - const { top, width, left, height } = dom.getBoundingClientRect(); - return Rect.fromLWTH(left, width, top, height); - } - -} - -export default Rect; -export { Rect }; diff --git a/src/features/compose/editor/utils/url.ts b/src/features/compose/editor/utils/url.ts deleted file mode 100644 index ca168f0a44..0000000000 --- a/src/features/compose/editor/utils/url.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * This source code is derived from code from Meta Platforms, Inc. - * and affiliates, licensed under the MIT license located in the - * LICENSE file in the /src/features/compose/editor directory. - */ - -// Source: https://stackoverflow.com/a/8234912/2013580 -const urlRegExp = new RegExp( - /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=+$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=+$,\w]+@)[A-Za-z0-9.-]+)((?:\/[+~%/.\w-_]*)?\??(?:[-+=&;%@.\w_]*)#?(?:[\w]*))?)/, -); - -export const validateUrl = (url: string): boolean => { - // TODO Fix UI for link insertion; it should never default to an invalid URL such as https://. - // Maybe show a dialog where they user can type the URL before inserting it. - return url === 'https://' || urlRegExp.test(url); -};