diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..29cdb07c8d --- /dev/null +++ b/.eslintignore @@ -0,0 +1,5 @@ +node_modules +dist +fixtures +coverage +__snapshots__ diff --git a/packages/core/src/common/constructor.ts b/packages/core/src/common/constructor.ts index 373a6a9563..12d50c07ea 100644 --- a/packages/core/src/common/constructor.ts +++ b/packages/core/src/common/constructor.ts @@ -18,6 +18,4 @@ * Generic interface defining constructor types, such as classes. This is used to type the class * itself in meta-programming situations such as decorators. */ -export interface IConstructor { - new (...args: any[]): T; -} +export type IConstructor = new (...args: any[]) => T; diff --git a/packages/core/src/common/errors.ts b/packages/core/src/common/errors.ts index 5f71c69a68..e3b81a7522 100644 --- a/packages/core/src/common/errors.ts +++ b/packages/core/src/common/errors.ts @@ -99,5 +99,5 @@ export const DRAWER_VERTICAL_IS_IGNORED = ns + ` vertical is ignored if export const DRAWER_ANGLE_POSITIONS_ARE_CASTED = ns + ` all angle positions are casted into pure position (TOP, BOTTOM, LEFT or RIGHT)`; -export const TOASTER_MAX_TOASTS_INVALID = ns + ` maxToasts is set to an invalid number, must be greater than 0`; - +export const TOASTER_MAX_TOASTS_INVALID = + ns + ` maxToasts is set to an invalid number, must be greater than 0`; diff --git a/packages/core/src/common/position.ts b/packages/core/src/common/position.ts index 9b1271cde5..67ddb69185 100644 --- a/packages/core/src/common/position.ts +++ b/packages/core/src/common/position.ts @@ -55,11 +55,7 @@ export function isPositionVertical(position: Position) { } export function getPositionIgnoreAngles(position: Position) { - if ( - position === Position.TOP || - position === Position.TOP_LEFT || - position === Position.TOP_RIGHT - ) { + if (position === Position.TOP || position === Position.TOP_LEFT || position === Position.TOP_RIGHT) { return Position.TOP; } else if ( position === Position.BOTTOM || @@ -67,11 +63,7 @@ export function getPositionIgnoreAngles(position: Position) { position === Position.BOTTOM_RIGHT ) { return Position.BOTTOM; - } else if ( - position === Position.LEFT || - position === Position.LEFT_TOP || - position === Position.LEFT_BOTTOM - ) { + } else if (position === Position.LEFT || position === Position.LEFT_TOP || position === Position.LEFT_BOTTOM) { return Position.LEFT; } else { return Position.RIGHT; diff --git a/packages/core/src/common/utils.ts b/packages/core/src/common/utils.ts index f391d23a25..532f399f95 100644 --- a/packages/core/src/common/utils.ts +++ b/packages/core/src/common/utils.ts @@ -209,8 +209,8 @@ export function countDecimalPlaces(num: number) { if (!isFinite(num)) { return 0; } - let e = 1, - p = 0; + let e = 1; + let p = 0; while (Math.round(num * e) / e !== num) { e *= 10; p++; diff --git a/packages/core/test/common/utils/compareUtilsTests.ts b/packages/core/test/common/utils/compareUtilsTests.ts index cd2933b604..0546fa57bf 100644 --- a/packages/core/test/common/utils/compareUtilsTests.ts +++ b/packages/core/test/common/utils/compareUtilsTests.ts @@ -277,7 +277,10 @@ describe("CompareUtils", () => { describe("returns unequal key/values if any specified values are not deeply equal", () => { runTest( - [{ key: "a", valueA: 2, valueB: 1 }, { key: "b", valueA: [2, 3, 4], valueB: [1, 2, 3] }], + [ + { key: "a", valueA: 2, valueB: 1 }, + { key: "b", valueA: [2, 3, 4], valueB: [1, 2, 3] }, + ], { a: 2, b: [2, 3, 4], c: "3" }, { b: [1, 2, 3], a: 1, c: "3" }, ["a", "b"], diff --git a/packages/core/test/overlay/overlayTests.tsx b/packages/core/test/overlay/overlayTests.tsx index c7008991dc..033abf3aad 100644 --- a/packages/core/test/overlay/overlayTests.tsx +++ b/packages/core/test/overlay/overlayTests.tsx @@ -368,6 +368,26 @@ describe("", () => { assertFocus("button", done); }); + it("does not crash while trying to return focus to overlay if user clicks outside the document", () => { + mountWrapper( + + {createOverlayContents()} + , + ); + + // this is a fairly custom / nonstandard event dispatch, trying to simulate what happens in some browsers when a user clicks + // on the browser toolbar (outside the document), but a focus event is still dispatched to document + // see https://github.com/palantir/blueprint/issues/3928 + const event = new FocusEvent("focus"); + Object.defineProperty(event, "target", { value: window }); + + try { + document.dispatchEvent(event); + } catch (e) { + assert.fail("threw uncaught error"); + } + }); + function assertFocus(selector: string | (() => void), done: MochaDone) { // the behavior being tested relies on requestAnimationFrame. // setTimeout for a few frames later to let things settle (to reduce flakes). diff --git a/packages/core/test/popover/popperUtilTests.ts b/packages/core/test/popover/popperUtilTests.ts index c4aa479689..221bfd8597 100644 --- a/packages/core/test/popover/popperUtilTests.ts +++ b/packages/core/test/popover/popperUtilTests.ts @@ -20,7 +20,10 @@ import { arrowOffsetModifier, getAlignment, getOppositePosition } from "../../sr describe("Popper utils", () => { it("getOppositePosition returns opposite", () => { - [["top", "bottom"], ["left", "right"]].map(([a, b]) => { + [ + ["top", "bottom"], + ["left", "right"], + ].map(([a, b]) => { expect(getOppositePosition(a as Position)).to.equal(b); expect(getOppositePosition(b as Position)).to.equal(a); }); @@ -34,12 +37,16 @@ describe("Popper utils", () => { describe("arrow offset modifier shifts away from popover", () => { it("right", () => { - const { offsets: { popper, arrow } } = arrowOffsetModifier(getPopperData("right"), {}); + const { + offsets: { popper, arrow }, + } = arrowOffsetModifier(getPopperData("right"), {}); expect(popper.left).to.be.greaterThan(arrow.left); }); it("left", () => { - const { offsets: { popper, arrow } } = arrowOffsetModifier(getPopperData("left"), {}); + const { + offsets: { popper, arrow }, + } = arrowOffsetModifier(getPopperData("left"), {}); expect(popper.left).to.be.lessThan(arrow.left); }); diff --git a/packages/core/test/toast/toasterTests.ts b/packages/core/test/toast/toasterTests.ts index 713ffa3326..47f2030a6d 100644 --- a/packages/core/test/toast/toasterTests.ts +++ b/packages/core/test/toast/toasterTests.ts @@ -72,7 +72,10 @@ describe("Toaster", () => { const key = toaster.show({ message: "two" }); toaster.show({ message: "six" }); toaster.dismiss(key); - assert.deepEqual(toaster.getToasts().map(t => t.message), ["six", "one"]); + assert.deepEqual( + toaster.getToasts().map(t => t.message), + ["six", "one"], + ); }); it("clear() removes all toasts", () => { diff --git a/packages/icons/src/iconName.ts b/packages/icons/src/iconName.ts index c18acb95c1..9b97bdb0a0 100644 --- a/packages/icons/src/iconName.ts +++ b/packages/icons/src/iconName.ts @@ -5,4 +5,4 @@ import * as IconNames from "./generated/iconNames"; /** String literal union type of all Blueprint UI icon names. */ -export type IconName = (typeof IconNames)[keyof typeof IconNames]; +export type IconName = typeof IconNames[keyof typeof IconNames]; diff --git a/packages/landing-app/src/logo.ts b/packages/landing-app/src/logo.ts index b4454d7ff7..b2be7abdc4 100644 --- a/packages/landing-app/src/logo.ts +++ b/packages/landing-app/src/logo.ts @@ -417,7 +417,11 @@ export type ISegment = [Point, Point]; export class Corner extends Transformable { public static CORNER() { return new Corner( - [[P(), P().translate(-1, 0, 0)], [P(), P().translate(0, 1, 0)], [P(), P().translate(0, 0, -1)]], + [ + [P(), P().translate(-1, 0, 0)], + [P(), P().translate(0, 1, 0)], + [P(), P().translate(0, 0, -1)], + ], P(), ); } @@ -520,7 +524,7 @@ export const T = { return t => callback(t === 0 ? 0 : Math.pow(e, 10 * (t - 1))); }, EASE_IN_OUT: (callback: IAnimatedCallback): IAnimatedCallback => { - return t => callback((t *= 2) < 1 ? 1 / 2 * t * t * t * t : -1 / 2 * ((t -= 2) * t * t * t - 2)); + return t => callback((t *= 2) < 1 ? (1 / 2) * t * t * t * t : (-1 / 2) * ((t -= 2) * t * t * t - 2)); }, EASE_IN_OUT_EXP: (e: number, callback: IAnimatedCallback): IAnimatedCallback => { return t => { @@ -529,9 +533,9 @@ export const T = { } else if (t === 1) { callback(1); } else if ((t *= 2) < 1) { - callback(1 / 2 * Math.pow(e, 10 * (t - 1))); + callback((1 / 2) * Math.pow(e, 10 * (t - 1))); } else { - callback(1 / 2 * (-Math.pow(e, -10 * --t) + 2)); + callback((1 / 2) * (-Math.pow(e, -10 * --t) + 2)); } }; }, @@ -1100,7 +1104,13 @@ export function initializeLogo(canvas: HTMLCanvasElement, canvasBackground: HTML .timeline() .tween(0, () => model.restore().translate(0, -8, 0)) .tween(offset + 100) - .tween(1000, T.EASE_OUT_EXP(2, T.INTERPOLATE(-8, 0, (t: number) => model.restore().translate(0, t, 0)))); + .tween( + 1000, + T.EASE_OUT_EXP( + 2, + T.INTERPOLATE(-8, 0, (t: number) => model.restore().translate(0, t, 0)), + ), + ); }; slideDownAnimation(0, slideInGroups[0]); diff --git a/packages/node-build-scripts/es-lint.js b/packages/node-build-scripts/es-lint.js index ce137f9756..5f7040d2f8 100755 --- a/packages/node-build-scripts/es-lint.js +++ b/packages/node-build-scripts/es-lint.js @@ -31,7 +31,7 @@ if (process.argv.includes("--fix")) { } // ESLint will fail if provided with no files, so we expand the glob before running it -const fileGlob = "{src,test}/**/*.tsx"; +const fileGlob = "{src,test}/**/*.{ts,tsx}"; const absoluteFileGlob = path.resolve(process.cwd(), fileGlob); const anyFilesToLint = glob.sync(absoluteFileGlob) if (anyFilesToLint.length === 0) { diff --git a/packages/select/test/listItemsPropsTests.ts b/packages/select/test/listItemsPropsTests.ts index 244d65b4f1..7c21531f81 100644 --- a/packages/select/test/listItemsPropsTests.ts +++ b/packages/select/test/listItemsPropsTests.ts @@ -18,18 +18,17 @@ import { assert } from "chai"; import * as sinon from "sinon"; import { executeItemsEqual } from "../src/common/listItemsProps"; - describe("IListItemsProps Utils", () => { describe("executeItemsEqual", () => { // interface for a non-primitive item value - interface ItemObject { + interface IItemObject { id: string; label: string; listOfValues: number[]; nullField: null; } - const ITEM_OBJECT_A: ItemObject = { + const ITEM_OBJECT_A: IItemObject = { id: "A", label: "Item A", listOfValues: [1, 2], @@ -37,21 +36,21 @@ describe("IListItemsProps Utils", () => { }; // Exactly the same contents as ITEM_OBJECT_A, but a different object - const ITEM_OBJECT_A_DUPLICATE: ItemObject = { + const ITEM_OBJECT_A_DUPLICATE: IItemObject = { id: "A", label: "Item A", listOfValues: [1, 2], nullField: null, }; - const ITEM_OBJECT_A_EQUIVALENT: ItemObject = { + const ITEM_OBJECT_A_EQUIVALENT: IItemObject = { id: "A", label: "Equivalent to item A based on 'id'", listOfValues: [3, 4], nullField: null, }; - const ITEM_OBJECT_B: ItemObject = { + const ITEM_OBJECT_B: IItemObject = { id: "B", label: "Item B", listOfValues: [5, 6], @@ -83,10 +82,10 @@ describe("IListItemsProps Utils", () => { describe("itemsEqual is a property name", () => { it("treats null and undefined as distinctly different", () => { - assert.isTrue(executeItemsEqual("id", null, null)); - assert.isTrue(executeItemsEqual("id", undefined, undefined)); - assert.isFalse(executeItemsEqual("id", null, undefined)); - assert.isFalse(executeItemsEqual("id", undefined, null)); + assert.isTrue(executeItemsEqual("id", null, null)); + assert.isTrue(executeItemsEqual("id", undefined, undefined)); + assert.isFalse(executeItemsEqual("id", null, undefined)); + assert.isFalse(executeItemsEqual("id", undefined, null)); }); it("compares primitives correctly", () => { @@ -102,13 +101,13 @@ describe("IListItemsProps Utils", () => { }); it("does not incorrectly compare null to a property with a null value", () => { - assert.isFalse(executeItemsEqual("nullField", ITEM_OBJECT_A, null)); + assert.isFalse(executeItemsEqual("nullField", ITEM_OBJECT_A, null)); }); }); describe("itemsEqual is a function", () => { // Simple equality comparator that compares IDs of ItemObjects. - const equalityComparator = sinon.spy((itemA: ItemObject, itemB: ItemObject): boolean => { + const equalityComparator = sinon.spy((itemA: IItemObject, itemB: IItemObject): boolean => { return itemA.id === itemB.id; }); @@ -117,33 +116,33 @@ describe("IListItemsProps Utils", () => { }); it("treats null and undefined as distinctly different", () => { - assert.isTrue(executeItemsEqual(equalityComparator, null, null)); - assert.isTrue(executeItemsEqual(equalityComparator, undefined, undefined)); - assert.isFalse(executeItemsEqual(equalityComparator, null, undefined)); - assert.isFalse(executeItemsEqual(equalityComparator, undefined, null)); + assert.isTrue(executeItemsEqual(equalityComparator, null, null)); + assert.isTrue(executeItemsEqual(equalityComparator, undefined, undefined)); + assert.isFalse(executeItemsEqual(equalityComparator, null, undefined)); + assert.isFalse(executeItemsEqual(equalityComparator, undefined, null)); assert(!equalityComparator.called); }); it("calls the function and uses its result (true)", () => { assert.isTrue( - executeItemsEqual(equalityComparator, ITEM_OBJECT_A, ITEM_OBJECT_A_EQUIVALENT), + executeItemsEqual(equalityComparator, ITEM_OBJECT_A, ITEM_OBJECT_A_EQUIVALENT), ); assert(equalityComparator.calledWith(ITEM_OBJECT_A, ITEM_OBJECT_A_EQUIVALENT)); assert(equalityComparator.returned(true)); }); it("calls the function and uses its result (false)", () => { - assert.isFalse(executeItemsEqual(equalityComparator, ITEM_OBJECT_A, ITEM_OBJECT_B)); + assert.isFalse(executeItemsEqual(equalityComparator, ITEM_OBJECT_A, ITEM_OBJECT_B)); assert(equalityComparator.calledWith(ITEM_OBJECT_A, ITEM_OBJECT_B)); assert(equalityComparator.returned(false)); }); it("does not call the function if one param is null/undefined", () => { - assert.isFalse(executeItemsEqual(equalityComparator, ITEM_OBJECT_A, null)); - assert.isFalse(executeItemsEqual(equalityComparator, ITEM_OBJECT_A, undefined)); - assert.isFalse(executeItemsEqual(equalityComparator, null, ITEM_OBJECT_A)); - assert.isFalse(executeItemsEqual(equalityComparator, undefined, ITEM_OBJECT_A)); + assert.isFalse(executeItemsEqual(equalityComparator, ITEM_OBJECT_A, null)); + assert.isFalse(executeItemsEqual(equalityComparator, ITEM_OBJECT_A, undefined)); + assert.isFalse(executeItemsEqual(equalityComparator, null, ITEM_OBJECT_A)); + assert.isFalse(executeItemsEqual(equalityComparator, undefined, ITEM_OBJECT_A)); assert(!equalityComparator.called); }); diff --git a/packages/table/src/common/utils.ts b/packages/table/src/common/utils.ts index 05de754853..1934ddc08e 100644 --- a/packages/table/src/common/utils.ts +++ b/packages/table/src/common/utils.ts @@ -14,10 +14,12 @@ * limitations under the License. */ +import { Icon } from "@blueprintjs/core"; + // used to exclude icons from column header measure export const CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT = "bp-table-text-no-measure"; // supposed width of the icons placeholder -const EXCLUDED_ICON_PLACEHOLDER_WIDTH = 16; +const EXCLUDED_ICON_PLACEHOLDER_WIDTH = Icon.SIZE_STANDARD; /** * Since Firefox doesn't provide a computed "font" property, we manually @@ -356,7 +358,7 @@ function measureTextContentWithExclusions(context: CanvasRenderingContext2D, ele const elementsToExclude = element.querySelectorAll(`.${CLASSNAME_EXCLUDED_FROM_TEXT_MEASUREMENT}`); let excludedElementsWidth = 0; if (elementsToExclude && elementsToExclude.length) { - elementsToExclude.forEach((e) => { + elementsToExclude.forEach(e => { const excludedMetrics = context.measureText(e.textContent); excludedElementsWidth += excludedMetrics.width - EXCLUDED_ICON_PLACEHOLDER_WIDTH; }); diff --git a/packages/table/src/interactions/resizeSensor.ts b/packages/table/src/interactions/resizeSensor.ts index 27e5f6474a..5a7ec8cde5 100644 --- a/packages/table/src/interactions/resizeSensor.ts +++ b/packages/table/src/interactions/resizeSensor.ts @@ -76,7 +76,8 @@ export class ResizeSensor { }; } - private static RESIZE_SENSOR_STYLE = "position: absolute; left: 0; top: 0; right: 0; " + + private static RESIZE_SENSOR_STYLE = + "position: absolute; left: 0; top: 0; right: 0; " + "bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;"; private static RESIZE_SENSOR_HTML = `
{ it("copies cells", () => { - const success = Clipboard.copyCells([["A", "B", "C"], ["D", "E", "F"]]); + const success = Clipboard.copyCells([ + ["A", "B", "C"], + ["D", "E", "F"], + ]); expect(success).to.be.false; }); diff --git a/packages/table/test/regionsTests.ts b/packages/table/test/regionsTests.ts index 16778f7a01..637e91652a 100644 --- a/packages/table/test/regionsTests.ts +++ b/packages/table/test/regionsTests.ts @@ -261,14 +261,30 @@ describe("Regions", () => { expect(invalid).to.have.lengthOf(0); const cells = Regions.enumerateUniqueCells([Regions.column(0), Regions.row(0)], 3, 2); - expect(cells).to.deep.equal([[0, 0], [0, 1], [1, 0], [2, 0]]); + expect(cells).to.deep.equal([ + [0, 0], + [0, 1], + [1, 0], + [2, 0], + ]); }); it("sparsely maps cells", () => { - const cells = [[0, 0], [0, 1], [1, 0], [2, 0]] as ICellCoordinate[]; + const cells = [ + [0, 0], + [0, 1], + [1, 0], + [2, 0], + ] as ICellCoordinate[]; const sparse = Regions.sparseMapCells(cells, () => "X"); // normal deep equals doesn't work here so we use JSON.stringify - expect(JSON.stringify(sparse)).to.equal(JSON.stringify([["X", "X"], ["X", null], ["X", null]])); + expect(JSON.stringify(sparse)).to.equal( + JSON.stringify([ + ["X", "X"], + ["X", null], + ["X", null], + ]), + ); }); describe("clampRegion", () => {