Skip to content
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,18 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
#### 🐛 Fixed
- Fix partially or fully hidden outlines for `WorkspaceLayoutItem` headers and `Navigator` toggle button.
- Fix undo/redo not adding or removing graph elements or links after `DataDiagramModel.discardLayout()` call (e.g. by a reload from `useLoadedWorkspace()`).
- Fix small input width overflow in `UnifiedSearch` when resized to the minimum size.
- Fix `Navigator` to avoid animating expand/collapse transition on the initial mount.

#### ⏱ Performance
- Fix canvas panning optimization not being applied due to incorrect `z-index` value.

#### 💅 Polish
- Improve `WorkspaceLayout*` item resize handing:
* Enable size transition on expand/collapse `WorkspaceLayoutRow` items;
* Set a default minimum non-wrapping size on item width via `--reactodia-accordion-item-min-width`;
* Auto-collapse items after resize if the final size is less than `minSize` for that item;
* Prevent toggle buttons on `WorkspaceLayoutRow` children from being partially hidden when corresponding item is collapsed.
- Export `TranslationProvider` and `DefaultTranslation` to be able to use `useTranslation()` outside the workspace component:
* Remove deprecated `Translation.formatIri()` method (use `DataLocaleProvider.formatIri()` instead).
- Always display ungroup buttons on `StandardGroup` when the element is single-selected.
Expand Down
33 changes: 29 additions & 4 deletions src/widgets/navigator.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import cx from 'clsx';

import { useColorScheme } from '../coreUtils/colorScheme';
import { EventObserver } from '../coreUtils/events';
Expand Down Expand Up @@ -166,6 +167,7 @@ interface NavigatorInnerProps extends NavigatorProps {
}

interface State {
initialized: boolean;
expanded: boolean;
autoToggle: boolean;
allowExpand: boolean;
Expand Down Expand Up @@ -208,6 +210,7 @@ class NavigatorInner extends React.Component<NavigatorInnerProps, State> {
super(props);
const {expanded = DEFAULT_EXPANDED} = this.props;
this.state = {
initialized: false,
expanded: Boolean(expanded),
autoToggle: expanded === 'auto',
allowExpand: true,
Expand Down Expand Up @@ -471,26 +474,48 @@ class NavigatorInner extends React.Component<NavigatorInnerProps, State> {
this.setState({
expanded: autoExpanded,
allowExpand: strictExpanded,
}, this.scheduleRedraw);
}, () => {
this.scheduleRedraw();
void this.setInitialized();
});
} else if (strictExpanded !== allowExpand) {
this.setState({allowExpand: strictExpanded});
this.setState(
{allowExpand: strictExpanded},
() => {
void this.setInitialized();
}
);
} else {
void this.setInitialized();
}
};

private async setInitialized(): Promise<void> {
// Perform state update in a microtask to allow expanded state to settle
// and avoid running any expand/collapse transitions on the initial mount
await Promise.resolve();
this.setState({initialized: true});
}

