Skip to content

Commit

Permalink
feat: more structured code
Browse files Browse the repository at this point in the history
  • Loading branch information
johnwalley committed Apr 10, 2022
1 parent e558c4e commit bc78ac3
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 128 deletions.
55 changes: 32 additions & 23 deletions src/allotment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import classNames from "classnames";
import clamp from "lodash.clamp";
import React, {
forwardRef,
useCallback,
useEffect,
useImperativeHandle,
useLayoutEffect,
Expand All @@ -13,14 +14,10 @@ import useResizeObserver from "use-resize-observer";

import styles from "./allotment.module.css";
import { isIOS } from "./helpers/platform";
import { LayoutService } from "./layout-service";
import { PaneView } from "./pane-view";
import { Orientation, setGlobalSashSize } from "./sash";
import {
LayoutService,
PaneView,
Sizing,
SplitView,
SplitViewOptions,
} from "./split-view/split-view";
import { Sizing, SplitView, SplitViewOptions } from "./split-view";

function isPane(item: React.ReactNode): item is typeof Pane {
return (item as any).type.displayName === "Allotment.Pane";
Expand Down Expand Up @@ -129,9 +126,25 @@ const Allotment = forwardRef<AllotmentHandle, AllotmentProps>(
[children]
);

const resizeToPreferredSize = useCallback((index: number): boolean => {
const view = views.current?.[index];

if (typeof view?.preferredSize !== "number") {
return false;
}

splitViewRef.current?.resizeView(index, Math.round(view.preferredSize));

return true;
}, []);

useImperativeHandle(ref, () => ({
reset: () => {
splitViewRef.current?.distributeViewSizes();

for (let index = 0; index < views.current.length; index++) {
resizeToPreferredSize(index);
}
},
resize: (sizes) => {
splitViewRef.current?.resizeViews(sizes);
Expand Down Expand Up @@ -219,21 +232,6 @@ const Allotment = forwardRef<AllotmentHandle, AllotmentProps>(
if (onReset) {
onReset();
} else {
const resizeToPreferredSize = (index: number): boolean => {
const view = views.current?.[index];

if (typeof view?.preferredSize !== "number") {
return false;
}

splitViewRef.current?.resizeView(
index,
Math.round(view.preferredSize)
);

return true;
};

if (resizeToPreferredSize(index)) {
return;
}
Expand Down Expand Up @@ -324,6 +322,17 @@ const Allotment = forwardRef<AllotmentHandle, AllotmentProps>(
}
}

for (const updateKey of update) {
const props = splitViewPropsRef.current.get(updateKey);
const index = keys.findIndex((key) => key === updateKey);

if (props && isPaneProps(props)) {
if (props.preferredSize !== undefined) {
views.current[index].preferredSize = props.preferredSize;
}
}
}

if (enter.length > 0 || exit.length > 0) {
previousKeys.current = keys;
}
Expand All @@ -335,7 +344,7 @@ const Allotment = forwardRef<AllotmentHandle, AllotmentProps>(
onResize: ({ width, height }) => {
if (width && height) {
splitViewRef.current?.layout(vertical ? height : width);
layoutService.current.layout(vertical ? height : width);
layoutService.current.setSize(vertical ? height : width);
setDimensionsInitialized(true);
}
},
Expand Down
2 changes: 0 additions & 2 deletions src/helpers/platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ if (typeof navigator === "object") {
_userAgent.indexOf("iPhone") >= 0) &&
!!navigator.maxTouchPoints &&
navigator.maxTouchPoints > 0;
} else {
console.error("Unable to resolve platform.");
}

export const isIOS = _isIOS;
Expand Down
1 change: 1 addition & 0 deletions src/layout-service/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./layout-service";
11 changes: 11 additions & 0 deletions src/layout-service/layout-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export class LayoutService {
private _size!: number;

public getSize() {
return this._size;
}

public setSize(size: number) {
this._size = size;
}
}
1 change: 1 addition & 0 deletions src/pane-view/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./pane-view";
135 changes: 135 additions & 0 deletions src/pane-view/pane-view.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { endsWith } from "../helpers/string";
import { LayoutService } from "../layout-service";
import { View } from "../split-view";

export interface Layout {
getPreferredSize: () => number | undefined;
}

export class PixelLayout implements Layout {
private size: number;

constructor(size: number) {
this.size = size;
}

public getPreferredSize() {
return this.size;
}
}

export class ProportionLayout implements Layout {
private proportion: number;
private layoutService: LayoutService;

constructor(proportion: number, layoutService: LayoutService) {
this.proportion = proportion;
this.layoutService = layoutService;
}

public getPreferredSize() {
return this.proportion * this.layoutService.getSize();
}
}

export class NullLayout implements Layout {
public getPreferredSize() {
return undefined;
}
}

export interface PaneViewOptions {
element: HTMLElement;
minimumSize?: number;
maximumSize?: number;
preferredSize?: number | string;
snap?: boolean;
}

export class PaneView implements View {
public minimumSize: number = 0;
public maximumSize: number = Number.POSITIVE_INFINITY;

readonly element: HTMLElement;
readonly snap: boolean;

private layoutService: LayoutService;
private layoutStrategy: Layout;

get preferredSize(): number | undefined {
return this.layoutStrategy.getPreferredSize();
}

set preferredSize(preferredSize: number | string | undefined) {
if (typeof preferredSize === "number") {
this.layoutStrategy = new PixelLayout(preferredSize);
} else if (typeof preferredSize === "string") {
const trimmedPreferredSize = preferredSize.trim();

if (endsWith(trimmedPreferredSize, "%")) {
const proportion = Number(trimmedPreferredSize.slice(0, -1)) / 100;

this.layoutStrategy = new ProportionLayout(
proportion,
this.layoutService
);
} else if (endsWith(trimmedPreferredSize, "px")) {
const pixels = Number(trimmedPreferredSize.slice(0, -2)) / 100;

this.layoutStrategy = new PixelLayout(pixels);
} else if (typeof Number.parseFloat(trimmedPreferredSize) === "number") {
const number = Number.parseFloat(trimmedPreferredSize);

this.layoutStrategy = new PixelLayout(number);
} else {
this.layoutStrategy = new NullLayout();
}
} else {
this.layoutStrategy = new NullLayout();
}
}

constructor(layoutService: LayoutService, options: PaneViewOptions) {
this.layoutService = layoutService;
this.element = options.element;

this.minimumSize =
typeof options.minimumSize === "number" ? options.minimumSize : 30;

this.maximumSize =
typeof options.maximumSize === "number"
? options.maximumSize
: Number.POSITIVE_INFINITY;

if (typeof options.preferredSize === "number") {
this.layoutStrategy = new PixelLayout(options.preferredSize);
} else if (typeof options.preferredSize === "string") {
const preferredSize = options.preferredSize.trim();

if (endsWith(preferredSize, "%")) {
const proportion = Number(preferredSize.slice(0, -1)) / 100;

this.layoutStrategy = new ProportionLayout(
proportion,
this.layoutService
);
} else if (endsWith(preferredSize, "px")) {
const pixels = Number(preferredSize.slice(0, -2)) / 100;

this.layoutStrategy = new PixelLayout(pixels);
} else if (typeof Number.parseFloat(preferredSize) === "number") {
const number = Number.parseFloat(preferredSize);

this.layoutStrategy = new PixelLayout(number);
} else {
this.layoutStrategy = new NullLayout();
}
} else {
this.layoutStrategy = new NullLayout();
}

this.snap = typeof options.snap === "boolean" ? options.snap : false;
}

layout(_size: number): void {}
}
86 changes: 0 additions & 86 deletions src/split-view/split-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,92 +146,6 @@ export interface View {
setVisible?(visible: boolean): void;
}

export class LayoutService {
private _size!: number;

get size() {
return this._size;
}

public layout(size: number) {
this._size = size;
}
}

export interface PaneViewOptions {
element: HTMLElement;
minimumSize?: number;
maximumSize?: number;
preferredSize?: number | string;
snap?: boolean;
}

export class PaneView implements View {
public minimumSize: number = 0;
public maximumSize: number = Number.POSITIVE_INFINITY;

readonly element: HTMLElement;
readonly snap: boolean;

private layoutService: LayoutService;
private _preferredSize: () => number | undefined;

get preferredSize() {
return this._preferredSize();
}

constructor(layoutService: LayoutService, options: PaneViewOptions) {
this.layoutService = layoutService;
this.element = options.element;

this.minimumSize =
typeof options.minimumSize === "number" ? options.minimumSize : 30;

this.maximumSize =
typeof options.maximumSize === "number"
? options.maximumSize
: Number.POSITIVE_INFINITY;

if (typeof options.preferredSize === "number") {
this._preferredSize = () => {
return options.preferredSize as number;
};
} else if (typeof options.preferredSize === "string") {
if (endsWith(options.preferredSize, "%")) {
const percentage = Number(options.preferredSize.slice(0, -1)) / 100;

this._preferredSize = () => {
return percentage * this.layoutService.size;
};
} else if (endsWith(options.preferredSize, "px")) {
const pixels = Number(options.preferredSize.slice(0, -2)) / 100;

this._preferredSize = () => {
return pixels;
};
} else if (Number.parseFloat(options.preferredSize)) {
const number = Number.parseFloat(options.preferredSize);

this._preferredSize = () => {
return number;
};
} else {
this._preferredSize = () => {
return undefined;
};
}
} else {
this._preferredSize = () => {
return undefined;
};
}

this.snap = typeof options.snap === "boolean" ? options.snap : false;
}

layout(_size: number): void {}
}

type ViewItemSize = number | { cachedVisibleSize: number };

abstract class ViewItem {
Expand Down
Loading

0 comments on commit bc78ac3

Please sign in to comment.