Skip to content

Commit

Permalink
Minor conductor changes, lint fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
gius committed Oct 31, 2021
1 parent 83fd69e commit 9954636
Show file tree
Hide file tree
Showing 27 changed files with 136 additions and 121 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"build": "lerna run build",
"test": "jest",
"storybook": "yarn --cwd stories start",
"lint": "eslint \"./{packages,examples}/**/*.{ts,tsx}\" --cache",
"lint": "eslint \"./{packages,stories}/**/*.{ts,tsx}\" --cache",
"validate": "yarn run lint && yarn run cleanbuild && yarn run test && yarn run publish",
"lernaupdate": "lernaupdate",
"deps:outdated": "yarn outdated & lerna exec --stream --no-bail -- \"copy package.json package.bak && findstr /v \"@frui.ts/\" package.bak > package.json & yarn install & npx yarn-deduplicate yarn.lock & yarn outdated & move /Y package.bak package.json\"",
Expand Down
4 changes: 2 additions & 2 deletions packages/screens/__tests__/router/urlRouterBase.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe("UrlRouterBase", () => {

await router.initialize();

expect(router.persistedPath).toBe("my-screen");
expect(router.persistedPath).toBe("/my-screen");
});
});

Expand All @@ -32,7 +32,7 @@ describe("UrlRouterBase", () => {

const router = new TestRouter(navigator);

await router.navigate("my-screen");
await router.navigate("/my-screen");

expect(navigator.navigate).toBeCalledWith([{ name: "my-screen" }]);
});
Expand Down
2 changes: 1 addition & 1 deletion packages/screens/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export { default as Router } from "./router/router";
export { default as RouterBase } from "./router/routerBase";
export { default as UrlRouterBase } from "./router/urlRouterBase";

export { default as BusyWatcher, BusyWatcherKey, IBusyWatcher } from "./busyWatcher";
export { default as BusyWatcher, BusyWatcherKey, IBusyWatcher, watchBusy } from "./busyWatcher";
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import LifecycleScreenNavigatorBase from "../lifecycleScreenNavigatorBase";
import type { LifecycleScreenNavigator, ScreenNavigator } from "../types";

