feat(Pairing): add nextFocalId cycle math and expose slice API
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
export { comboKey } from './comboKey/comboKey';
|
||||||
|
export { createPairing } from './createPairing/createPairing';
|
||||||
|
export { nextFocalId } from './nextFocalId/nextFocalId';
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import {
|
||||||
|
describe,
|
||||||
|
expect,
|
||||||
|
it,
|
||||||
|
} from 'vitest';
|
||||||
|
import { nextFocalId } from './nextFocalId';
|
||||||
|
|
||||||
|
const ids = ['a', 'b', 'c'];
|
||||||
|
|
||||||
|
describe('nextFocalId', () => {
|
||||||
|
it('steps forward', () => {
|
||||||
|
expect(nextFocalId(ids, 'a', 1)).toBe('b');
|
||||||
|
});
|
||||||
|
it('steps backward', () => {
|
||||||
|
expect(nextFocalId(ids, 'b', -1)).toBe('a');
|
||||||
|
});
|
||||||
|
it('wraps forward at the end', () => {
|
||||||
|
expect(nextFocalId(ids, 'c', 1)).toBe('a');
|
||||||
|
});
|
||||||
|
it('wraps backward at the start', () => {
|
||||||
|
expect(nextFocalId(ids, 'a', -1)).toBe('c');
|
||||||
|
});
|
||||||
|
it('returns the only id when list has one', () => {
|
||||||
|
expect(nextFocalId(['solo'], 'solo', 1)).toBe('solo');
|
||||||
|
});
|
||||||
|
it('returns current when focal id is absent', () => {
|
||||||
|
expect(nextFocalId(ids, 'missing', 1)).toBe('missing');
|
||||||
|
});
|
||||||
|
it('returns null for an empty list', () => {
|
||||||
|
expect(nextFocalId([], 'x', 1)).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* The id one step from `currentId` in board order, wrapping at both ends.
|
||||||
|
*
|
||||||
|
* @param orderedIds - Pairing ids in board order.
|
||||||
|
* @param currentId - The currently focal id to step from.
|
||||||
|
* @param direction - +1 for next, -1 for previous.
|
||||||
|
* @returns The neighbouring id (wrapped), `currentId` unchanged if it isn't in
|
||||||
|
* the list, or null for an empty list.
|
||||||
|
*/
|
||||||
|
export function nextFocalId(orderedIds: string[], currentId: string, direction: 1 | -1): string | null {
|
||||||
|
if (orderedIds.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const i = orderedIds.indexOf(currentId);
|
||||||
|
if (i === -1) {
|
||||||
|
return currentId;
|
||||||
|
}
|
||||||
|
const len = orderedIds.length;
|
||||||
|
const next = (i + direction + len) % len;
|
||||||
|
return orderedIds[next];
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
export {
|
||||||
|
comboKey,
|
||||||
|
createPairing,
|
||||||
|
nextFocalId,
|
||||||
|
} from './domain';
|
||||||
|
export type {
|
||||||
|
Pairing,
|
||||||
|
Role,
|
||||||
|
} from './model/types';
|
||||||
Reference in New Issue
Block a user