-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
split platform-dock-layout #683
Merged
Merged
Changes from 7 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
ba6a0ad
split platform-dock-layout
Sebastian-ubs 6fd9ef7
remove cyclic and rename files
Sebastian-ubs 11d2768
split util code only between storage and positioning
Sebastian-ubs 0a3f36c
replace LegacyRef, move types, clean imports, onLayoutChange > inner …
Sebastian-ubs ea94841
fix types
Sebastian-ubs 3502948
storybook: add platform-dock-layout, use subfolders
Sebastian-ubs 35013ed
merge aec03f742ea6658ff87f9755dfdbf86c6a0128d1
Sebastian-ubs 6914dd1
change folder name, re-add ref-selector
Sebastian-ubs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
File renamed without changes.
46 changes: 46 additions & 0 deletions
46
src/renderer/components/docking/dock-layout-wrapper.component.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import 'rc-dock/dist/rc-dock.css'; | ||
import './dock-layout-wrapper.component.scss'; | ||
|
||
import { CSSProperties, ForwardedRef, PropsWithChildren, forwardRef } from 'react'; | ||
import DockLayout, { LayoutProps, LayoutData, LayoutBase } from 'rc-dock'; | ||
|
||
import { SavedTabInfo } from '@shared/models/docking-framework.model'; | ||
|
||
import { RCDockTabInfo } from './docking-framework-internal.model'; | ||
import { GROUPS } from './platform-dock-layout-positioning.util'; | ||
|
||
export type DockLayoutWrapperProps = PropsWithChildren<{ | ||
loadTab: (savedTabInfo: SavedTabInfo) => RCDockTabInfo; | ||
saveTab: (dockTabInfo: RCDockTabInfo) => SavedTabInfo | undefined; | ||
onLayoutChange: LayoutProps['onLayoutChange']; | ||
defaultLayout?: LayoutBase; | ||
style?: CSSProperties; | ||
}>; | ||
|
||
const DockLayoutWrapper = forwardRef(function DockLayoutWrapper( | ||
{ loadTab, saveTab, onLayoutChange, defaultLayout, style }: DockLayoutWrapperProps, | ||
ref: ForwardedRef<DockLayout> | undefined, | ||
) { | ||
return ( | ||
<DockLayout | ||
ref={ref} | ||
groups={GROUPS} | ||
// DockLayout requires LayoutData, but it needs to be LayoutBase in case we use loadTab | ||
/* eslint-disable no-type-assertion/no-type-assertion */ | ||
defaultLayout={ | ||
(defaultLayout as LayoutData) || { dockbox: { mode: 'horizontal', children: [] } } | ||
} | ||
style={style} | ||
dropMode="edge" | ||
loadTab={loadTab} | ||
// Type assert `saveTab` as not returning `undefined` because rc-dock's types are wrong | ||
// Here, if `saveTab` returns `undefined` the tab is not saved | ||
// https://github.com/ticlo/rc-dock/blob/8b6481dca4b4dd07f89107d6f48b1831bbdf0470/src/Serializer.ts#L68 | ||
// eslint-disable-next-line no-type-assertion/no-type-assertion | ||
saveTab={saveTab as (dockTabInfo: RCDockTabInfo) => SavedTabInfo} | ||
onLayoutChange={onLayoutChange} | ||
/> | ||
); | ||
}); | ||
|
||
export default DockLayoutWrapper; |
19 changes: 19 additions & 0 deletions
19
src/renderer/components/docking/docking-framework-internal.model.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { TabData, PanelData, BoxData } from 'rc-dock'; | ||
import { TabInfo } from '@shared/models/docking-framework.model'; | ||
|
||
export type TabType = string; | ||
|
||
export type RCDockTabInfo = TabData & TabInfo; | ||
|
||
/** | ||
* Check if the input item is just a tab, i.e. not a panel, box, or float. | ||
* | ||
* @param tab To check. | ||
* @returns `true` if its a tab or `false` otherwise. | ||
*/ | ||
export function isTab(tab: PanelData | TabData | BoxData | undefined): tab is TabData { | ||
// Assert the more specific type. Null to work with the external API. | ||
// eslint-disable-next-line no-type-assertion/no-type-assertion, no-null/no-null | ||
if (!tab || (tab as TabData).title == null) return false; | ||
return true; | ||
} |
62 changes: 62 additions & 0 deletions
62
src/renderer/components/docking/platform-dock-layout-positioning.util.tests.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* eslint-disable import/first */ | ||
jest.mock('../../../shared/services/logger.service'); | ||
|
||
import { FloatPosition } from 'rc-dock'; | ||
import { FloatLayout } from '@shared/models/docking-framework.model'; | ||
import { getFloatPosition } from './platform-dock-layout-positioning.util'; | ||
/* eslint-enable */ | ||
|
||
describe('Dock Layout Component', () => { | ||
describe('getFloatPosition()', () => { | ||
it('should cascade from top-left of layout', () => { | ||
const layout: FloatLayout = { type: 'float', floatSize: { width: 20, height: 10 } }; | ||
const floatPosition: FloatPosition = { left: 0, top: 0, width: 0, height: 0 }; | ||
|
||
let nextPosition = getFloatPosition(layout, floatPosition, { width: 100, height: 100 }); | ||
|
||
expect(nextPosition).toEqual({ | ||
left: 28, | ||
top: 28, | ||
width: 20, | ||
height: 10, | ||
}); | ||
|
||
nextPosition = getFloatPosition(layout, nextPosition, { width: 100, height: 100 }); | ||
|
||
expect(nextPosition).toEqual({ | ||
left: 2 * 28, | ||
top: 2 * 28, | ||
width: 20, | ||
height: 10, | ||
}); | ||
}); | ||
|
||
it('should overflow right of layout', () => { | ||
const layout: FloatLayout = { type: 'float', floatSize: { width: 20, height: 10 } }; | ||
const floatPosition: FloatPosition = { left: 2 * 28, top: 2 * 28, width: 0, height: 0 }; | ||
// right = 2*28 + 20 + 28 = 104 | ||
// bottom = 2*28 + 10 + 28 = 94 | ||
|
||
expect(getFloatPosition(layout, floatPosition, { width: 100, height: 100 })).toEqual({ | ||
left: 28, | ||
top: 3 * 28, | ||
width: 20, | ||
height: 10, | ||
}); | ||
}); | ||
|
||
it('should overflow bottom of layout', () => { | ||
const layout: FloatLayout = { type: 'float', floatSize: { width: 20, height: 10 } }; | ||
const floatPosition: FloatPosition = { left: 2 * 28, top: 2 * 28, width: 0, height: 0 }; | ||
// right = 2*28 + 20 + 28 = 104 | ||
// bottom = 2*28 + 10 + 28 = 94 | ||
|
||
expect(getFloatPosition(layout, floatPosition, { width: 120, height: 90 })).toEqual({ | ||
left: 3 * 28, | ||
top: 28, | ||
width: 20, | ||
height: 10, | ||
}); | ||
}); | ||
}); | ||
}); |
115 changes: 115 additions & 0 deletions
115
src/renderer/components/docking/platform-dock-layout-positioning.util.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
import { FloatPosition, FloatSize, LayoutSize, TabGroup } from 'rc-dock'; | ||
import cloneDeep from 'lodash/cloneDeep'; | ||
import { | ||
PanelDirection, | ||
Layout, | ||
SavedTabInfo, | ||
FloatLayout, | ||
} from '@shared/models/docking-framework.model'; | ||
import DIALOGS from '@renderer/components/dialogs'; | ||
import { TabType } from './docking-framework-internal.model'; | ||
|
||
/** | ||
* The default initial size for floating tabs in CSS `px` units. Can be overridden by tabTypes' | ||
* initial sizes | ||
*/ | ||
const DEFAULT_FLOAT_SIZE: FloatSize = { width: 300, height: 150 }; | ||
/** Default direction a tab will be placed from an existing tab if created as a panel */ | ||
const DEFAULT_PANEL_DIRECTION: PanelDirection = 'right'; | ||
|
||
const DOCK_FLOAT_OFFSET = 28; | ||
// NOTE: 'card' is a built-in style. We can likely remove it when we create a full theme for | ||
// Platform. | ||
export const TAB_GROUP = 'card platform-bible'; | ||
|
||
export const GROUPS: { [key: string]: TabGroup } = { | ||
[TAB_GROUP]: { | ||
maximizable: true, // Allow groups of tabs to be maximized | ||
floatable: true, // Allow tabs to be floated | ||
animated: false, // Don't animate tab transitions | ||
// TODO: Currently allowing newWindow crashes since electron doesn't seem to have window.open defined? | ||
// newWindow: true, // Allow floating windows to show in a native window | ||
}, | ||
}; | ||
|
||
/** Initial sizes for each tab in CSS `px` units if created as floating tabs */ | ||
const tabInitialFloatingSize: Record<TabType, FloatSize> = Object.fromEntries( | ||
Object.entries(DIALOGS).map( | ||
([dialogTabType, dialogDefinition]) => [dialogTabType, dialogDefinition.initialSize] as const, | ||
), | ||
); | ||
|
||
function offsetOrOverflowAxis( | ||
axis: number, | ||
size: number, | ||
max: number, | ||
offset = DOCK_FLOAT_OFFSET, | ||
): number { | ||
if (axis + size + offset >= max) return offset; | ||
return axis + offset; | ||
} | ||
|
||
/** | ||
* Get left & top so float windows cascade their position. Float window should not overflow the | ||
* layout but start cascading again. | ||
* | ||
* @param layout Specified by the WebView. Must have all values - this function assumes this layout | ||
* has had default values set already | ||
* @param previousPosition Used with the previous float window. | ||
* @param layoutSize Of the whole dock layout. | ||
* @returns Cascaded position. | ||
*/ | ||
export function getFloatPosition( | ||
layout: FloatLayout, | ||
previousPosition: FloatPosition, | ||
layoutSize: LayoutSize, | ||
): FloatPosition { | ||
// Defaults are added in `layoutDefaults`. | ||
// eslint-disable-next-line no-type-assertion/no-type-assertion | ||
const { width, height } = layout.floatSize!; | ||
|
||
let { left, top } = previousPosition; | ||
|
||
switch (layout.position) { | ||
case 'center': | ||
left = layoutSize.width / 2 - width / 2; | ||
top = layoutSize.height / 2 - height / 2; | ||
break; | ||
case 'cascade': | ||
default: | ||
left = offsetOrOverflowAxis(left, width, layoutSize.width); | ||
top = offsetOrOverflowAxis(top, height, layoutSize.height); | ||
break; | ||
} | ||
return { left, top, width, height }; | ||
} | ||
|
||
/** Set up defaults for webview layout instructions */ | ||
export function layoutDefaults(layout: Layout, savedTabInfo: SavedTabInfo): Layout { | ||
const layoutDefaulted = cloneDeep(layout); | ||
switch (layoutDefaulted.type) { | ||
case 'float': { | ||
if (!layoutDefaulted.floatSize) { | ||
layoutDefaulted.floatSize = | ||
tabInitialFloatingSize[savedTabInfo.tabType] || DEFAULT_FLOAT_SIZE; | ||
} else { | ||
if (!layoutDefaulted.floatSize.width || layoutDefaulted.floatSize.width <= 0) | ||
layoutDefaulted.floatSize.width = | ||
tabInitialFloatingSize[savedTabInfo.tabType]?.width || DEFAULT_FLOAT_SIZE.width; | ||
|
||
if (!layoutDefaulted.floatSize.height || layoutDefaulted.floatSize.height <= 0) | ||
layoutDefaulted.floatSize.height = | ||
tabInitialFloatingSize[savedTabInfo.tabType]?.height || DEFAULT_FLOAT_SIZE.height; | ||
} | ||
|
||
break; | ||
} | ||
case 'panel': | ||
if (!layoutDefaulted.direction) layoutDefaulted.direction = DEFAULT_PANEL_DIRECTION; | ||
break; | ||
case 'tab': | ||
default: | ||
// do nothing | ||
} | ||
return layoutDefaulted; | ||
} |
62 changes: 2 additions & 60 deletions
62
...ng/platform-dock-layout.component.test.ts → ...platform-dock-layout-storage.util.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tjcouch-sil: Is this correct? At least it renders :-)