Skip to content

Commit 3157cb5

Browse files
ctrl alt left/right for entry within demo selections
1 parent fe81f18 commit 3157cb5

6 files changed

Lines changed: 102 additions & 15 deletions

File tree

src/components/registry/DemoEntry.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@ export class DemoEntry {
3131
return this.demoInstances.findByTitle(title);
3232
}
3333

34+
findNextInstanceByCurrentTitle(title: string): DemoInstance {
35+
return this.demoInstances.findNextInstanceByCurrentTitle(title);
36+
}
37+
38+
findPrevInstanceByCurrentTitle(title: string): DemoInstance {
39+
return this.demoInstances.findPrevInstanceByCurrentTitle(title);
40+
}
41+
3442
isMiniApp(): boolean {
3543
return this.urlPrefix.length > 0;
3644
}

src/components/registry/DemoInstances.test.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,32 @@ describe('DemoInstances', () => {
4747
expect(demoInstances.groups[0].description).toEqual('');
4848
expect(demoInstances.groups[1].description).toEqual(desc);
4949
});
50+
51+
it('should find next entry by given current entry title', () => {
52+
demoInstances.add('a', 'description', () => <div/>);
53+
demoInstances.add('b', 'description', () => <div/>);
54+
55+
expect(demoInstances.findNextInstanceByCurrentTitle('a').title).toEqual('b');
56+
});
57+
58+
it('should find prev entry by given current entry title', () => {
59+
demoInstances.add('a', 'description', () => <div/>);
60+
demoInstances.add('b', 'description', () => <div/>);
61+
62+
expect(demoInstances.findPrevInstanceByCurrentTitle('b').title).toEqual('a');
63+
});
64+
65+
it('should find first entry when looking for a prev entry and no entry with given title exist', () => {
66+
demoInstances.add('a', 'description', () => <div/>);
67+
demoInstances.add('b', 'description', () => <div/>);
68+
69+
expect(demoInstances.findPrevInstanceByCurrentTitle('wrong-title').title).toEqual('a');
70+
});
71+
72+
it('should find last entry when looking for a next entry and current title is last already', () => {
73+
demoInstances.add('a', 'description', () => <div/>);
74+
demoInstances.add('b', 'description', () => <div/>);
75+
76+
expect(demoInstances.findNextInstanceByCurrentTitle('b').title).toEqual('b');
77+
});
5078
});

src/components/registry/DemoInstances.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from 'react';
22

33
import { DemoInstance } from './DemoInstance';
44
import { DemoInstancesGroup } from './DemoInstancesGroup';
5+
import { findAndReturn } from './listUtils';
56