render() {
const {
dock = 'se', dockOffsetX, dockOffsetY,
width = DEFAULT_WIDTH,
height = DEFAULT_HEIGHT,
translation: t,
} = this.props;
const {expanded, allowExpand} = this.state;
const {initialized, expanded, allowExpand} = this.state;
const expandedWhenAllowed = expanded && allowExpand;
return (
<ViewportDock dock={dock}
dockOffsetX={dockOffsetX}
dockOffsetY={dockOffsetY}>
<div className={`${CLASS_NAME} ${CLASS_NAME}--${expandedWhenAllowed ? 'expanded' : 'collapsed'}`}
<div
className={cx(
CLASS_NAME,
initialized ? `${CLASS_NAME}--animated` : undefined,
`${CLASS_NAME}--${expandedWhenAllowed ? 'expanded' : 'collapsed'}`,
)}
style={expandedWhenAllowed ? {width, height} : undefined}>
<canvas ref={this.onCanvasMount}
width={width}
Expand Down
1 change: 0 additions & 1 deletion src/widgets/unifiedSearch/unifiedSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -396,7 +396,6 @@ function SearchToggle(props: {
role='searchbox'
type='text'
className={`${CLASS_NAME}__search-input`}
style={{minWidth}}
placeholder={
t.textOptional('unified_search.input.placeholder') ??
t.text('search_defaults.input.placeholder')
Expand Down
34 changes: 22 additions & 12 deletions src/workspace/accordion.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,13 @@ export class Accordion extends React.Component<AccordionProps, State> {

private defaultProps!: ReadonlyMap<number, DefaultItemProps>;

private isScrollable = false;

constructor(props: AccordionProps) {
super(props);
const childCount = React.Children.count(this.props.children);
this.state = {
sizes: [],
collapsed: [],
resizing: false,
resizing: true,
percents: React.Children.map(this.props.children, () => `${100 / childCount}%`) as string[],
};
}
Expand Down Expand Up @@ -111,10 +109,6 @@ export class Accordion extends React.Component<AccordionProps, State> {
if (typeof child !== 'object') { return; }
if (child) {
const {defaultSize, defaultCollapsed, collapsedSize, minSize} = child.props;
// enables the scrollbar in the accordion if at least one item has min size
if (minSize !== undefined) {
this.isScrollable = true;
}
defaultProps.set(index, {defaultSize, defaultCollapsed, collapsedSize, minSize});
} else {
defaultProps.set(index, {});
Expand Down Expand Up @@ -169,6 +163,8 @@ export class Accordion extends React.Component<AccordionProps, State> {
percents: newPercents,
collapsed: newCollapsed,
};
}, () => {
this.setState({resizing: false});
});
}

Expand All @@ -181,7 +177,6 @@ export class Accordion extends React.Component<AccordionProps, State> {
CLASS_NAME,
`${CLASS_NAME}--${direction}`,
resizing ? `${CLASS_NAME}--resizing` : undefined,
this.isScrollable ? `${CLASS_NAME}--scrollable` : undefined,
className
)}
style={style}>
Expand Down Expand Up @@ -239,9 +234,22 @@ export class Accordion extends React.Component<AccordionProps, State> {
}

private onEndDragHandle = () => {
this.setState({resizing: false});
this.setState(
{resizing: false},
() => this.tryCollapseTooSmallItem()
);
};

private tryCollapseTooSmallItem() {
const collapsedIndex = this.state.sizes.findIndex((size, index) => {
const defaults = this.defaultProps.get(index);
return defaults && defaults.minSize && size < defaults.minSize;
});
if (collapsedIndex >= 0) {
this.onItemChangeCollapsed({itemIndex: collapsedIndex, itemCollapsed: true});
}
}

private computeEffectiveItemSizes(): number[] {
const sizes: Array<number> = [];
this.items.forEach((item, index) => {
Expand Down Expand Up @@ -275,7 +283,7 @@ export class Accordion extends React.Component<AccordionProps, State> {
const originTotalSize = this.dragOrigin!.totalSize;

new SizeDistributor(
sizes, collapsed, originTotalSize, this.sizeWhenCollapsed,
sizes, collapsed, originTotalSize, this.sizeWhenCollapsed
).distribute(itemIndex + 1, this.isVertical ? dy : dx);

const percents = sizes.map(size => `${100 * size / originTotalSize}%`);
Expand All @@ -298,7 +306,8 @@ export class Accordion extends React.Component<AccordionProps, State> {

const collapsedSize = this.sizeWhenCollapsed(itemIndex);
const distributor = new SizeDistributor(
sizes, collapsed, totalSize, this.sizeWhenCollapsed);
sizes, collapsed, totalSize, this.sizeWhenCollapsed
);

if (itemCollapsed) {
const splitShift = Math.max(effectiveSize - collapsedSize, 0);
Expand Down Expand Up @@ -396,9 +405,10 @@ class SizeDistributor {
expand(shift: number, index: number) {
if (shift <= 0) { return 0; }
const oldSize = this.sizes[index];
const collapsedSize = this.sizeWhenCollapsed(index);
const newSize = Math.round(oldSize + shift);
this.sizes[index] = newSize;
this.collapsed[index] = newSize <= this.sizeWhenCollapsed(index);
this.collapsed[index] = newSize <= collapsedSize;
return newSize - oldSize;
}

Expand Down
7 changes: 6 additions & 1 deletion src/workspace/accordionItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,12 @@ export class AccordionItem extends React.Component<AccordionItemProps, State> {
} = this.props;
const {resizing} = this.state;
const shouldRenderHandle = onBeginDragHandle && onDragHandle && onEndDragHandle;
const providedStyle: React.CSSProperties = this.isVertical ? {height: size} : {width: size};
const providedStyle: React.CSSProperties = this.isVertical
? {height: size}
: {
width: size,
'--reactodia-accordion-item-size': typeof size === 'number' ? `${size}px` : undefined,
} as React.CSSProperties;

// unmount child component when the accordion item is collapsed and has dockSide
const isMounted = !(collapsed && dockSide);
Expand Down
1 change: 1 addition & 0 deletions styles/theme/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -121,5 +121,6 @@

--reactodia-toolbar-height: 30px;

--reactodia-item-min-width: 150px;
--reactodia-accordion-transition-duration: var(--reactodia-transition-duration);
}
1 change: 1 addition & 0 deletions styles/theme/_theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -188,4 +188,5 @@ $navigator-overflow-stroke-dash: var(--reactodia-navigator-overflow-stroke-dash)
$toolbar-height: var(--reactodia-toolbar-height);

/* Accordion */
$accordion-item-min-width: var(--reactodia-item-min-width);
$accordion-transition-duration: var(--reactodia-accordion-transition-duration);
8 changes: 5 additions & 3 deletions styles/widgets/_navigator.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
border-radius: theme.$border-radius-s;
box-shadow: theme.$canvas-box-shadow;

transition:
width theme.$transition-duration,
height theme.$transition-duration;
&--animated {
transition:
width theme.$transition-duration,
height theme.$transition-duration;
}

&--collapsed {
width: 24px;
Expand Down
1 change: 1 addition & 0 deletions styles/widgets/_unifiedSearch.scss
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ $searchButtonTotal: $searchButtonWidth + $searchButtonPadding * 2;
display: block;
margin: 0;
padding: 6px #{12px + $searchButtonTotal} 6px 12px;
min-width: 0;
color: theme.$input-color;
background-color: theme.$background-color-surface;
border: none;
Expand Down
36 changes: 27 additions & 9 deletions styles/workspace/_accordion.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,23 @@
height: 100%;
width: 100%;

&--scrollable {
overflow: auto;
}

&--vertical {
flex-direction: column;
}

&--vertical:not(&--resizing):not(:has(.reactodia-accordion-item__handle:focus)) > .reactodia-accordion-item {
transition: height theme.$accordion-transition-duration ease-in-out;
}

&--horizontal:not(&--resizing):not(:has(.reactodia-accordion-item__handle:focus)) > .reactodia-accordion-item {
transition: width theme.$accordion-transition-duration ease-in-out;
}
}

.reactodia-accordion-item {
$buttonSize: 20px;
$buttonAreaMargin: 4px;

display: flex;
position: relative;
flex: auto;
Expand Down Expand Up @@ -68,10 +71,10 @@

&__handle-btn {
position: absolute;
width: 20px;
height: 20px;
width: $buttonSize;
height: $buttonSize;
top: 50%;
margin-top: -10px;
margin-top: -0.5 * $buttonSize;
padding: 0;

background-color: theme.$button-default-background-color;
Expand Down Expand Up @@ -110,24 +113,38 @@

&__handle-btn-left {
left: 100%;
margin-left: -10px;
margin-left: -0.5 * $buttonSize;

&::before {
-webkit-mask-image: url("@codicons/chevron-left.svg");
mask-image: url("@codicons/chevron-left.svg");
}
}

&--collapsed &__handle-btn-left {
margin-left: calc(-1 * min(
0.5 * $buttonSize,
var(--reactodia-accordion-item-size, 0px) - $buttonAreaMargin
));
}

&__handle-btn-right {
right: 100%;
margin-right: -10px;
margin-right: -0.5 * $buttonSize;

&:before {
-webkit-mask-image: url("@codicons/chevron-right.svg");
mask-image: url("@codicons/chevron-right.svg");
}
}

&--collapsed &__handle-btn-right {
margin-right: calc(-1 * min(
0.5 * $buttonSize,
var(--reactodia-accordion-item-size, 0px) - $buttonAreaMargin
));
}

&--collapsed &__handle-btn:before {
transform: rotate(180deg);
}
Expand All @@ -144,6 +161,7 @@
display: flex;
flex-direction: column;
background-color: theme.$background-color;
min-width: theme.$accordion-item-min-width;
}

&__header {
Expand Down
Loading