mirror of
https://github.com/slidevjs/rough-notation.git
synced 2026-01-14 17:44:21 +01:00
initial code
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
node_modules
|
||||||
|
bin
|
||||||
|
dist
|
||||||
|
lib
|
||||||
|
demo
|
||||||
43
package-lock.json
generated
Normal file
43
package-lock.json
generated
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "rough-notation",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"requires": true,
|
||||||
|
"dependencies": {
|
||||||
|
"path-data-parser": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w=="
|
||||||
|
},
|
||||||
|
"points-on-curve": {
|
||||||
|
"version": "0.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz",
|
||||||
|
"integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A=="
|
||||||
|
},
|
||||||
|
"points-on-path": {
|
||||||
|
"version": "0.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz",
|
||||||
|
"integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==",
|
||||||
|
"requires": {
|
||||||
|
"path-data-parser": "0.1.0",
|
||||||
|
"points-on-curve": "0.2.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"roughjs": {
|
||||||
|
"version": "4.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.3.1.tgz",
|
||||||
|
"integrity": "sha512-m42+OBaBR7x5UhIKyjBCnWqqkaEkBKLkXvHv4pOWJXPofvMnQY4ZcFEQlqf3coKKyZN2lfWMyx7QXSg2GD7SGA==",
|
||||||
|
"requires": {
|
||||||
|
"path-data-parser": "^0.1.0",
|
||||||
|
"points-on-curve": "^0.2.0",
|
||||||
|
"points-on-path": "^0.2.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"version": "3.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.3.tgz",
|
||||||
|
"integrity": "sha512-D/wqnB2xzNFIcoBG9FG8cXRDjiqSTbG2wd8DMZeQyJlP1vfTkIxH4GKveWaEBYySKIg+USu+E+EDIR47SqnaMQ==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
30
package.json
Normal file
30
package.json
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "rough-notation",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "Annotate html",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/pshihn/rough-notation.git"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"annotate",
|
||||||
|
"rough",
|
||||||
|
"sketchy"
|
||||||
|
],
|
||||||
|
"author": "Preet Shihn",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/pshihn/rough-notation/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/pshihn/rough-notation#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^3.9.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"roughjs": "^4.3.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/keyframes.ts
Normal file
14
src/keyframes.ts
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
export function ensureKeyframes() {
|
||||||
|
if (!(window as any).__rough_notation_keyframe_styles) {
|
||||||
|
const style = (window as any).__rough_notation_keyframe_styles = document.createElement('style');
|
||||||
|
style.textContent = `
|
||||||
|
@keyframes rough-notation-dash {
|
||||||
|
to {
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
console.log('keyframe added');
|
||||||
|
document.head.appendChild(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
src/model.ts
Normal file
27
src/model.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
export const SVG_NS = 'http://www.w3.org/2000/svg';
|
||||||
|
|
||||||
|
export interface Rect {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RoughAnnotationType = 'underline' | 'box' | 'circle' | 'highlight' | 'strike-through' | 'crossed-off';
|
||||||
|
|
||||||
|
export interface RoughAnnotationConfig {
|
||||||
|
type: RoughAnnotationType;
|
||||||
|
animate?: boolean; // defaults to true
|
||||||
|
animationDuration?: number; // defaulst to 1000ms
|
||||||
|
animationDelay?: number; // default = 0
|
||||||
|
color?: string; // defaults to currentColor
|
||||||
|
strokeWidth?: number; // default based on type
|
||||||
|
padding?: number; // defaults to 5px
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RoughAnnotation {
|
||||||
|
isShowing(): boolean;
|
||||||
|
show(): void;
|
||||||
|
hide(): void;
|
||||||
|
remove(): void;
|
||||||
|
}
|
||||||
149
src/render.ts
Normal file
149
src/render.ts
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
import { Rect, RoughAnnotationConfig, SVG_NS } from './model.js';
|
||||||
|
import { ResolvedOptions, OpSet } from 'roughjs/bin/core';
|
||||||
|
import { line, rectangle, ellipse } from 'roughjs/bin/renderer';
|
||||||
|
|
||||||
|
const defaultOptions: ResolvedOptions = {
|
||||||
|
maxRandomnessOffset: 2,
|
||||||
|
roughness: 1.5,
|
||||||
|
bowing: 1,
|
||||||
|
stroke: '#000',
|
||||||
|
strokeWidth: 1.5,
|
||||||
|
curveTightness: 0,
|
||||||
|
curveFitting: 0.95,
|
||||||
|
curveStepCount: 9,
|
||||||
|
fillStyle: 'hachure',
|
||||||
|
fillWeight: -1,
|
||||||
|
hachureAngle: -41,
|
||||||
|
hachureGap: -1,
|
||||||
|
dashOffset: -1,
|
||||||
|
dashGap: -1,
|
||||||
|
zigzagOffset: -1,
|
||||||
|
seed: 0,
|
||||||
|
combineNestedSvgPaths: false,
|
||||||
|
disableMultiStroke: false,
|
||||||
|
disableMultiStrokeFill: false
|
||||||
|
};
|
||||||
|
const singleStrokeOptions = JSON.parse(JSON.stringify(defaultOptions));
|
||||||
|
singleStrokeOptions.disableMultiStroke = true;
|
||||||
|
const highlightOptions = JSON.parse(JSON.stringify(defaultOptions));
|
||||||
|
highlightOptions.roughness = 3;
|
||||||
|
|
||||||
|
export function renderAnnotation(svg: SVGSVGElement, rect: Rect, config: RoughAnnotationConfig) {
|
||||||
|
let ops: OpSet | null = null;
|
||||||
|
let strokeWidth = config.strokeWidth || 2;
|
||||||
|
const padding = (config.padding === 0) ? 0 : (config.padding || 5);
|
||||||
|
const animate = (config.animate === undefined) ? true : (!!config.animate);
|
||||||
|
|
||||||
|
switch (config.type) {
|
||||||
|
case 'underline': {
|
||||||
|
const y = rect.y + rect.h + padding;
|
||||||
|
ops = line(rect.x, y, rect.x + rect.w, y, defaultOptions);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'strike-through': {
|
||||||
|
const y = rect.y + (rect.h / 2);
|
||||||
|
ops = line(rect.x, y, rect.x + rect.w, y, defaultOptions);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'box': {
|
||||||
|
const x = rect.x - padding;
|
||||||
|
const y = rect.y - padding;
|
||||||
|
const width = rect.w + (2 * padding);
|
||||||
|
const height = rect.h + (2 * padding);
|
||||||
|
ops = rectangle(x, y, width, height, singleStrokeOptions);
|
||||||
|
const ops2 = rectangle(x, y, width, height, singleStrokeOptions);
|
||||||
|
ops.ops = [...ops.ops, ...ops2.ops];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'crossed-off': {
|
||||||
|
const x = rect.x;
|
||||||
|
const y = rect.y;
|
||||||
|
const x2 = x + rect.w;
|
||||||
|
const y2 = y + rect.h;
|
||||||
|
ops = line(x, y, x2, y2, defaultOptions);
|
||||||
|
const ops2 = line(x2, y, x, y2, defaultOptions);
|
||||||
|
ops.ops = [...ops.ops, ...ops2.ops];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'circle': {
|
||||||
|
const p2 = padding * 2;
|
||||||
|
const width = rect.w + (2 * p2);
|
||||||
|
const height = rect.h + (2 * p2);
|
||||||
|
const x = rect.x - p2 + (width / 2);
|
||||||
|
const y = rect.y - p2 + (height / 2);
|
||||||
|
ops = ellipse(x, y, width, height, defaultOptions);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'highlight': {
|
||||||
|
strokeWidth = rect.h * 0.95;
|
||||||
|
const y = rect.y + (rect.h / 2);
|
||||||
|
ops = line(rect.x, y, rect.x + rect.w, y, highlightOptions);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ops) {
|
||||||
|
const pathStrings = opsToPath(ops);
|
||||||
|
const lengths: number[] = [];
|
||||||
|
const pathElements: SVGPathElement[] = [];
|
||||||
|
let totalLength = 0;
|
||||||
|
const totalDuration = config.animationDuration === 0 ? 0 : (config.animationDuration || 500);
|
||||||
|
const initialDelay = config.animationDelay === 0 ? 0 : (config.animationDelay || 0);
|
||||||
|
|
||||||
|
for (const d of pathStrings) {
|
||||||
|
const path = document.createElementNS(SVG_NS, 'path');
|
||||||
|
path.setAttribute('d', d);
|
||||||
|
path.setAttribute('fill', 'none');
|
||||||
|
path.setAttribute('stroke', config.color || 'currentColor');
|
||||||
|
path.setAttribute('stroke-width', `${strokeWidth}`);
|
||||||
|
if (animate) {
|
||||||
|
const length = path.getTotalLength();
|
||||||
|
lengths.push(length);
|
||||||
|
totalLength += length;
|
||||||
|
}
|
||||||
|
svg.appendChild(path);
|
||||||
|
pathElements.push(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (animate) {
|
||||||
|
let durationOffset = 0;
|
||||||
|
for (let i = 0; i < pathElements.length; i++) {
|
||||||
|
const path = pathElements[i];
|
||||||
|
const length = lengths[i];
|
||||||
|
const duration = totalLength ? (totalDuration * (length / totalLength)) : 0;
|
||||||
|
const delay = initialDelay + durationOffset;
|
||||||
|
const style = path.style;
|
||||||
|
style.strokeDashoffset = `${length}`;
|
||||||
|
style.strokeDasharray = `${length}`;
|
||||||
|
style.animation = `rough-notation-dash ${duration}ms ease-out ${delay}ms forwards`;
|
||||||
|
durationOffset += duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function opsToPath(drawing: OpSet): string[] {
|
||||||
|
const paths: string[] = [];
|
||||||
|
let path = '';
|
||||||
|
for (const item of drawing.ops) {
|
||||||
|
const data = item.data;
|
||||||
|
switch (item.op) {
|
||||||
|
case 'move':
|
||||||
|
if (path.trim()) {
|
||||||
|
paths.push(path.trim());
|
||||||
|
}
|
||||||
|
path = `M${data[0]} ${data[1]} `;
|
||||||
|
break;
|
||||||
|
case 'bcurveTo':
|
||||||
|
path += `C${data[0]} ${data[1]}, ${data[2]} ${data[3]}, ${data[4]} ${data[5]} `;
|
||||||
|
break;
|
||||||
|
case 'lineTo':
|
||||||
|
path += `L${data[0]} ${data[1]} `;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path.trim()) {
|
||||||
|
paths.push(path.trim());
|
||||||
|
}
|
||||||
|
return paths;
|
||||||
|
}
|
||||||
182
src/rough-notation.ts
Normal file
182
src/rough-notation.ts
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import { Rect, RoughAnnotationConfig, RoughAnnotation, SVG_NS } from './model.js';
|
||||||
|
import { renderAnnotation } from './render.js';
|
||||||
|
import { ensureKeyframes } from './keyframes.js';
|
||||||
|
|
||||||
|
type AnootationState = 'unattached' | 'not-showing' | 'showing';
|
||||||
|
|
||||||
|
class RoughAnnotationImpl implements RoughAnnotation {
|
||||||
|
private _state: AnootationState = 'unattached';
|
||||||
|
private _config: RoughAnnotationConfig;
|
||||||
|
private _e: HTMLElement;
|
||||||
|
private _svg?: SVGSVGElement;
|
||||||
|
private _resizing = false;
|
||||||
|
private _resizeObserver?: any; // ResizeObserver is not supported in typescript std lib yet
|
||||||
|
private _lastSize?: Rect;
|
||||||
|
|
||||||
|
constructor(e: HTMLElement, config: RoughAnnotationConfig) {
|
||||||
|
this._e = e;
|
||||||
|
this._config = config;
|
||||||
|
this.attach();
|
||||||
|
}
|
||||||
|
|
||||||
|
private _resizeListener = () => {
|
||||||
|
if (!this._resizing) {
|
||||||
|
this._resizing = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
this._resizing = false;
|
||||||
|
if (this._state === 'showing') {
|
||||||
|
const newSize = this.computeSize();
|
||||||
|
if (newSize && this.hasRectChanged(newSize)) {
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private attach() {
|
||||||
|
if (this._state === 'unattached' && this._e.parentElement) {
|
||||||
|
ensureKeyframes();
|
||||||
|
const svg = this._svg = document.createElementNS(SVG_NS, 'svg');
|
||||||
|
const style = svg.style;
|
||||||
|
style.position = 'absolute';
|
||||||
|
style.top = '0';
|
||||||
|
style.left = '0';
|
||||||
|
style.overflow = 'visible';
|
||||||
|
style.pointerEvents = 'none';
|
||||||
|
style.width = '1px';
|
||||||
|
style.height = '1px';
|
||||||
|
const prepend = this._config.type === 'highlight';
|
||||||
|
this._e.insertAdjacentElement(prepend ? 'beforebegin' : 'afterend', svg);
|
||||||
|
this._state = 'not-showing';
|
||||||
|
|
||||||
|
// ensure e is positioned
|
||||||
|
if (prepend) {
|
||||||
|
const computedPos = window.getComputedStyle(this._e).position;
|
||||||
|
const unpositioned = (!computedPos) || (computedPos === 'static');
|
||||||
|
if (unpositioned) {
|
||||||
|
this._e.style.position = 'relative';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.attachListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private detachListeners() {
|
||||||
|
window.removeEventListener('resize', this._resizeListener);
|
||||||
|
if (this._resizeObserver) {
|
||||||
|
this._resizeObserver.unobserve(this._e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private attachListeners() {
|
||||||
|
this.detachListeners();
|
||||||
|
window.addEventListener('resize', this._resizeListener, { passive: true });
|
||||||
|
if ((!this._resizeObserver) && ('ResizeObserver' in window)) {
|
||||||
|
this._resizeObserver = new (window as any).ResizeObserver((entries: any) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
let trigger = true;
|
||||||
|
if (entry.contentRect) {
|
||||||
|
const newRect = this.computeSizeWithBounds(entry.contentRect);
|
||||||
|
if (newRect && (!this.hasRectChanged(newRect))) {
|
||||||
|
trigger = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (trigger) {
|
||||||
|
this._resizeListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (this._resizeObserver) {
|
||||||
|
this._resizeObserver.observe(this._e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sameInteger(a: number, b: number): boolean {
|
||||||
|
return Math.round(a) === Math.round(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
private hasRectChanged(rect: Rect): boolean {
|
||||||
|
if (this._lastSize && rect) {
|
||||||
|
return !(
|
||||||
|
this.sameInteger(rect.x, this._lastSize.x) &&
|
||||||
|
this.sameInteger(rect.y, this._lastSize.y) &&
|
||||||
|
this.sameInteger(rect.w, this._lastSize.w) &&
|
||||||
|
this.sameInteger(rect.h, this._lastSize.h)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isShowing(): boolean {
|
||||||
|
return (this._state !== 'not-showing');
|
||||||
|
}
|
||||||
|
|
||||||
|
show(): void {
|
||||||
|
switch (this._state) {
|
||||||
|
case 'unattached':
|
||||||
|
break;
|
||||||
|
case 'showing':
|
||||||
|
this.hide();
|
||||||
|
this.show();
|
||||||
|
break;
|
||||||
|
case 'not-showing':
|
||||||
|
this.attach();
|
||||||
|
if (this._svg) {
|
||||||
|
this.render(this._svg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hide(): void {
|
||||||
|
if (this._svg) {
|
||||||
|
while (this._svg.lastChild) {
|
||||||
|
this._svg.removeChild(this._svg.lastChild);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._state = 'not-showing';
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(): void {
|
||||||
|
if (this._svg && this._svg.parentElement) {
|
||||||
|
this._svg.parentElement.removeChild(this._svg);
|
||||||
|
}
|
||||||
|
this._svg = undefined;
|
||||||
|
this._state = 'unattached';
|
||||||
|
this.detachListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(svg: SVGSVGElement) {
|
||||||
|
const rect = this.computeSize();
|
||||||
|
if (rect) {
|
||||||
|
renderAnnotation(svg, rect, this._config);
|
||||||
|
this._lastSize = rect;
|
||||||
|
this._state = 'showing';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private computeSize(): Rect | null {
|
||||||
|
return this.computeSizeWithBounds(this._e.getBoundingClientRect());
|
||||||
|
}
|
||||||
|
|
||||||
|
private computeSizeWithBounds(bounds: DOMRect | DOMRectReadOnly): Rect | null {
|
||||||
|
if (this._svg) {
|
||||||
|
const rect1 = this._svg.getBoundingClientRect();
|
||||||
|
const rect2 = bounds;
|
||||||
|
|
||||||
|
const x = (rect2.x || rect2.left) - (rect1.x || rect1.left);
|
||||||
|
const y = (rect2.y || rect2.top) - (rect1.y || rect1.top);
|
||||||
|
const w = rect2.width;
|
||||||
|
const h = rect2.height;
|
||||||
|
|
||||||
|
return { x, y, w, h };
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function annotate(element: HTMLElement, config: RoughAnnotationConfig): RoughAnnotation {
|
||||||
|
return new RoughAnnotationImpl(element, config);
|
||||||
|
}
|
||||||
24
tsconfig.json
Normal file
24
tsconfig.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es2017",
|
||||||
|
"module": "es2015",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"lib": [
|
||||||
|
"es2017",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"declaration": true,
|
||||||
|
"outDir": "./lib",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"strict": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
61
tslint.json
Normal file
61
tslint.json
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
{
|
||||||
|
"rules": {
|
||||||
|
"arrow-parens": true,
|
||||||
|
"class-name": true,
|
||||||
|
"indent": [
|
||||||
|
true,
|
||||||
|
"spaces",
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"prefer-const": true,
|
||||||
|
"no-duplicate-variable": true,
|
||||||
|
"no-eval": true,
|
||||||
|
"no-internal-module": true,
|
||||||
|
"no-trailing-whitespace": false,
|
||||||
|
"no-var-keyword": true,
|
||||||
|
"one-line": [
|
||||||
|
true,
|
||||||
|
"check-open-brace",
|
||||||
|
"check-whitespace"
|
||||||
|
],
|
||||||
|
"quotemark": [
|
||||||
|
true,
|
||||||
|
"single",
|
||||||
|
"avoid-escape"
|
||||||
|
],
|
||||||
|
"semicolon": [
|
||||||
|
true,
|
||||||
|
"always"
|
||||||
|
],
|
||||||
|
"trailing-comma": [
|
||||||
|
true,
|
||||||
|
"multiline"
|
||||||
|
],
|
||||||
|
"triple-equals": [
|
||||||
|
true,
|
||||||
|
"allow-null-check"
|
||||||
|
],
|
||||||
|
"typedef-whitespace": [
|
||||||
|
true,
|
||||||
|
{
|
||||||
|
"call-signature": "nospace",
|
||||||
|
"index-signature": "nospace",
|
||||||
|
"parameter": "nospace",
|
||||||
|
"property-declaration": "nospace",
|
||||||
|
"variable-declaration": "nospace"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"variable-name": [
|
||||||
|
true,
|
||||||
|
"ban-keywords"
|
||||||
|
],
|
||||||
|
"whitespace": [
|
||||||
|
true,
|
||||||
|
"check-branch",
|
||||||
|
"check-decl",
|
||||||
|
"check-operator",
|
||||||
|
"check-separator",
|
||||||
|
"check-type"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user