UNPKG

@reactodia/workspace

Version:

Reactodia Workspace -- library for visual interaction with graphs in a form of a diagram.

122 lines (107 loc) 3.38 kB
interface BasicMap<K, V> { get(key: K): V | undefined; set(key: K, value: V): unknown; delete(key: K): unknown; } export function multimapArrayAdd<K, V>(map: BasicMap<K, V[]>, key: K, value: V): void { let values = map.get(key); if (!values) { values = []; map.set(key, values); } values.push(value); } export function multimapAdd<K, V>(map: BasicMap<K, Set<V>>, key: K, value: V): void { let itemSet = map.get(key); if (!itemSet) { itemSet = new Set(); map.set(key, itemSet); } itemSet.add(value); } export function multimapDelete<K, V>(map: BasicMap<K, Set<V>>, key: K, value: V): void { const itemSet = map.get(key); if (itemSet) { itemSet.delete(value); if (itemSet.size === 0) { map.delete(key); } } } /** * Returns `true` if two arrays has equal elements (compared via `===`) * and in the same order, otherwise returns `false`. * * @category Utilities */ export function shallowArrayEqual<T>(a: ReadonlyArray<T>, b: ReadonlyArray<T>): boolean { if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; i++) { if (a[i] !== b[i]) { return false; } } return true; } export class OrderedMap<V> { private mapping = new Map<string, V>(); private ordered: V[] = []; reorder(compare: (a: V, b: V) => number) { this.ordered.sort(compare); } get items(): ReadonlyArray<V> { return this.ordered; } get(key: string): V | undefined { return this.mapping.get(key); } push(key: string, value: V) { if (this.mapping.has(key)) { const previous = this.mapping.get(key)!; if (previous === value) { return; } const index = this.ordered.indexOf(previous); this.ordered.splice(index, 1); } this.mapping.set(key, value); this.ordered.push(value); } delete(key: string): V | undefined { if (!this.mapping.has(key)) { return undefined; } const previous = this.mapping.get(key)!; const index = this.ordered.indexOf(previous); this.ordered.splice(index, 1); this.mapping.delete(key); return previous; } } /** * Makes a sorting comparator (a function to pass to `Array.sort()`) which * moves specified subset of items either to the beginning of the array * or to the end. * * @category Utilities */ export function moveComparator<T>( items: ReadonlyArray<T>, selected: ReadonlyArray<T>, moveDirection: 'start' | 'end', ): (a: T, b: T) => number { const orderMap = new Map<T, number>(); const moveSign = moveDirection === 'start' ? -1 : 1; const selectionIndexOffset = moveSign * items.length; items.forEach((item, index) => { orderMap.set(item, index); }); for (const selectedItem of selected) { orderMap.set(selectedItem, selectionIndexOffset + orderMap.get(selectedItem)!); } return (a: T, b: T) => { const orderA = orderMap.get(a)!; const orderB = orderMap.get(b)!; return ( orderA > orderB ? 1 : orderA < orderB ? -1 : 0 ); }; }