67
export class DemoInstances {
78
groups: DemoInstancesGroup[] = [];
@@ -31,16 +32,32 @@ export class DemoInstances {
3132
}
3233

3334
findByTitle(title: string): DemoInstance {
34-
const found = this.all.filter(instance => instance.title === title);
35-
if (! found.length) {
35+
const found = findInstanceAndReturn(this.all, title, idx => this.all[idx]);
36+
if (!found) {
3637
throw new Error('cannot find demo instance with "' + title + '" title');
3738
}
3839

39-
return found[0];
40+
return found;
41+
}
42+
43+
findNextInstanceByCurrentTitle(title: string): DemoInstance {
44+
const found = findInstanceAndReturn(this.all, title, idx => this.all[idx + 1]);
45+
return found ? found : this.all[this.all.length - 1];
46+
}
47+
48+
findPrevInstanceByCurrentTitle(title: string): DemoInstance {
49+
const found = findInstanceAndReturn(this.all, title, idx => this.all[idx - 1]);
50+
return found ? found : this.all[0];
4051
}
4152

4253
private createNewGroup(description: string) {
4354
this.currentGroup = new DemoInstancesGroup(description);
4455
this.groups.push(this.currentGroup);
4556
}
57+
}
58+
59+
function findInstanceAndReturn(instances: DemoInstance[],
60+
title: string,
61+
returnFunc: (idx: number) => DemoInstance | undefined) {
62+
return findAndReturn(instances, instance => instance.title === title, returnFunc);
4663
}

src/components/registry/Registry.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { LayoutProps } from '../layouts/LayoutProps';
77
import { LabelInstanceTableLayout } from '../layouts/LabelInstanceTableLayout';
88
import { SingleItemLayout } from '../layouts/SingleItemLayout';
99
import { wrapComponent, WrapperProps } from './componentWrapper';
10+
import { findAndReturn } from './listUtils';
1011

1112
export interface RegistryConfig {
1213
componentWrapper?: React.ComponentType<WrapperProps>;
@@ -124,16 +125,8 @@ class Registry {
124125

125126
function findDemoAndReturn(demos: DemoEntry[],
126127
currentDemoName: string,
127-
returnFunc: (idx: number) => DemoEntry | null) {
128-
let idx = 0;
129-
for (const demo of demos) {
130-
if (demo.name === currentDemoName) {
131-
return returnFunc(idx);
132-
}
133-
idx++;
134-
}
135-
136-
return undefined;
128+
returnFunc: (idx: number) => DemoEntry | undefined) {
129+
return findAndReturn(demos, demo => demo.name === currentDemoName, returnFunc);
137130
}
138131

139132
export { Registry };
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export function findAndReturn<V>(values: V[],
2+
predicate: (v: V) => boolean,
3+
returnFunc: (idx: number) => V | undefined) {
4+
let idx = 0;
5+
for (const v of values) {
6+
if (predicate(v)) {
7+
return returnFunc(idx);
8+
}
9+
idx++;
10+
}
11+
12+
return undefined;
13+
}

src/components/viewer/ComponentViewer.tsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
4545
this.state = this.stateFromUrl();
4646
this.hotKeyBoundActions = {
4747
'Alt F': this.onFullScreenToggle,
48-
'Alt Down': this.onNextDemo,
49-
'Alt Up': this.onPrevDemo,
48+
'Ctrl Alt Down': this.onNextDemo,
49+
'Ctrl Alt Up': this.onPrevDemo,
50+
'Ctrl Alt Right': this.onNextDemoEntry,
51+
'Ctrl Alt Left': this.onPrevDemoEntry,
5052
...this.dropDownKeyBoundActions()
5153
};
5254
}
@@ -220,6 +222,18 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
220222
}));
221223
}
222224

225+
private onNextDemoEntry = () => {
226+
this.withRegistryAndDemoAndTitleWhenPresent(((registry, demo, title) => {
227+
this.selectInstanceByTitle(demo.findNextInstanceByCurrentTitle(title).title);
228+
}));
229+
}
230+
231+
private onPrevDemoEntry = () => {
232+
this.withRegistryAndDemoAndTitleWhenPresent(((registry, demo, title) => {
233+
this.selectInstanceByTitle(demo.findPrevInstanceByCurrentTitle(title).title);
234+
}));
235+
}
236+
223237
private withRegistryAndDemoNameWhenPresent = (code: (registry: Registry, demoName: string) => void) => {
224238
const registry = this.findSelectedRegistry();
225239
const {demoName} = this.state;
@@ -231,6 +245,20 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
231245
code(registry, demoName);
232246
}
233247

248+
private withRegistryAndDemoAndTitleWhenPresent = (
249+
code: (registry: Registry, demo: DemoEntry, title: string) => void
250+
) => {
251+
this.withRegistryAndDemoNameWhenPresent(((registry, demoName) => {
252+
const demo = registry.findDemoByName(demoName);
253+
if (!demo) {
254+
return;
255+
}
256+
257+
const {entryTitle} = this.state;
258+
code(registry, demo, entryTitle);
259+
}));
260+
}
261+
234262
private selectRegistry = (registryName: string) => {
235263
this.pushUrl(
236264
registryName,

0 commit comments

Comments
 (0)