export default class ActiveChildConductor<
TScreen = unknown,
TChild = unknown,
TScreen = any,
TNavigationParams extends Record<string, string> = Record<string, string>
> extends LifecycleScreenNavigatorBase<TScreen, TNavigationParams> {
@observable.ref private activeChildValue?: TChild = undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import LifecycleScreenNavigatorBase from "../lifecycleScreenNavigatorBase";
import type ScreenLifecycleEventHub from "../screenLifecycleEventHub";

export default class AllChildrenActiveConductor<
TScreen = unknown,
TChild = unknown,
TScreen = any,
TNavigationParams extends Record<string, string> = Record<string, string>
> extends LifecycleScreenNavigatorBase<TScreen, TNavigationParams> {
readonly children: TChild[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import type { LifecycleScreenNavigator } from "../types";
import ActiveChildConductor from "./activeChildConductor";

export default class OneOfListActiveConductor<
TScreen = unknown,
TChild = unknown,
TScreen = any,
TNavigationParams extends Record<string, string> = Record<string, string>
> extends ActiveChildConductor<TScreen, TChild, TNavigationParams> {
> extends ActiveChildConductor<TChild, TScreen, TNavigationParams> {
readonly children: TChild[];

/** When set to `true`, navigating directly to the conductor (with no child path specified) activates the previously set `activeChild`. */
Expand Down
5 changes: 5 additions & 0 deletions packages/screens/src/router/routerBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,9 @@ export default abstract class RouterBase {

return path;
}

protected cloneWithChildPath(path: PathElement[], child: ScreenNavigator | undefined) {
const childPath = child?.getNavigationState();
return childPath ? [...path, childPath] : path;
}
}
17 changes: 15 additions & 2 deletions packages/screens/src/router/urlRouterBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ export default abstract class UrlRouterBase extends RouterBase implements Router
// TODO unwrap path if alias for a route

const elements: PathElement[] =
typeof path === "string" ? path.split(URL_SEPARATOR).map(x => this.deserializePath(x) ?? { name: "parse-error" }) : path;
typeof path === "string"
? path
.split(URL_SEPARATOR)
.filter(x => x)
.map(x => this.deserializePath(x) ?? { name: "parse-error" })
: path;
await this.rootNavigator?.navigate(elements);

const currentPath = this.getCurrentPath();
Expand Down Expand Up @@ -92,6 +97,14 @@ export default abstract class UrlRouterBase extends RouterBase implements Router
return this.serializePath(path);
}

getUrlFactoryForChild(parent: ScreenBase) {
const rootPath = this.getPathForChild(parent.navigator, undefined);
return (child: ScreenBase) => {
const path = this.cloneWithChildPath(rootPath, child.navigator);
return this.serializePath(path);
};
}

getUrlForRoute(routeName: RouteName, params?: any) {
const route = this.routes.get(routeName);
if (route) {
Expand All @@ -101,7 +114,7 @@ export default abstract class UrlRouterBase extends RouterBase implements Router
}

protected serializePath(pathElements: PathElement[]): string {
return pathElements.map(x => this.serializePathElement(x)).join(URL_SEPARATOR);
return URL_SEPARATOR + pathElements.map(x => this.serializePathElement(x)).join(URL_SEPARATOR);
}

protected serializePathElement(element: PathElement): string {
Expand Down
6 changes: 3 additions & 3 deletions packages/views/src/view.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import type { ScreenBase } from "@frui.ts/screens";
import React from "react";
import type { ErrorBoundaryProps } from "./errorBoundary";
import ErrorBoundary from "./errorBoundary";
import useScreenLifecycle from "./useScreenLifecycle";
import { getView, tryGetView } from "./viewLocator";

interface ViewProps {
vm?: ScreenBase;
vm?: unknown;
context?: string;
useLifecycle?: boolean;
}
Expand All @@ -18,7 +17,8 @@ const PureView: React.FunctionComponent<ViewProps> = props => {
return <React.Fragment>{children}</React.Fragment>;
}

const FoundView = children === undefined ? getView(vm.constructor, context) : tryGetView(vm.constructor, context);
const vmConstructor = (vm as Record<string, any>).constructor;
const FoundView = children === undefined ? getView(vmConstructor, context) : tryGetView(vmConstructor, context);

if (!FoundView) {
return <React.Fragment>{children}</React.Fragment>;
Expand Down
3 changes: 2 additions & 1 deletion stories/src/bootstrap.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import "!style-loader!css-loader!bootstrap/dist/css/bootstrap.css";
import { Check, Input, Select } from "@frui.ts/bootstrap";
import { attachAutomaticDirtyWatcher } from "@frui.ts/dirtycheck";
import { attachAutomaticValidator, Configuration, EntityValidationRules } from "@frui.ts/validation";
import type { EntityValidationRules } from "@frui.ts/validation";
import { attachAutomaticValidator, Configuration } from "@frui.ts/validation";
import { storiesOf } from "@storybook/react";
import { action, observable } from "mobx";
import { Observer } from "mobx-react-lite";
Expand Down
3 changes: 2 additions & 1 deletion stories/src/controls/formField.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { getDirtyWatcher } from "@frui.ts/dirtycheck";
import { getValidationMessage } from "@frui.ts/validation";
import { getInnerComponent, IFormFieldProps } from "@frui.ts/views";
import type { IFormFieldProps } from "@frui.ts/views";
import { getInnerComponent } from "@frui.ts/views";
import { observer } from "mobx-react-lite";
import React from "react";

Expand Down
4 changes: 2 additions & 2 deletions stories/src/navigation.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ScreenNavigator } from "@frui.ts/screens";
import type { ScreenNavigator } from "@frui.ts/screens";
import { preventDefault, View } from "@frui.ts/views";
import { storiesOf } from "@storybook/react";
import { action } from "mobx";
Expand Down Expand Up @@ -41,7 +41,7 @@ storiesOf("Navigation", module).add("Path", () => {
<form onSubmit={preventDefault(() => router.current.navigate(router.current.currentPath))}>
URL:
<input
value={router.current.currentPath ?? "uninitialized"}
value={router.current.currentPath}
onChange={action(e => (router.current.currentPath = e.currentTarget.value))}
/>
<button type="submit">Go</button>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Check, Input } from "@frui.ts/bootstrap";
import { AutomaticEntityValidator, Configuration, EntityValidationRules, ValidationResult } from "@frui.ts/validation";
import type { EntityValidationRules, ValidationResult } from "@frui.ts/validation";
import { AutomaticEntityValidator, Configuration } from "@frui.ts/validation";
import { storiesOf } from "@storybook/react";
import { action, observable } from "mobx";
import { Observer } from "mobx-react-lite";
Expand Down
3 changes: 2 additions & 1 deletion stories/src/validation/automaticEntityValidator.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Check, Input } from "@frui.ts/bootstrap";
import { AutomaticEntityValidator, Configuration, EntityValidationRules, ValidationResult } from "@frui.ts/validation";
import type { EntityValidationRules, ValidationResult } from "@frui.ts/validation";
import { AutomaticEntityValidator, Configuration } from "@frui.ts/validation";
import { storiesOf } from "@storybook/react";
import { action, observable } from "mobx";
import { Observer } from "mobx-react-lite";
Expand Down
5 changes: 3 additions & 2 deletions stories/src/validation/validationErrors.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { observer } from "mobx-react-lite";
import { EntityValidator } from "@frui.ts/validation";
import type { EntityValidator } from "@frui.ts/validation";
import React from "react";

function validationErrors({ validator, property }: { validator: EntityValidator<any>; property: string }) {
Expand All @@ -8,7 +8,8 @@ function validationErrors({ validator, property }: { validator: EntityValidator<
<ul>
{results.map(result => (
<li key={result.code}>
<strong>{property}</strong>:{" "}
<strong>{property}</strong>
{/* eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing */}
<span style={{ color: result.isValid ? "green" : "red" }}>{result.message || result.code}</span>
</li>
))}
Expand Down
2 changes: 1 addition & 1 deletion stories/src/validation/validityIndicator.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EntityValidator } from "@frui.ts/validation";
import type { EntityValidator } from "@frui.ts/validation";
import { observer } from "mobx-react-lite";
import React from "react";

Expand Down
9 changes: 5 additions & 4 deletions stories/src/viewModels/allChildrenActiveViewModel.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { AllChildrenActiveConductor, ScreenBase } from "@frui.ts/screens";
import { action } from "mobx";
import ChildViewModel from "./childViewModel";
import { IChildScreen } from "./types";
import type { IChildScreen } from "./types";

export default class AllChildrenActiveViewModel
extends ScreenBase<AllChildrenActiveConductor<AllChildrenActiveViewModel, ChildViewModel>>
implements IChildScreen {
extends ScreenBase<AllChildrenActiveConductor<ChildViewModel>>
implements IChildScreen
{
name = "All Active";

private childCounter = 1;

constructor() {
super();
this.navigator = new AllChildrenActiveConductor<AllChildrenActiveViewModel, ChildViewModel>(this);
this.navigator = new AllChildrenActiveConductor<ChildViewModel>(this);
this.navigator.navigationName = "all";
}

Expand Down
9 changes: 5 additions & 4 deletions stories/src/viewModels/oneChildActiveViewModel.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { OneOfListActiveConductor, ScreenBase } from "@frui.ts/screens";
import { action } from "mobx";
import ChildViewModel from "./childViewModel";
import { IChildScreen } from "./types";
import type { IChildScreen } from "./types";

export default class OneChildActiveViewModel
extends ScreenBase<OneOfListActiveConductor<OneChildActiveViewModel, ChildViewModel>>
implements IChildScreen {
extends ScreenBase<OneOfListActiveConductor<ChildViewModel>>
implements IChildScreen
{
name = "One Active";

private childCounter = 1;

constructor() {
super();
this.navigator = new OneOfListActiveConductor<OneChildActiveViewModel, ChildViewModel>(this);
this.navigator = new OneOfListActiveConductor<ChildViewModel>(this);
this.navigator.navigationName = "one";
this.navigator.preserveActiveChild = true;
}
Expand Down
6 changes: 3 additions & 3 deletions stories/src/viewModels/rootViewModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { OneOfListActiveConductor, ScreenBase } from "@frui.ts/screens";
import AllChildrenActiveViewModel from "./allChildrenActiveViewModel";
import OneChildActiveViewModel from "./oneChildActiveViewModel";
import SingleChildViewModel from "./singleChildViewModel";
import { IChildScreen } from "./types";
import type { IChildScreen } from "./types";

export default class RootViewModel extends ScreenBase<OneOfListActiveConductor<RootViewModel, IChildScreen>> {
export default class RootViewModel extends ScreenBase<OneOfListActiveConductor<IChildScreen>> {
name = "My Root View Model";

constructor() {
super();

this.navigator = new OneOfListActiveConductor<RootViewModel, IChildScreen>(this);
this.navigator = new OneOfListActiveConductor<IChildScreen>(this);
this.navigator.navigationName = "root";
this.navigator.children.push(new AllChildrenActiveViewModel(), new OneChildActiveViewModel(), new SingleChildViewModel());
}
Expand Down
4 changes: 2 additions & 2 deletions stories/src/viewModels/router.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import TestRouter from "./testRouter";
import type TestRouter from "./testRouter";

const router = { current: (undefined as unknown) as TestRouter };
const router = { current: undefined as unknown as TestRouter };

export default router;
10 changes: 4 additions & 6 deletions stories/src/viewModels/singleChildViewModel.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import { ActiveChildConductor, ScreenBase } from "@frui.ts/screens";
import ChildViewModel from "./childViewModel";
import { IChildScreen } from "./types";
import type { IChildScreen } from "./types";

export default class SingleChildViewModel
extends ScreenBase<ActiveChildConductor<SingleChildViewModel, ChildViewModel>>
implements IChildScreen {
export default class SingleChildViewModel extends ScreenBase<ActiveChildConductor<ChildViewModel>> implements IChildScreen {
name = "Single active";

constructor() {
super();
this.navigator = new ActiveChildConductor<SingleChildViewModel, ChildViewModel>(this);
this.navigator = new ActiveChildConductor<ChildViewModel>(this);
this.navigator.navigationName = "single";
this.navigator.findNavigationChild = this.findNavigationChild;
}

private findNavigationChild: SingleChildViewModel["navigator"]["findNavigationChild"] = context => {
const childPathElement = context.path[1];
const childPathElement = context.path.length > 1 && context.path[1];
if (childPathElement) {
if (childPathElement.name === this.navigator.activeChild?.navigator.navigationName) {
return Promise.resolve({
Expand Down
2 changes: 1 addition & 1 deletion stories/src/viewModels/testRouter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { UrlRouterBase } from "@frui.ts/screens";
import { action, observable } from "mobx";
import { MouseEvent, MouseEventHandler } from "react";
import type { MouseEvent, MouseEventHandler } from "react";

export default class TestRouter extends UrlRouterBase {
@observable
Expand Down
2 changes: 1 addition & 1 deletion stories/src/viewModels/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ScreenBase } from "@frui.ts/screens";
import type { ScreenBase } from "@frui.ts/screens";

export interface IChildScreen extends ScreenBase {
name: string;
Expand Down
34 changes: 16 additions & 18 deletions stories/src/views/allChildrenActiveView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,21 @@ import { observer, Observer } from "mobx-react-lite";
import React from "react";
import AllChildrenActiveViewModel from "../viewModels/allChildrenActiveViewModel";

const allChildrenActiveView: React.FunctionComponent<{ vm: AllChildrenActiveViewModel }> = observer(({ vm }) =>
!vm ? null : (
<div>
Child view models: &nbsp;
<button onClick={vm.addChild}>+</button>
<br />
<Observer>
{() => (
<React.Fragment>
{vm.navigator.children.map(x => (
<View key={x.navigator.navigationName} vm={x} />
))}
</React.Fragment>
)}
</Observer>
</div>
)
);
const allChildrenActiveView: React.FunctionComponent<{ vm: AllChildrenActiveViewModel }> = observer(({ vm }) => (
<div>
Child view models: &nbsp;
<button onClick={vm.addChild}>+</button>
<br />
<Observer>
{() => (
<React.Fragment>
{vm.navigator.children.map(x => (
<View key={x.navigator.navigationName} vm={x} />
))}
</React.Fragment>
)}
</Observer>
</div>
));
registerView(allChildrenActiveView, AllChildrenActiveViewModel);
export default allChildrenActiveView;
18 changes: 8 additions & 10 deletions stories/src/views/childView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@ import React from "react";
import ChildViewModel from "../viewModels/childViewModel";
import router from "../viewModels/router";

const childView: React.FunctionComponent<{ vm: ChildViewModel }> = observer(({ vm }) =>
!vm ? null : (
<p>
{vm.text} &nbsp;
<button title={router.current.getUrlForParent(vm)} onClick={() => router.current.navigateToParent(vm)}>
×
</button>
</p>
)
);
const childView: React.FunctionComponent<{ vm: ChildViewModel }> = observer(({ vm }) => (
<p>
{vm.text} &nbsp;
<button title={router.current.getUrlForParent(vm)} onClick={() => router.current.navigateToParent(vm)}>
×
</button>
</p>
));
registerView(childView, ChildViewModel);
export default childView;
Loading

0 comments on commit 9954636

Please sign in to comment.