Skip to content

Commit

Permalink
Migrate @superset-ui/color to TypeScript (apache#69)
Browse files Browse the repository at this point in the history
* Refactor: Convert color to TS
  • Loading branch information
kristw authored Jan 7, 2019
1 parent 9c48747 commit d860842
Show file tree
Hide file tree
Showing 28 changed files with 95 additions and 48 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
"build": "yarn run build:cjs && yarn run build:esm && yarn run type:dts",
"build:cjs": "NODE_ENV=production beemo babel --extensions=\".js,.jsx,.ts,.tsx\" ./src --out-dir lib/ --minify --workspaces=\"@superset-ui/!(demo|generator-superset)\"",
"build:esm": "NODE_ENV=production beemo babel --extensions=\".js,.jsx,.ts,.tsx\" ./src --out-dir esm/ --esm --minify --workspaces=\"@superset-ui/!(demo|generator-superset)\"",
"type": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|chart)\" --noEmit",
"type:dts": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|chart)\" --emitDeclarationOnly",
"type": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|color|chart)\" --noEmit",
"type:dts": "NODE_ENV=production beemo typescript --workspaces=\"@superset-ui/(connection|core|color|chart)\" --emitDeclarationOnly",
"lint": "beemo create-config prettier && beemo eslint \"./packages/*/{src,test,storybook}/**/*.{js,jsx,ts,tsx}\"",
"lint:fix": "beemo create-config prettier && beemo eslint --fix \"./packages/*/{src,test,storybook}/**/*.{js,jsx,ts,tsx}\"",
"jest": "beemo jest --color --coverage --react",
Expand Down
1 change: 1 addition & 0 deletions packages/superset-ui-color/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
},
"dependencies": {
"@superset-ui/core": "^0.7.0",
"@types/d3-scale": "^2.0.2",
"d3-scale": "^2.1.2"
}
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import CategoricalColorScale from './CategoricalColorScale';
import { ColorsLookup } from './types';
import getCategoricalSchemeRegistry from './CategoricalSchemeRegistrySingleton';
import stringifyAndTrim from './stringifyAndTrim';

