Skip to content

Commit 5ed81c0

Browse files
streamline mini apps: add url auto nav; shortcut for registrator (#33)
1 parent aa69609 commit 5ed81c0

11 files changed

Lines changed: 95 additions & 39 deletions

src/App.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@ import { Registries } from './components';
44
import { ComponentViewer } from './components';
55
import { buttonsDemo } from './demos/buttons';
66
import { linksDemo } from './demos/links';
7-
import { profileScreenDemo } from './demos/profileScreen';
7+
import { ProfileApp } from './demos/ProfileApp';
88
import { sideBySideDemo } from './demos/sideBySide';
99
import { inputsDemo } from './demos/inputs';
1010
import { WrapperProps } from './components/registry/componentWrapper';
11+
import { ProfileScreenDemo } from './demos/ProfileScreenDemo';
1112

1213
const registries = new Registries({componentWrapper: DemoWrapper});
1314
registries.add('components')
@@ -19,8 +20,8 @@ registries.add('layouts')
1920
.registerAsRows('Side by Side', sideBySideDemo);
2021

2122
registries.add('screens')
22-
.registerSingle('Single Screen', profileScreenDemo)
23-
.registerAsMiniApp('Single Screen mini app', '/app', profileScreenDemo);
23+
.registerSingle('Single Screen', ProfileScreenDemo)
24+
.registerAsMiniApp('Single Screen mini app', '/app', /\/app/, ProfileApp);
2425

2526
export class App extends React.Component {
2627
render() {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import * as React from 'react';
2+
3+
export interface Props {
4+
initialUrl: string;
5+
urlRegexp: RegExp;
6+
component: React.ComponentType;
7+
}
8+
9+
export class NavigateToUrlWrapper extends React.Component<Props> {
10+
render() {
11+
const {component: Component} = this.props;
12+
return (
13+
<Component/>
14+
);
15+
}
16+
17+
componentDidMount() {
18+
const {initialUrl, urlRegexp} = this.props;
19+
20+
if (urlRegexp.test(document.location.pathname + document.location.search)) {
21+
return;
22+
}
23+
24+
document.location.href = initialUrl;
25+
}
26+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import * as React from 'react';
2+
import { Registry } from '..';
3+
import { NavigateToUrlWrapper } from './NavigateToUrlWrapper';
4+
5+
export function createRegistratorForMiniApp(initialUrl: string, urlRegexp: RegExp, miniApp: React.ComponentType) {
6+
return function miniAppRegistrator(registry: Registry) {
7+
registry.add(initialUrl, () => (
8+
<NavigateToUrlWrapper
9+
initialUrl={initialUrl}
10+
urlRegexp={urlRegexp}
11+
component={miniApp}
12+
/>)
13+
);
14+
};
15+
}
16+
17+
export function createRegistratorForSingle(name: string, singleComponent: React.ComponentType) {
18+
const SingleComponent = singleComponent;
19+
20+
return function singleComponentRegistrator(registry: Registry) {
21+
registry.add(name, () => (<SingleComponent/>));
22+
};
23+
}

src/components/registry/DemoEntry.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@ export class DemoEntry {
99
layoutComponent: React.ComponentType<LayoutProps>;
1010
layoutOpts: object;
1111
demoInstances: DemoInstances;
12-
urlPrefix: string;
12+
urlRegexp?: RegExp;
1313

14-
constructor(name: string, layoutInstance: React.ComponentType<LayoutProps>, urlPrefix: string, layoutOpts: object) {
14+
constructor(name: string,
15+
layoutInstance: React.ComponentType<LayoutProps>,
16+
urlRegexp: RegExp | undefined,
17+
layoutOpts: object) {
1518
this.name = name;
1619
this.layoutComponent = layoutInstance;
17-
this.urlPrefix = urlPrefix;
20+
this.urlRegexp = urlRegexp;
1821
this.layoutOpts = layoutOpts;
1922
this.demoInstances = new DemoInstances();
2023
}
@@ -40,7 +43,7 @@ export class DemoEntry {
4043
}
4144

4245
isMiniApp(): boolean {
43-
return this.urlPrefix.length > 0;
46+
return !!this.urlRegexp;
4447
}
4548

4649
get firstEntryTitle(): string {

src/components/registry/Registry.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { LabelInstanceTableLayout } from '../layouts/LabelInstanceTableLayout';
88
import { SingleItemLayout } from '../layouts/SingleItemLayout';
99
import { wrapComponent, WrapperProps } from './componentWrapper';
1010
import { findAndReturn } from './listUtils';
11+
import { createRegistratorForMiniApp, createRegistratorForSingle } from '../registrators/registrators';
1112

1213
export interface RegistryConfig {
1314
componentWrapper?: React.ComponentType<WrapperProps>;
@@ -28,11 +29,11 @@ class Registry {
2829
}
2930

3031
registerAsGrid(name: string, minWidth: number, componentRegistrator: (registry: Registry) => void) {
31-
return this.register(name, GridLayout, componentRegistrator, '', {minWidth});
32+
return this.register(name, GridLayout, componentRegistrator, undefined, {minWidth});
3233
}
3334

3435
registerAsRows(name: string, componentRegistrator: (registry: Registry) => void) {
35-
return this.register(name, GridLayout, componentRegistrator, '', {minWidth: 0});
36+
return this.register(name, GridLayout, componentRegistrator, undefined, {minWidth: 0});
3637
}
3738

3839
registerAsTabs(name: string, componentRegistrator: (registry: Registry) => void) {
@@ -43,26 +44,26 @@ class Registry {
4344
return this.register(name, LabelInstanceTableLayout, componentRegistrator);
4445
}
4546

46-
registerSingle(name: string, componentRegistrator: (registry: Registry) => void) {
47-
this.register(name, SingleItemLayout, componentRegistrator);
48-
return this;
47+
registerSingle(name: string, singleComponent: React.ComponentType) {
48+
return this.register(name, SingleItemLayout, createRegistratorForSingle(name, singleComponent));
4949
}
5050

51-
registerAsMiniApp(name: string, urlPrefix: string, componentRegistrator: (registry: Registry) => void) {
52-
this.register(name, SingleItemLayout, componentRegistrator, urlPrefix);
51+
registerAsMiniApp(name: string, initialUrl: string, urlRegexp: RegExp, appComponent: React.ComponentType) {
52+
return this.register(name, SingleItemLayout,
53+
createRegistratorForMiniApp(initialUrl, urlRegexp, appComponent), urlRegexp);
5354
}
5455

5556
register(name: string,
5657
layoutComponent: React.ComponentType<LayoutProps>,
5758
componentRegistrator: (registry: Registry) => void,
58-
urlPrefix: string = '',
59+
urlRegexp: RegExp | undefined = undefined,
5960
layoutOpts: object = {}) {
6061

6162
if (this.usedNames.indexOf(name) !== -1) {
6263
throw new Error(`name ${name} was already used`);
6364
}
6465

65-
this.currentDemo = new DemoEntry(name, layoutComponent, urlPrefix, layoutOpts);
66+
this.currentDemo = new DemoEntry(name, layoutComponent, urlRegexp, layoutOpts);
6667
this.demoEntries.push(this.currentDemo);
6768

6869
this.usedNames.push(name);
@@ -102,7 +103,7 @@ class Registry {
102103

103104
firstMiniAppByUrl(url: string): DemoEntry | null {
104105
const byUrl = this.demoEntries
105-
.filter(entry => entry.isMiniApp() && url.startsWith(entry.urlPrefix));
106+
.filter(entry => entry.isMiniApp() && entry.urlRegexp!.test(url));
106107

107108
return byUrl.length > 0 ? byUrl[0] : null;
108109
}

src/components/viewer/ComponentViewer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
163163
}
164164

165165
stateFromUrl() {
166-
return this.stateCreator.stateFromUrl(document.location.search);
166+
return this.stateCreator.stateFromUrl(document.location.pathname, document.location.search);
167167
}
168168

169169
updateStateFromUrl = (callback?: () => void) => {

src/components/viewer/ComponentViewerStateCreator.test.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,20 @@ describe('ComponentViewerStateCreator', () => {
99
beforeAll(() => {
1010
registries = new Registries();
1111
registries.add('core')
12-
.registerSingle('FirstC', (registry => registry.add('title-c-a', () => <div/>)));
12+
.registerSingle('FirstC', () => <div/>);
1313
registries.add('widgets')
14-
.registerSingle('FirstW', (registry => registry.add('title-w-a', () => <div/>)));
14+
.registerSingle('FirstW', () => <div/>);
1515

1616
});
1717

1818
it('should pick the first registry, first demo and demo entry if url has no query params', () => {
1919
const stateCreator = new ComponentViewerStateCreator(registries);
20-
const state = stateCreator.stateFromUrl('/path');
20+
const state = stateCreator.stateFromUrl('/path', '');
2121

2222
expect(state).toEqual({
2323
registryName: 'core',
2424
demoName: 'FirstC',
25-
entryTitle: 'title-c-a',
25+
entryTitle: 'FirstC',
2626
filterText: '',
2727
isFullScreen: false,
2828
isHelpOn: false,
@@ -32,7 +32,7 @@ describe('ComponentViewerStateCreator', () => {
3232

3333
it('should take fullscreen state from url', () => {
3434
const stateCreator = new ComponentViewerStateCreator(registries);
35-
const state = stateCreator.stateFromUrl('_rcv_fs=true');
35+
const state = stateCreator.stateFromUrl('', '_rcv_fs=true');
3636

3737
expect(state.isFullScreen).toEqual(true);
3838
});

src/components/viewer/ComponentViewerStateCreator.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ export class ComponentViewerStateCreator {
2929
this._registries = registries;
3030
}
3131

32-
stateFromUrl(url: string): ComponentViewerState {
33-
const searchParams = new URLSearchParams(url);
32+
stateFromUrl(path: string, search: string): ComponentViewerState {
33+
const searchParams = new URLSearchParams(search);
3434

3535
const selectedToolbarItem = searchParams.get(queryParamNames.selectedToolbarItem) || '';
3636

37-
const miniAppByUrl = this.miniAppByUrl(url);
37+
const miniAppByUrl = this.miniAppByUrl(path + search);
3838
if (miniAppByUrl) {
3939
return {
4040
registryName: miniAppByUrl.registry.name,

src/demos/ProfileApp.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import * as React from 'react';
2+
import { ProfileScreenDemo } from './ProfileScreenDemo';
3+
4+
export function ProfileApp() {
5+
return (
6+
<ProfileScreenDemo/>
7+
);
8+
}

src/demos/ProfileScreenDemo.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import * as React from 'react';
2+
3+
export function ProfileScreenDemo() {
4+
return (
5+
<div>Profile Screen</div>
6+
);
7+
}

0 commit comments

Comments
 (0)