Skip to content

Commit

Permalink
convert to Typescript
Browse files Browse the repository at this point in the history
  • Loading branch information
Macil committed Sep 18, 2023
1 parent 1161ce9 commit 710c78d
Show file tree
Hide file tree
Showing 19 changed files with 367 additions and 394 deletions.
2 changes: 1 addition & 1 deletion .babelrc
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-flow"
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-transform-runtime"
Expand Down
3 changes: 1 addition & 2 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
/flow-libs
/js
/dist
11 changes: 5 additions & 6 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
/* @flow */
module.exports = {
'parser': '@babel/eslint-parser',
'env': {
'browser': true,
'mocha': true,
'node': true,
'es6': true
},
'extends': ['eslint:recommended'],
'plugins': [
'flowtype'
'extends': [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
'plugins': [],
'rules': {
'flowtype/define-flow-type': 1,
'flowtype/require-valid-file-annotation': ['error', 'always'],
'@typescript-eslint/no-explicit-any': ['off'],

'indent': ['error', 2],
'linebreak-style': ['error', 'unix'],
Expand Down
14 changes: 0 additions & 14 deletions .flowconfig

This file was deleted.

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
.DS_Store
/node_modules
npm-debug.log
/js
/dist
1 change: 0 additions & 1 deletion .mocharc.yaml

This file was deleted.

4 changes: 4 additions & 0 deletions .mocharc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
require: "test/babel-register.js"
extension:
- ts
spec: "test/**/*.test.ts"
2 changes: 1 addition & 1 deletion .npmignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
*~
.DS_Store
/flow-libs
/node_modules
npm-debug.log
/src
/test
/yarn.lock
.babelrc
tsconfig.json
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
]
}
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,5 @@ uses it for building interactive menus.

## Types

Both [TypeScript](https://www.typescriptlang.org/) and
[Flow](https://flowtype.org/) type definitions for this module are included!
[TypeScript](https://www.typescriptlang.org/) type definitions for this module are included!
The type definitions won't require any configuration to use.
8 changes: 0 additions & 8 deletions flow-libs/mocha.js

This file was deleted.

48 changes: 0 additions & 48 deletions index.d.ts

This file was deleted.

18 changes: 9 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
"name": "contain-by-screen",
"version": "2.0.0",
"description": "Position a dropdown element near a button in a way that fits on the screen.",
"main": "js/index.js",
"main": "dist/src/index.js",
"sideEffects": false,
"scripts": {
"prepare": "rimraf js && babel -s true -d js/ src/ && flow-copy-source -v src js",
"test": "yarn run lint && yarn run flow_check && mocha && tsc",
"flow_check": "flow check",
"prepare": "rimraf dist && babel -s true -d dist/src/ src/ -x .ts,.tsx --ignore '**/*.test.ts,**/*.test.tsx' && tsc",
"test": "yarn run lint && mocha && tsc --noEmit --emitDeclarationOnly false",
"lint": "eslint .",
"lint-fix": "eslint . --fix"
},
Expand All @@ -34,21 +33,22 @@
"devDependencies": {
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"@babel/eslint-parser": "^7.18.9",
"@babel/plugin-transform-runtime": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-flow": "^7.0.0",
"@babel/preset-typescript": "^7.22.15",
"@babel/register": "^7.0.0",
"@types/mocha": "^10.0.1",
"@types/node": "^20.6.2",
"@typescript-eslint/eslint-plugin": "^6.7.2",
"@typescript-eslint/parser": "^6.7.2",
"eslint": "^8.23.0",
"eslint-plugin-flowtype": "^8.0.3",
"flow-bin": "^0.81.0",
"flow-copy-source": "^2.0.0",
"mocha": "^10.0.0",
"rimraf": "^5.0.1",
"typescript": "^5.2.2"
},
"dependencies": {
"@babel/runtime": "^7.0.0",
"@types/lodash": "^4.14.198",
"envify": "^4.1.0",
"lodash": "^4.6.1"
}
Expand Down
78 changes: 43 additions & 35 deletions src/index.js → src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
/* @flow */

import flatten from 'lodash/flatten';
import uniq from 'lodash/uniq';
import { isNotNil } from './isNotNil';

export type PositionOption = 'top'|'bottom'|'left'|'right'|'cover';
export type HAlignOption = 'center'|'left'|'right';
Expand All @@ -10,44 +9,44 @@ export type VAlignOption = 'center'|'top'|'bottom';
export type Position = PositionOption | PositionOption[];
export type HAlign = HAlignOption | HAlignOption[];
export type VAlign = VAlignOption | VAlignOption[];
export type Choice = {
export interface Choice {
position: PositionOption;
hAlign: HAlignOption;
vAlign: VAlignOption;
};
}

export type Coordinates = {
export interface Coordinates {
top: number;
left: number;
};
}

export type ChoiceAndCoordinates = {
export interface ChoiceAndCoordinates {
choice: Choice;
coordinates: Coordinates;
};

export type Options = {
position?: ?Position;
forcePosition?: ?boolean;
hAlign?: ?HAlign;
forceHAlign?: ?boolean;
vAlign?: ?VAlign;
forceVAlign?: ?boolean;
buffer?: ?number;
topBuffer?: ?number;
bottomBuffer?: ?number;
leftBuffer?: ?number;
rightBuffer?: ?number;
};

type Rect = { // Similar to ClientRect, but not a class
}

export interface Options {
position?: Position | null;
forcePosition?: boolean | null;
hAlign?: HAlign | null;
forceHAlign?: boolean | null;
vAlign?: VAlign | null;
forceVAlign?: boolean | null;
buffer?: number | null;
topBuffer?: number | null;
bottomBuffer?: number | null;
leftBuffer?: number | null;
rightBuffer?: number | null;
}

interface Rect {
top: number;
bottom: number;
height: number;
left: number;
right: number;
width: number;
};
}

export function containByScreen(
element: HTMLElement,
Expand Down Expand Up @@ -82,9 +81,9 @@ export function getContainByScreenResults(element: HTMLElement, anchorPoint: HTM
right: options.rightBuffer || 0
};

const optionPositions = Array.isArray(options.position) ? options.position : [options.position].filter(Boolean);
const optionHAligns = Array.isArray(options.hAlign) ? options.hAlign : [options.hAlign].filter(Boolean);
const optionVAligns = Array.isArray(options.vAlign) ? options.vAlign : [options.vAlign].filter(Boolean);
const optionPositions = Array.isArray(options.position) ? options.position : [options.position].filter(isNotNil);
const optionHAligns = Array.isArray(options.hAlign) ? options.hAlign : [options.hAlign].filter(isNotNil);
const optionVAligns = Array.isArray(options.vAlign) ? options.vAlign : [options.vAlign].filter(isNotNil);

const positions: PositionOption[] = optionPositions.length > 0 && options.forcePosition ?
optionPositions :
Expand All @@ -96,9 +95,9 @@ export function getContainByScreenResults(element: HTMLElement, anchorPoint: HTM
optionVAligns :
uniq(optionVAligns.concat(['center','top','bottom']));

const allPossibleChoices = flatten(positions.map(position =>
const allPossibleChoices: Choice[] = flatten(positions.map(position =>
(position === 'cover') ?
flatten(hAligns.map(hAlign => vAligns.map(vAlign => ({position, hAlign, vAlign})))) :
flatten(hAligns.map(hAlign => vAligns.map(vAlign => ({position, hAlign, vAlign} as Choice)))) :
(position === 'top' || position === 'bottom') ?
hAligns.map(hAlign => ({position, hAlign, vAlign: 'center'})) :
vAligns.map(vAlign => ({position, hAlign: 'center', vAlign}))
Expand Down Expand Up @@ -140,15 +139,24 @@ function getBoundingClientRect(el: Element): Rect {
let rect = el.getBoundingClientRect();
if (!('width' in rect)) {
// IE <9 support
rect = Object.assign(({
width: rect.right-rect.left,
height: rect.bottom-rect.top
}: Object), rect);
rect = {
width: (rect as any).right-(rect as any).left,
height: (rect as any).bottom-(rect as any).top,
...(rect as any)
};
}
return rect;
}

function positionAndAlign(elRect: Rect, anchorRect: Rect, {position, hAlign, vAlign}: Choice, buffers): Coordinates {
interface Buffers {
all: number;
top: number;
bottom: number;
left: number;
right: number;
}

function positionAndAlign(elRect: Rect, anchorRect: Rect, {position, hAlign, vAlign}: Choice, buffers: Buffers): Coordinates {
let top=0, left=0;
if (position === 'cover') {
switch (hAlign) {
Expand Down
7 changes: 7 additions & 0 deletions src/isNotNil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* Type predicate to avoid opting out of strict type checking in filter operations.
* Adapted from https://stackoverflow.com/a/46700791
*/
export function isNotNil<TValue>(value: TValue | null | undefined): value is TValue {
return value != null;
}
4 changes: 4 additions & 0 deletions test/babel-register.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const register = require('@babel/register').default;

register({ extensions: ['.ts', '.tsx', '.js', '.jsx'] });
Loading

0 comments on commit 710c78d

Please sign in to comment.