export default class CategoricalColorNamespace {
constructor(name) {
name: string;
forcedItems: ColorsLookup;
scales: {
[key: string]: CategoricalColorScale;
};

constructor(name: string) {
this.name = name;
this.scales = {};
this.forcedItems = {};
}

getScale(schemeId) {
const id = schemeId || getCategoricalSchemeRegistry().getDefaultKey();
getScale(schemeId?: string) {
const id = schemeId || getCategoricalSchemeRegistry().getDefaultKey() || '';
const scale = this.scales[id];
if (scale) {
return scale;
}
const newScale = new CategoricalColorScale(
getCategoricalSchemeRegistry().get(id).colors,
this.forcedItems,
);
const scheme = getCategoricalSchemeRegistry().get(id);

const newScale = new CategoricalColorScale((scheme && scheme.colors) || [], this.forcedItems);
this.scales[id] = newScale;

return newScale;
Expand All @@ -31,17 +37,20 @@ export default class CategoricalColorNamespace {
* @param {*} value value
* @param {*} forcedColor color
*/
setColor(value, forcedColor) {
setColor(value: string, forcedColor: string) {
this.forcedItems[stringifyAndTrim(value)] = forcedColor;

return this;
}
}

const namespaces = {};
const namespaces: {
[key: string]: CategoricalColorNamespace;
} = {};

export const DEFAULT_NAMESPACE = 'GLOBAL';

export function getNamespace(name = DEFAULT_NAMESPACE) {
export function getNamespace(name: string = DEFAULT_NAMESPACE) {
const instance = namespaces[name];
if (instance) {
return instance;
Expand All @@ -52,12 +61,12 @@ export function getNamespace(name = DEFAULT_NAMESPACE) {
return newInstance;
}

export function getColor(value, schemeId, namespace) {
export function getColor(value?: string, schemeId?: string, namespace?: string) {
return getNamespace(namespace)
.getScale(schemeId)
.getColor(value);
}

export function getScale(scheme, namespace) {
export function getScale(scheme?: string, namespace?: string) {
return getNamespace(namespace).getScale(scheme);
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import { ExtensibleFunction } from '@superset-ui/core';
import { ColorsLookup } from './types';
import stringifyAndTrim from './stringifyAndTrim';

export default class CategoricalColorScale extends ExtensibleFunction {
colors: string[];
parentForcedColors?: ColorsLookup;
forcedColors: ColorsLookup;
seen: { [key: string]: number };

/**
* Constructor
* @param {*} colors an array of colors
* @param {*} parentForcedColors optional parameter that comes from parent
* (usually CategoricalColorNamespace) and supersede this.forcedColors
*/
constructor(colors, parentForcedColors) {
super((...args) => this.getColor(...args));
constructor(colors: string[], parentForcedColors?: ColorsLookup) {
super((value: string) => this.getColor(value));
this.colors = colors;
this.parentForcedColors = parentForcedColors;
this.forcedColors = {};
this.seen = {};
}

getColor(value) {
getColor(value?: string) {
const cleanedValue = stringifyAndTrim(value);

const parentColor = this.parentForcedColors && this.parentForcedColors[cleanedValue];
Expand Down Expand Up @@ -46,7 +52,7 @@ export default class CategoricalColorScale extends ExtensibleFunction {
* @param {*} value value
* @param {*} forcedColor forcedColor
*/
setColor(value, forcedColor) {
setColor(value: string, forcedColor: string) {
this.forcedColors[stringifyAndTrim(value)] = forcedColor;

return this;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { makeSingleton } from '@superset-ui/core';
import CategoricalScheme from './CategoricalScheme';
import ColorSchemeRegistry from './ColorSchemeRegistry';

class CategoricalSchemeRegistry extends ColorSchemeRegistry {}
class CategoricalSchemeRegistry extends ColorSchemeRegistry<CategoricalScheme> {}

const getInstance = makeSingleton(CategoricalSchemeRegistry);

Expand Down
10 changes: 0 additions & 10 deletions packages/superset-ui-color/src/ColorScheme.js

This file was deleted.

21 changes: 21 additions & 0 deletions packages/superset-ui-color/src/ColorScheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export interface ColorSchemeConfig {
colors: string[];
description?: string;
id: string;
label?: string;
}

export default class ColorScheme {
colors: string[];
description: string;
id: string;
label: string;

constructor(config: ColorSchemeConfig) {
const { colors, description = '', id, label } = config;
this.id = id;
this.label = label || id;
this.colors = colors;
this.description = description;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { RegistryWithDefaultKey } from '@superset-ui/core';

export default class ColorSchemeRegistry extends RegistryWithDefaultKey {
export default class ColorSchemeRegistry<T> extends RegistryWithDefaultKey<T> {
constructor() {
super({
name: 'ColorScheme',
setFirstItemAsDefault: true,
});
}

get(key?: string) {
return super.get(key) as T | undefined;
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { scaleLinear } from 'd3-scale';
import ColorScheme from './ColorScheme';
import ColorScheme, { ColorSchemeConfig } from './ColorScheme';

function range(count) {
function range(count: number) {
const values = [];
for (let i = 0; i < count; i += 1) {
values.push(i);
Expand All @@ -10,28 +10,34 @@ function range(count) {
return values;
}

export interface SequentialSchemeConfig extends ColorSchemeConfig {
isDiverging?: boolean;
}

export default class SequentialScheme extends ColorScheme {
constructor(input) {
super(input);
const { isDiverging = false } = input;
isDiverging: boolean;

constructor(config: SequentialSchemeConfig) {
super(config);
const { isDiverging = false } = config;
this.isDiverging = isDiverging;
}

createLinearScale(extent = [0, 1]) {
createLinearScale(extent: number[] = [0, 1]) {
// Create matching domain
// because D3 continuous scale uses piecewise mapping
// between domain and range.
const valueScale = scaleLinear().range(extent);
const denominator = this.colors.length - 1;
const domain = range(this.colors.length).map(i => valueScale(i / denominator));

return scaleLinear()
return scaleLinear<string>()
.domain(domain)
.range(this.colors)
.clamp(true);
}

getColors(numColors = this.colors.length) {
getColors(numColors: number = this.colors.length): string[] {
if (numColors === this.colors.length) {
return this.colors;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { makeSingleton } from '@superset-ui/core';
import ColorSchemeRegistry from './ColorSchemeRegistry';
import SequentialScheme from './SequentialScheme';

class SequentialSchemeRegistry extends ColorSchemeRegistry {}
class SequentialSchemeRegistry extends ColorSchemeRegistry<SequentialScheme> {}

const getInstance = makeSingleton(SequentialSchemeRegistry);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as CategoricalColorNamespace from './CategoricalColorNamespace';

export { CategoricalColorNamespace };
export { ColorSchemeConfig } from './ColorScheme';
export { default as CategoricalColorScale } from './CategoricalColorScale';
export { default as CategoricalScheme } from './CategoricalScheme';
export { default as getCategoricalSchemeRegistry } from './CategoricalSchemeRegistrySingleton';
export { default as getSequentialSchemeRegistry } from './SequentialSchemeRegistrySingleton';
export { default as SequentialScheme } from './SequentialScheme';
export { default as SequentialScheme, SequentialSchemeConfig } from './SequentialScheme';

export const BRAND_COLOR = '#00A699';
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
* Ensure value is a string
* @param {any} value
*/
export default function stringifyAndTrim(value) {
export default function stringifyAndTrim(value?: number | string) {
return String(value).trim();
}
5 changes: 5 additions & 0 deletions packages/superset-ui-color/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* eslint-disable import/prefer-default-export */

export interface ColorsLookup {
[key: string]: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,13 @@ describe('CategoricalColorNamespace', () => {
expect(scale).toBeDefined();
expect(scale.getColor('dog')).toBeDefined();
});
it('returns a scale when a schemeId is not specified and there is no default key', () => {
getCategoricalSchemeRegistry().clearDefaultKey();
const namespace = getNamespace('new-space');
const scale = namespace.getScale();
expect(scale).toBeDefined();
getCategoricalSchemeRegistry().setDefaultKey('testColors');
});
it('returns same scale if the scale with that name already exists in this namespace', () => {
const namespace = getNamespace('test-get-scale2');
const scale1 = namespace.getScale('testColors');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('CategoricalColorScale', () => {
expect(c3).not.toBe(c1);
});
it('recycles colors when number of items exceed available colors', () => {
const colorSet = {};
const colorSet: { [key: string]: number } = {};
const scale = new CategoricalColorScale(['blue', 'red', 'green']);
const colors = [
scale.getColor('pig'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ import ColorScheme from '../src/ColorScheme';

describe('ColorScheme', () => {
describe('new ColorScheme()', () => {
it('requires name and color', () => {
expect(() => new ColorScheme()).toThrow();
expect(() => new ColorScheme({ id: 'test' })).toThrow();
expect(() => new ColorScheme({ colors: ['red', 'blue'] })).toThrow();
});
it('returns an instance of ColorScheme', () => {
const scheme = new ColorScheme({ id: 'test', colors: ['red', 'blue'] });
expect(scheme).toBeInstanceOf(ColorScheme);
Expand Down
2 changes: 1 addition & 1 deletion packages/superset-ui-core/src/utils/isRequired.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export default function isRequired(field: string) {
export default function isRequired(field: string): never {
throw new Error(`${field} is required.`);
}

0 comments on commit d860842

Please sign in to comment.