Skip to content
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

feat(collapse): collaspe support to specify grow attr #188

Merged
merged 3 commits into from
Jun 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 142 additions & 32 deletions src/components/collapse/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import {
collapseContentClassName,
} from './base';
import { Scrollable } from '../scrollable';
import { select } from 'mo/common/dom';

type RenderFunctionProps = (data: DataBaseProps) => React.ReactNode;

interface DataBaseProps {
id: React.Key;
name: string;
Expand All @@ -25,6 +25,17 @@ interface DataBaseProps {
toolbar?: IActionBarItemProps[];
renderPanel?: RenderFunctionProps;

// detect the collapse panel whether empty
_isEmpty?: boolean;
config?: {
/**
* Specify how much of the remaining space should be assigned to the item, default is 1
*
* It unfolds in its own content height or the `MAX_GROW_HEIGHT` rather than in calculated height
*/
grow?: number;
};

[key: string]: any;
}

Expand All @@ -40,6 +51,10 @@ export interface ICollapseProps {

// default collapse height, only contains header
const HEADER_HEIGTH = 26;
/**
* It's the max height for the item which set the grow to 0
*/
const MAX_GROW_HEIGHT = 220;

export function Collapse(props: ICollapseProps) {
const [activePanelKeys, setActivePanelKeys] = useState<React.Key[]>([]);
Expand All @@ -53,9 +68,13 @@ export function Collapse(props: ICollapseProps) {
...restProps
} = props;

const visibleData = data.filter((d) => !d.hidden);

// assets data must have id
const filterData = data.filter((panel) => panel.id) as DataBaseProps[];
if (filterData.length < data.length) {
const filterData = visibleData.filter(
(panel) => panel.id
) as DataBaseProps[];
if (filterData.length < visibleData.length) {
Logger.warn(new SyntaxError('collapse data must have id'));
}

Expand All @@ -78,7 +97,7 @@ export function Collapse(props: ICollapseProps) {
const isActive = activePanelKeys.includes(panel.id);
let isEmpty = true;
if (isActive) {
const contentDom = document.querySelector(
const contentDom = select(
`.${collapseContentClassName}[data-content='${panel.id}']`
);
isEmpty = !contentDom?.hasChildNodes();
Expand All @@ -90,15 +109,15 @@ export function Collapse(props: ICollapseProps) {
filterData
);
_cachePosition.push([height, top]);
const dom = document.querySelector<HTMLElement>(
const dom = select<HTMLElement>(
`.${collapseItemClassName}[data-content='${panel.id}']`
);
if (dom) {
dom.style.height = `${height}px`;
dom.style.top = `${top}px`;
}
});
}, [activePanelKeys]);
}, [filterData]);

const handleChangeCallback = (key: React.Key) => {
const currentKeys = activePanelKeys.concat();
Expand Down Expand Up @@ -130,6 +149,53 @@ export function Collapse(props: ICollapseProps) {
return null;
};

/**
* Returns the grow of data, or 1
*/
const getGrow = (data: DataBaseProps) => {
if (typeof data.config?.grow === 'number') {
return data.config.grow;
} else {
return 1;
}
};

/**
* Returns the key whose panel is active and whose grow is 0
*/
const getZeroPanelsByKeys = (
keys: React.Key[],
panels: DataBaseProps[]
) => {
return keys.filter((key) => {
const targetPanel = panels.find((panel) => panel.id === key);
if (targetPanel) {
return targetPanel.config?.grow === 0;
}
return false;
});
};

/**
* Returns the collections of height
*/
const getContentHeightsByKeys = (data: React.Key[]) => {
return data.map((key) => {
const contentDom = select(
`.${collapseContentClassName}[data-content='${key}']`
);
if (contentDom) {
// border-top-width + border-bottom-width = 2
const basisHeight =
contentDom.getBoundingClientRect().height -
2 +
HEADER_HEIGTH;
return basisHeight > 220 ? 220 : basisHeight;
}
return 0;
});
};

/**
* Calculate the position of the panel in view
* @param keys Current active keys
Expand All @@ -150,35 +216,79 @@ export function Collapse(props: ICollapseProps) {
// the height of inactive panel or empty panel is a fixed value
res[0] = HEADER_HEIGTH;
} else {
// total height
const wrapperHeight =
wrapper.current?.getBoundingClientRect().height ||
_cacheWrapperHeight.current;
_cacheWrapperHeight.current = wrapperHeight;
// count active panels
const activeCount = keys.length;
// count the height for active panels
const activePanelHeight =
wrapperHeight - HEADER_HEIGTH * (panels.length - activeCount);
// count the non-empty & active panels in active panels
const nonEmptyAndActivePanels = keys.filter((key) => {
const targetPanel = panels.find((panel) => panel.id === key);
if (!targetPanel) {
return false;
} else if (typeof targetPanel._isEmpty === 'boolean') {
return !targetPanel._isEmpty;
} else {
const content = renderPanels(panel, panel.renderPanel);
return !!content;
if (panel.config?.grow === 0) {
// to get current panel content
const contentDom = select(
`.${collapseContentClassName}[data-content='${panel.id}']`
);
if (contentDom) {
const height =
contentDom.getBoundingClientRect().height +
HEADER_HEIGTH;
res[0] =
height > MAX_GROW_HEIGHT ? MAX_GROW_HEIGHT : height;
}
});
} else {
// get the height of the wrapper
let wrapperHeight =
wrapper.current?.getBoundingClientRect().height ||
_cacheWrapperHeight.current;
_cacheWrapperHeight.current = wrapperHeight;
// count active panels
const activeCount = keys.length;
const inactiveCount = panels.length - activeCount;
// the height active panels can occupied
wrapperHeight = wrapperHeight - HEADER_HEIGTH * inactiveCount;

// get grow-zero panels' heights
const growZeroPanelsKeys = getZeroPanelsByKeys(keys, panels);
const growZeroPanelsHeights = getContentHeightsByKeys(
growZeroPanelsKeys
);

// the height for active panels is divided equally by non-empty & active panels
res[0] =
(activePanelHeight -
// the height grow-normal panels can occupied =
// the height active panels can occupied -
// each grow-zero panels' heights
growZeroPanelsHeights.forEach((height) => {
wrapperHeight -= height;
});

// count the non-empty & active & non-grow-zero panels in active panels
const nonEmptyAndActivePanels: DataBaseProps[] = [];
const nonEmptyAndActivePanelKeys = keys.filter((key) => {
const target = panels.find((p) => p.id === key);
if (target) {
if (getGrow(target) === 0) return false;
if (typeof target._isEmpty === 'boolean') {
!target._isEmpty &&
nonEmptyAndActivePanels.push(target);
return !target._isEmpty;
}
// In general, the following code will not be excuted
const contentDom = select(
`.${collapseContentClassName}[data-content='${panel.id}']`
);
return contentDom?.hasChildNodes();
}
return false;
});

const growSum = nonEmptyAndActivePanels.reduce((pre, cur) => {
return pre + getGrow(cur);
}, 0);

const emptyAndActivePanelsHeights =
HEADER_HEIGTH *
(keys.length - nonEmptyAndActivePanels.length)) /
nonEmptyAndActivePanels.length;
(keys.length -
growZeroPanelsKeys.length -
nonEmptyAndActivePanelKeys.length);

// the height for grow-normal panels is divided by non-empty & active & grow-normal panels depends on grow number
res[0] =
((wrapperHeight - emptyAndActivePanelsHeights) *
getGrow(panel)) /
growSum;
}
}

// calculate top for current panel
Expand Down
3 changes: 3 additions & 0 deletions src/extensions/editorTree/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ export const ExtendsEditorTree: IExtension = {

molecule.editorTree.onClose((tabId, groupId) => {
molecule.editor.closeTab(tabId, groupId);
molecule.explorer.forceUpdate();
});

molecule.editorTree.onCloseOthers((tabItem, groupId) => {
molecule.editor.closeOthers(tabItem, groupId);
molecule.explorer.forceUpdate();
});

molecule.editorTree.onCloseSaved((groupId) => {
Expand All @@ -28,6 +30,7 @@ export const ExtendsEditorTree: IExtension = {
molecule.editor.closeAll(group.id!);
});
}
molecule.explorer.forceUpdate();
});

molecule.editorTree.onSaveAll((groupId) => {
Expand Down
1 change: 1 addition & 0 deletions src/extensions/folderTree/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const ExtendsFolderTree: IExtension = {
} else {
molecule.editor.open(tabData);
}
molecule.explorer.updateRender();
}
);

Expand Down
6 changes: 6 additions & 0 deletions src/model/workbench/explorer/explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ export function builtInExplorerEditorPanel() {
iconName: 'codicon-close-all',
},
],
config: {
grow: 0,
},
};
}

Expand Down Expand Up @@ -164,6 +167,9 @@ export function builtInExplorerFolderPanel() {
iconName: 'codicon-collapse-all',
},
],
config: {
grow: 2,
},
};
}

Expand Down