Skip to content

Commit 126811d

Browse files
mini-app explicit selection. dropdowns enumeration api changes. (#34)
1 parent d964f0c commit 126811d

17 files changed

Lines changed: 196 additions & 138 deletions

src/App.tsx

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { sideBySideDemo } from './demos/sideBySide';
99
import { inputsDemo } from './demos/inputs';
1010
import { WrapperProps } from './components/registry/componentWrapper';
1111
import { ProfileScreenDemo } from './demos/ProfileScreenDemo';
12+
import { DropDowns } from './components/viewer/dropdown/DropDowns';
1213

1314
const registries = new Registries({componentWrapper: DemoWrapper});
1415
registries.add('components')
@@ -21,47 +22,35 @@ registries.add('layouts')
2122

2223
registries.add('screens')
2324
.registerSingle('Single Screen', ProfileScreenDemo)
24-
.registerAsMiniApp('Single Screen mini app', '/app', /\/app/, ProfileApp);
25+
.registerAsMiniApp('Single Screen mini app', /\/app/,
26+
{'welcome part': '/app/welcome'},
27+
ProfileApp);
28+
29+
const dropDowns = new DropDowns();
30+
dropDowns.add('Brand')
31+
.addItem('Brand-A', 'Alt 1')
32+
.addItem('B-Brand', 'Alt 2')
33+
.onSelect(onBrandSelect);
34+
35+
dropDowns.add('Services')
36+
.addItem('Fake', 'Alt 5')
37+
.addItem('REST', 'Alt 6')
38+
.onSelect(onServiceSelect);
2539

2640
export class App extends React.Component {
2741
render() {
2842
return (
29-
<ComponentViewer
30-
registries={registries}
31-
dropDowns={[this.createServiceDropDown(), this.createBrandDropDown()]}
32-
/>
43+
<ComponentViewer registries={registries} dropDowns={dropDowns}/>
3344
);
3445
}
46+
}
3547

36-
private createBrandDropDown() {
37-
return {
38-
label: 'Brand',
39-
items: [
40-
{label: 'Brand-A', hotKey: 'Alt 1'},
41-
{label: 'B-Brand', hotKey: 'Alt 2'}
42-
],
43-
onSelect: this.onBrandSelect
44-
};
45-
}
46-
47-
private createServiceDropDown() {
48-
return {
49-
label: 'Services',
50-
items: [
51-
{label: 'Fake', hotKey: 'Alt 5'},
52-
{label: 'REST', hotKey: 'Alt 6'}
53-
],
54-
onSelect: this.onServiceSelect
55-
};
56-
}
57-
58-
private onBrandSelect = (brand: string) => {
59-
console.log('selected brand', brand);
60-
}
48+
function onBrandSelect(brand: string) {
49+
console.log('selected brand', brand);
50+
}
6151

62-
private onServiceSelect = (service: string) => {
63-
console.log('selected service', service);
64-
}
52+
function onServiceSelect(service: string) {
53+
console.log('selected service', service);
6554
}
6655

6756
function DemoWrapper({OriginalComponent}: WrapperProps) {
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+
import { currentUrlMatchesRegexp } from './urlUtils';
3+
4+
export interface Props {
5+
component: React.ComponentType;
6+
urlRegexp: RegExp;
7+
urlsByLabel: { [label: string]: string };
8+
}
9+
10+
export function MiniAppUrlsSelection({component: Component, urlRegexp, urlsByLabel}: Props) {
11+
const renderComponent = currentUrlMatchesRegexp(urlRegexp);
12+
13+
if (renderComponent) {
14+
return <Component/>;
15+
}
16+
17+
return (
18+
<div>
19+
{Object.keys(urlsByLabel).map(label => (
20+
<div>
21+
<a href={urlsByLabel[label]}>{label}</a>
22+
</div>
23+
))}
24+
</div>
25+
);
26+
}

src/components/miniapp/urlUtils.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function currentUrl() {
2+
return document.location.pathname + '?' + document.location.search;
3+
}
4+
5+
export function currentUrlMatchesRegexp(urlRegexp: RegExp) {
6+
return urlRegexp.test(currentUrl());
7+
}

src/components/registrators/NavigateToUrlWrapper.tsx

Lines changed: 0 additions & 26 deletions
This file was deleted.

src/components/registrators/registrators.tsx

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,18 @@
11
import * as React from 'react';
22
import { Registry } from '..';
3-
import { NavigateToUrlWrapper } from './NavigateToUrlWrapper';
3+
import { MiniAppUrlsSelection } from '../miniapp/MiniAppUrlsSelection';
44

5-
export function createRegistratorForMiniApp(initialUrl: string, urlRegexp: RegExp, miniApp: React.ComponentType) {
5+
export function createRegistratorForMiniApp(name: string,
6+
urlRegexp: RegExp,
7+
urlsByLabel: { [label: string]: string },
8+
miniApp: React.ComponentType) {
69
return function miniAppRegistrator(registry: Registry) {
7-
registry.add(initialUrl, () => (
8-
<NavigateToUrlWrapper
9-
initialUrl={initialUrl}
10+
registry.add(name, () => (
11+
<MiniAppUrlsSelection
12+
urlsByLabel={urlsByLabel}
1013
urlRegexp={urlRegexp}
1114
component={miniApp}
12-
/>)
13-
);
15+
/>));
1416
};
1517
}
1618

src/components/registry/Registry.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,12 @@ class Registry {
4848
return this.register(name, SingleItemLayout, createRegistratorForSingle(name, singleComponent));
4949
}
5050

51-
registerAsMiniApp(name: string, initialUrl: string, urlRegexp: RegExp, appComponent: React.ComponentType) {
51+
registerAsMiniApp(name: string,
52+
urlRegexp: RegExp,
53+
urlsByLabel: {[label: string]: string},
54+
appComponent: React.ComponentType) {
5255
return this.register(name, SingleItemLayout,
53-
createRegistratorForMiniApp(initialUrl, urlRegexp, appComponent), urlRegexp);
56+
createRegistratorForMiniApp(name, urlRegexp, urlsByLabel, appComponent), urlRegexp);
5457
}
5558

5659
register(name: string,

src/components/viewer/ComponentViewer.tsx

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,20 +19,19 @@ import { GlobalHotKeysHandler } from '../hotkeys/GlobalHotKeysHandler';
1919

2020
import { HotKeyBoundActions } from '../hotkeys/HotKeyBoundActions';
2121

22-
import { ComponentViewerDropDown } from './ComponentViewerDropDown';
23-
2422
import { ComponentViewerHelp } from './help/ComponentViewerHelp';
2523
import { globalActionDefaultKeys } from './GlobalActions';
2624

2725
import { VisualizedActions } from '../actions/VisualizedActions';
2826

29-
import './ComponentViewer.css';
27+
import { labelToKey } from './dropdown/labelUtils';
28+
import { DropDowns } from './dropdown/DropDowns';
3029

31-
import { labelToKey } from './toolbar/labelUtils';
30+
import './ComponentViewer.css';
3231

3332
export interface Props {
3433
registries: Registries;
35-
dropDowns: ComponentViewerDropDown[];
34+
dropDowns: DropDowns;
3635
}
3736

3837
class ComponentViewer extends Component<Props, ComponentViewerState> {
@@ -67,7 +66,7 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
6766
const registry = this.findSelectedRegistry();
6867
const demoEntry = registry ? registry.findDemoByName(demoName) : null;
6968

70-
const rendered = demoEntry && (demoEntry.isMiniApp() || isFullScreen) ?
69+
const rendered = demoEntry && isFullScreen ?
7170
this.renderDemo(demoEntry, true) :
7271
this.renderSelectionPanelAndDemo(demoEntry);
7372

@@ -173,33 +172,23 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
173172

174173
triggerDropDownSelection() {
175174
const {dropDowns} = this.props;
176-
if (dropDowns.length === 0) {
175+
if (dropDowns.isEmpty()) {
177176
return;
178177
}
179178

180179
const {selectedToolbarItems} = this.state;
181180
Object.keys(selectedToolbarItems).forEach(dropDownKey => {
182-
const dropDown = dropDownByLabelKey(dropDownKey);
183-
const itemKey = selectedToolbarItems[dropDownKey];
181+
const dropDown = dropDowns.findDropDownByLabelKey(dropDownKey);
184182
if (!dropDown) {
185183
return;
186184
}
187185

188-
const itemLabel = dropItemLabelByKey();
189-
if (itemLabel) {
190-
dropDown.onSelect(itemLabel);
191-
}
192-
193-
function dropItemLabelByKey() {
194-
const found = dropDown!.items.filter(item => labelToKey(item.label) === itemKey);
195-
return found.length > 0 ? found[0].label : undefined;
186+
const itemKey = selectedToolbarItems[dropDownKey];
187+
const item = dropDown.findItemByLabelKey(itemKey);
188+
if (item) {
189+
dropDown.triggerSelectHandler(item.label);
196190
}
197191
});
198-
199-
function dropDownByLabelKey(labelKey: string) {
200-
const found = dropDowns.filter(dd => labelToKey(dd.label) === labelKey);
201-
return found.length ? found[0] : undefined;
202-
}
203192
}
204193

205194
componentWillUnmount() {
@@ -210,11 +199,11 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
210199
const result: HotKeyBoundActions = {};
211200

212201
const {dropDowns} = this.props;
213-
if (dropDowns.length === 0) {
202+
if (dropDowns.isEmpty()) {
214203
return result;
215204
}
216205

217-
dropDowns.forEach(dropDown =>
206+
dropDowns.list.forEach(dropDown =>
218207
dropDown.items
219208
.filter(item => !!item.hotKey)
220209
.forEach(item => result[item.hotKey!] =
@@ -232,11 +221,11 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
232221
}
233222

234223
private onFullScreenToggle = () => {
235-
this.pushUrl({isFullScreen: !this.state.isFullScreen});
224+
this.pushUrl({partialState: {isFullScreen: !this.state.isFullScreen}});
236225
}
237226

238227
private onQuestionMarkToggle = () => {
239-
this.pushUrl({isHelpOn: !this.state.isHelpOn});
228+
this.pushUrl({partialState: {isHelpOn: !this.state.isHelpOn}});
240229
}
241230

242231
private onNextDemo = () => {
@@ -291,35 +280,35 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
291280
}
292281

293282
private selectRegistry = (registryName: string) => {
294-
this.pushUrl({
283+
this.pushUrl({partialState: {
295284
registryName,
296285
demoName: '',
297286
entryTitle: ''
298-
});
287+
}, clearPath: true});
299288
}
300289

301290
private selectDemo = (demoName: string) => {
302-
this.pushUrl({demoName, entryTitle: ''});
291+
this.pushUrl({partialState: {demoName, entryTitle: ''}, clearPath: true});
303292
}
304293

305294
private selectInstanceByTitle = (title: string) => {
306-
this.pushUrl({entryTitle: title});
295+
this.pushUrl({partialState: {entryTitle: title}, clearPath: true});
307296
}
308297

309298
private selectToolbarItem = (dropDownLabel: string, itemLabel: string) => {
310299
const {dropDowns} = this.props;
311300
const {selectedToolbarItems} = this.state;
312301

313-
this.pushUrl({
302+
this.pushUrl({partialState: {
314303
selectedToolbarItems: {
315304
...selectedToolbarItems,
316305
[labelToKey(dropDownLabel)]: labelToKey(itemLabel)
317306
}
318-
});
307+
}});
319308

320-
const found = dropDowns.filter(dd => dd.label === dropDownLabel);
321-
if (found.length > 0) {
322-
found[0].onSelect(itemLabel);
309+
const found = dropDowns.findDropDownByLabel(dropDownLabel);
310+
if (found) {
311+
found.triggerSelectHandler(itemLabel);
323312
}
324313
}
325314

@@ -339,10 +328,10 @@ class ComponentViewer extends Component<Props, ComponentViewerState> {
339328
[];
340329
}
341330

342-
private pushUrl(newState: Partial<ComponentViewerState>) {
343-
const fullState = {...this.state, ...newState};
331+
private pushUrl({partialState, clearPath}: {partialState: Partial<ComponentViewerState>, clearPath?: boolean}) {
332+
const fullState = {...this.state, ...partialState};
344333
const searchParams = this.stateCreator.buildUrlSearchParams({...fullState, filterText: ''});
345-
const newUrl = '?' + searchParams;
334+
const newUrl = (clearPath ? '/' : '' ) + '?' + searchParams;
346335

347336
window.history.pushState({}, '', newUrl);
348337
this.updateStateFromUrl();

src/components/viewer/ComponentViewerDropDown.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export interface ComponentViewerDropDown {
44
label: string;
55
items: ToolbarDropDownItem[];
66
onSelect(label: string): void;
7+
isSelected?(): boolean;
78
}

src/components/viewer/ComponentViewerStateCreator.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ export class ComponentViewerStateCreator {
3434

3535
const selectedToolbarItems = extractSelectedToolbarItems();
3636

37+
const fullScreenValue = searchParams.get(queryParamNames.isFullScreen) || 'false';
38+
const isFullScreen = fullScreenValue === 'true';
39+
3740
const miniAppByUrl = this.miniAppByUrl(path + '?' + search);
3841
if (miniAppByUrl) {
3942
return {
4043
registryName: miniAppByUrl.registry.name,
4144
demoName: miniAppByUrl.demoEntry.name,
4245
entryTitle: miniAppByUrl.demoEntry.firstEntryTitle,
43-
isFullScreen: true,
46+
isFullScreen,
4447
isHelpOn: false,
4548
filterText: '',
4649
selectedToolbarItems
@@ -56,9 +59,6 @@ export class ComponentViewerStateCreator {
5659
const entryTitle = searchParams.get(queryParamNames.entryTitle) ||
5760
ComponentViewerStateCreator.firstTitleByDemoName(registry, demoName);
5861

59-
const fullScreenValue = searchParams.get(queryParamNames.isFullScreen) || 'false';
60-
const isFullScreen = fullScreenValue === 'true';
61-
6262
const helpOnValue = searchParams.get(queryParamNames.isHelpOn) || 'false';
6363
const isHelpOn = helpOnValue === 'true';
6464

0 commit comments

Comments
 (0)