Merge pull request #411 from NaNgets/388-rtl-support-gpgsigned

RTL support.
This commit is contained in:
mathuo 2023-12-28 21:42:05 +00:00 committed by GitHub
commit c2d65db045
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 289 additions and 69 deletions

View File

@ -3,10 +3,10 @@
> .drop-target-dropzone {
position: absolute;
left: 0px;
top: 0px;
left: 0px;
right: 0px;
height: 100%;
width: 100%;
z-index: 1000;
pointer-events: none;
@ -17,8 +17,8 @@
width: 100%;
background-color: var(--dv-drag-over-background-color);
transition: top 70ms ease-out, left 70ms ease-out,
width 70ms ease-out, height 70ms ease-out,
opacity 0.15s ease-out;
right 70ms ease-out, width 70ms ease-out,
height 70ms ease-out, opacity 0.15s ease-out;
will-change: transform;
pointer-events: none;

View File

@ -42,8 +42,8 @@
.dv-resize-handle-top {
height: 4px;
width: calc(100% - 8px);
left: 4px;
right: 4px;
top: -2px;
z-index: 999;
position: absolute;
@ -52,8 +52,8 @@
.dv-resize-handle-bottom {
height: 4px;
width: calc(100% - 8px);
left: 4px;
right: 4px;
bottom: -2px;
z-index: 999;
position: absolute;

View File

@ -1,6 +1,6 @@
import { DragAndDropObserver } from '../../dnd/dnd';
import { Droptarget } from '../../dnd/droptarget';
import { getDomNodePagePosition, toggleClass } from '../../dom';
import { getDomNodePagePosition, hasClassInTree, toggleClass } from '../../dom';
import { CompositeDisposable, Disposable, IDisposable } from '../../lifecycle';
import { IDockviewPanel } from '../dockviewPanel';
@ -77,7 +77,9 @@ export class GreadyRenderContainer extends CompositeDisposable {
// TODO propagate position to avoid getDomNodePagePosition calls
const box = getDomNodePagePosition(referenceContainer.element);
const box2 = getDomNodePagePosition(this.element);
focusContainer.style.left = `${box.left - box2.left}px`;
const isRtl = hasClassInTree(this.element, 'dv-rtl');
focusContainer.style.left = isRtl ? '' : `${(box.left || 0) - (box2.left || 0)}px`;
focusContainer.style.right = isRtl ? `${(box.right || 0) - (box2.right || 0)}px` : '';
focusContainer.style.top = `${box.top - box2.top}px`;
focusContainer.style.width = `${box.width}px`;
focusContainer.style.height = `${box.height}px`;

View File

@ -63,12 +63,19 @@
content: ' ';
position: absolute;
top: 0;
left: 0;
z-index: 5;
pointer-events: none;
background-color: var(--dv-tab-divider-color);
width: 1px;
height: 100%;
.dv-ltr & {
left: 0;
}
.dv-rtl & {
right: 0;
}
}
}
}

View File

@ -251,15 +251,15 @@ export class TabsContainer
) {
event.preventDefault();
const { top, left } =
const { top, left, right } =
this.element.getBoundingClientRect();
const { top: rootTop, left: rootLeft } =
const { top: rootTop, left: rootLeft, right: rootRight } =
this.accessor.element.getBoundingClientRect();
this.accessor.addFloatingGroup(
this.group,
{
x: left - rootLeft + 20,
x: (this.accessor.options.isRtl ? (right - rootRight) : (left - rootLeft)) + 20,
y: top - rootTop + 20,
},
{ inDragMode: true }
@ -361,14 +361,14 @@ export class TabsContainer
const panel = this.accessor.getGroupPanel(tab.panel.id);
const { top, left } = tab.element.getBoundingClientRect();
const { top: rootTop, left: rootLeft } =
const { top, left, right } = tab.element.getBoundingClientRect();
const { top: rootTop, left: rootLeft, right: rootRight } =
this.accessor.element.getBoundingClientRect();
this.accessor.addFloatingGroup(
panel as DockviewPanel,
{
x: left - rootLeft,
x: (this.accessor.options.isRtl ? (right - rootRight) : (left - rootLeft)) + 20,
y: top - rootTop,
},
{ inDragMode: true }

View File

@ -2,12 +2,20 @@
position: relative;
background-color: var(--dv-group-view-background-color);
&.dv-ltr {
direction: ltr;
}
&.dv-rtl {
direction: rtl;
}
.dv-watermark-container {
position: absolute;
top: 0px;
left: 0px;
right: 0px;
height: 100%;
width: 100%;
z-index: 1;
}

View File

@ -316,6 +316,7 @@ export class DockviewComponent
styles: options.styles,
parentElement: options.parentElement,
disableAutoResizing: options.disableAutoResizing,
isRtl: options.isRtl,
});
const gready = document.createElement('div');
@ -1007,7 +1008,8 @@ export class DockviewComponent
const relativeLocation = getRelativeLocation(
this.gridview.orientation,
location,
target
target,
this.options.isRtl
);
const group = this.createGroupAtLocation(relativeLocation);
panel = this.createPanel(options, group);
@ -1155,7 +1157,8 @@ export class DockviewComponent
const relativeLocation = getRelativeLocation(
this.gridview.orientation,
location,
target
target,
this.options.isRtl
);
this.doAddGroup(group, relativeLocation);
return group;
@ -1270,7 +1273,8 @@ export class DockviewComponent
const targetLocation = getRelativeLocation(
this.gridview.orientation,
referenceLocation,
destinationTarget
destinationTarget,
this.options.isRtl
);
if (sourceGroup && sourceGroup.size < 2) {
@ -1310,7 +1314,8 @@ export class DockviewComponent
const location = getRelativeLocation(
this.gridview.orientation,
updatedReferenceLocation,
destinationTarget
destinationTarget,
this.options.isRtl
);
this.doAddGroup(targetGroup, location);
} else {
@ -1325,7 +1330,8 @@ export class DockviewComponent
const dropLocation = getRelativeLocation(
this.gridview.orientation,
referenceLocation,
destinationTarget
destinationTarget,
this.options.isRtl
);
const group = this.createGroupAtLocation(dropLocation);
@ -1374,7 +1380,8 @@ export class DockviewComponent
const dropLocation = getRelativeLocation(
this.gridview.orientation,
referenceLocation,
target
target,
this.options.isRtl
);
this.gridview.addView(

View File

@ -7,7 +7,7 @@ export interface IDockviewFloatingGroupPanel {
position(
bounds: Partial<{
top: number;
left: number;
side: number;
height: number;
width: number;
}>
@ -27,7 +27,7 @@ export class DockviewFloatingGroupPanel
position(
bounds: Partial<{
top: number;
left: number;
side: number;
height: number;
width: number;
}>

View File

@ -98,6 +98,7 @@ export interface DockviewComponentOptions extends DockviewRenderFunctions {
minimumWidthWithinViewport?: number;
};
defaultRenderer?: DockviewPanelRenderer;
isRtl?: boolean;
debug?: boolean;
}

View File

@ -186,15 +186,29 @@ export function quasiDefaultPrevented(event: Event): boolean {
return (event as any)[QUASI_PREVENT_DEFAULT_KEY];
}
// Gets whether the given class exists in the element or its parent tree
export function hasClassInTree(domNode: Element, className: string): boolean {
if (domNode.classList.contains(className)) {
return true;
}
if (domNode.parentElement) {
return hasClassInTree(domNode.parentElement, className);
}
return false;
}
export function getDomNodePagePosition(domNode: Element): {
left: number;
left?: number;
right?: number;
top: number;
width: number;
height: number;
} {
const { left, top, width, height } = domNode.getBoundingClientRect();
const isRtl = hasClassInTree(domNode, 'dv-rtl');
const { left, right, top, width, height } = domNode.getBoundingClientRect();
return {
left: left + window.scrollX,
left: isRtl ? undefined : left + window.scrollX,
right: isRtl ? right + window.scrollX : undefined,
top: top + window.scrollY,
width: width,
height: height,

View File

@ -7,6 +7,7 @@ import { ISplitviewStyles, Orientation, Sizing } from '../splitview/splitview';
import { IPanel } from '../panel/types';
import { MovementOptions2 } from '../dockview/options';
import { Resizable } from '../resizable';
import { toggleClass } from '../dom';
const nextLayoutId = sequentialNumberGenerator();
@ -34,6 +35,7 @@ export interface BaseGridOptions {
readonly styles?: ISplitviewStyles;
readonly parentElement?: HTMLElement;
readonly disableAutoResizing?: boolean;
readonly isRtl?: boolean;
}
export interface IGridPanelView extends IGridView, IPanel {
@ -137,6 +139,9 @@ export abstract class BaseGrid<T extends IGridPanelView>
options.orientation
);
toggleClass(this.gridview.element, 'dv-rtl', options.isRtl === true);
toggleClass(this.gridview.element, 'dv-ltr', options.isRtl === false);
this.element.appendChild(this.gridview.element);
this.layout(0, 0, true); // set some elements height/widths

View File

@ -2,4 +2,12 @@
.branch-node {
height: 100%;
width: 100%;
&.dv-ltr {
direction: ltr;
}
&.dv-rtl {
direction: rtl;
}
}

View File

@ -123,7 +123,8 @@ export function getGridLocation(element: HTMLElement): number[] {
export function getRelativeLocation(
rootOrientation: Orientation,
location: number[],
direction: Position
direction: Position,
isRtl?: boolean
): number[] {
const orientation = getLocationOrientation(rootOrientation, location);
const directionOrientation = getDirectionOrientation(direction);
@ -132,13 +133,13 @@ export function getRelativeLocation(
const [rest, _index] = tail(location);
let index = _index;
if (direction === 'right' || direction === 'bottom') {
if ((isRtl ? direction === 'left' : direction === 'right') || direction === 'bottom') {
index += 1;
}
return [...rest, index];
} else {
const index = direction === 'right' || direction === 'bottom' ? 1 : 0;
const index = (isRtl ? direction === 'left' : direction === 'right') || direction === 'bottom' ? 1 : 0;
return [...location, index];
}
}

View File

@ -110,6 +110,7 @@ export class GridviewComponent
orientation: options.orientation,
styles: options.styles,
disableAutoResizing: options.disableAutoResizing,
isRtl: options.isRtl,
});
this._options = options;
@ -299,7 +300,8 @@ export class GridviewComponent
relativeLocation = getRelativeLocation(
this.gridview.orientation,
location,
target
target,
this.options.isRtl
);
}
@ -330,7 +332,8 @@ export class GridviewComponent
relativeLocation = getRelativeLocation(
this.gridview.orientation,
location,
target
target,
this.options.isRtl
);
}
}
@ -406,7 +409,8 @@ export class GridviewComponent
const targetLocation = getRelativeLocation(
this.gridview.orientation,
referenceLocation,
target
target,
this.options.isRtl
);
const [targetParentLocation, to] = tail(targetLocation);
@ -435,7 +439,8 @@ export class GridviewComponent
const location = getRelativeLocation(
this.gridview.orientation,
updatedReferenceLocation,
target
target,
this.options.isRtl
);
this.doAddGroup(targetGroup, location);
}

View File

@ -17,5 +17,6 @@ export interface GridviewComponentOptions {
};
frameworkComponentFactory?: FrameworkFactory<GridviewPanel>;
styles?: ISplitviewStyles;
isRtl?: boolean;
parentElement?: HTMLElement;
}

View File

@ -146,14 +146,29 @@ export abstract class DraggablePaneviewPanel extends PaneviewPanel {
const fromIndex = allPanels.indexOf(existingPanel);
let toIndex = containerApi.panels.indexOf(this);
console.log('onDrop', this.accessor.options.isRtl, fromIndex, toIndex, event.position);
if (event.position === 'left' || event.position === 'top') {
toIndex = Math.max(0, toIndex - 1);
if (this.accessor.options.isRtl) {
if (fromIndex > toIndex) {
toIndex++;
}
toIndex = Math.min(allPanels.length - 1, toIndex);
}
else {
toIndex = Math.max(0, toIndex - 1);
}
}
if (event.position === 'right' || event.position === 'bottom') {
if (fromIndex > toIndex) {
toIndex++;
if (this.accessor.options.isRtl) {
toIndex = Math.max(0, toIndex - 1);
}
else {
if (fromIndex > toIndex) {
toIndex++;
}
toIndex = Math.min(allPanels.length - 1, toIndex);
}
toIndex = Math.min(allPanels.length - 1, toIndex);
}
containerApi.movePanel(fromIndex, toIndex);

View File

@ -26,4 +26,5 @@ export interface PaneviewComponentOptions {
disableDnd?: boolean;
showDndOverlay?: (event: PaneviewDndOverlayEvent) => boolean;
parentElement?: HTMLElement;
isRtl?: boolean;
}

View File

@ -2,6 +2,18 @@
height: 100%;
width: 100%;
&.dv-ltr {
direction: ltr;
}
&.dv-rtl {
direction: rtl;
.view .default-header .dockview-pane-header-icon {
transform: scale(-1, 1);
}
}
&.animated {
.view {
transition-duration: 0.15s;
@ -38,8 +50,8 @@
}
> span {
padding-left: 8px;
flex-grow: 1;
padding-inline-start: 8px;
}
}
}
@ -70,7 +82,7 @@
position: absolute;
top: 0;
left: 0;
width: 100%;
right: 0;
height: 100%;
z-index: 5;
content: '';
@ -96,7 +108,7 @@
position: absolute;
top: 0;
left: 0;
width: 100%;
right: 0;
height: 100%;
z-index: 5;
content: '';

View File

@ -6,7 +6,7 @@ import {
} from '../splitview/splitview';
import { CompositeDisposable, IDisposable } from '../lifecycle';
import { Emitter, Event } from '../events';
import { addClasses, removeClasses } from '../dom';
import { addClasses, removeClasses, toggleClass } from '../dom';
import { PaneviewPanel } from './paneviewPanel';
interface PaneItem {
@ -54,7 +54,7 @@ export class Paneview extends CompositeDisposable implements IDisposable {
constructor(
container: HTMLElement,
options: { orientation: Orientation; descriptor?: ISplitViewDescriptor }
options: { orientation: Orientation; isRtl?: boolean; descriptor?: ISplitViewDescriptor }
) {
super();
@ -63,12 +63,16 @@ export class Paneview extends CompositeDisposable implements IDisposable {
this.element = document.createElement('div');
this.element.className = 'pane-container';
toggleClass(this.element, 'dv-rtl', options.isRtl === true);
toggleClass(this.element, 'dv-ltr', options.isRtl === false);
container.appendChild(this.element);
this.splitview = new Splitview(this.element, {
orientation: this._orientation,
proportionalLayout: false,
descriptor: options.descriptor,
isRtl: options.isRtl,
});
// if we've added views from the descriptor we need to

View File

@ -24,6 +24,7 @@ import { sequentialNumberGenerator } from '../math';
import { PaneTransfer } from '../dnd/dataTransfer';
import { Resizable } from '../resizable';
import { Parameters } from '../panel/types';
import { toggleClass } from '../dom';
const nextLayoutId = sequentialNumberGenerator();
@ -221,6 +222,7 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
this.paneview = new Paneview(this.element, {
// only allow paneview in the vertical orientation for now
orientation: Orientation.VERTICAL,
isRtl: options.isRtl,
});
this.addDisposables(this._disposable);
@ -369,6 +371,7 @@ export class PaneviewComponent extends Resizable implements IPaneviewComponent {
this.paneview = new Paneview(this.element, {
orientation: Orientation.VERTICAL,
isRtl: this.options.isRtl,
descriptor: {
size,
views: views.map((view) => {

View File

@ -25,6 +25,22 @@
height: 100%;
width: 100%;
&.dv-ltr {
direction: ltr;
&.separator-border .view:not(:first-child)::before {
left: 0;
}
}
&.dv-rtl {
direction: rtl;
&.separator-border .view:not(:first-child)::before {
right: 0;
}
}
&.animation {
.view,
.sash {
@ -145,7 +161,6 @@
content: ' ';
position: absolute;
top: 0;
left: 0;
z-index: 5;
pointer-events: none;
background-color: var(--dv-separator-border);

View File

@ -8,6 +8,7 @@ import {
addClasses,
toggleClass,
getElementsByTagName,
hasClassInTree,
} from '../dom';
import { Event, Emitter } from '../events';
import { pushToStart, pushToEnd, firstIndex } from '../array';
@ -36,6 +37,7 @@ export interface SplitViewOptions {
readonly descriptor?: ISplitViewDescriptor;
readonly proportionalLayout?: boolean;
readonly styles?: ISplitviewStyles;
readonly isRtl?: boolean;
}
export enum LayoutPriority {
@ -201,7 +203,7 @@ export class Splitview {
options: SplitViewOptions
) {
this._orientation = options.orientation;
this.element = this.createContainer();
this.element = this.createContainer(options.isRtl);
this.proportionalLayout =
options.proportionalLayout === undefined
@ -756,6 +758,7 @@ export class Splitview {
private layoutViews(): void {
this.contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
const isRtl = hasClassInTree(this.element, 'dv-rtl');
let sum = 0;
const x: number[] = [];
@ -768,18 +771,21 @@ export class Splitview {
const offset = Math.min(Math.max(0, sum - 2), this.size - 4);
if (this._orientation === Orientation.HORIZONTAL) {
this.sashes[i].container.style.left = `${offset}px`;
this.sashes[i].container.style.left = isRtl ? '' : `${offset}px`;
this.sashes[i].container.style.right = isRtl ? `${offset}px` : '';
this.sashes[i].container.style.top = `0px`;
}
if (this._orientation === Orientation.VERTICAL) {
this.sashes[i].container.style.left = `0px`;
this.sashes[i].container.style.left = isRtl ? '' : `0px`;
this.sashes[i].container.style.right = isRtl ? `0px` : '';
this.sashes[i].container.style.top = `${offset}px`;
}
}
this.viewItems.forEach((view, i) => {
if (this._orientation === Orientation.HORIZONTAL) {
view.container.style.width = `${view.size}px`;
view.container.style.left = i == 0 ? '0px' : `${x[i - 1]}px`;
view.container.style.left = isRtl ? '' : (i == 0 ? '0px' : `${x[i - 1]}px`);
view.container.style.right = isRtl ? (i == 0 ? '0px' : `${x[i - 1]}px`) : '';
view.container.style.top = '';
view.container.style.height = '';
}
@ -788,6 +794,7 @@ export class Splitview {
view.container.style.top = i == 0 ? '0px' : `${x[i - 1]}px`;
view.container.style.width = '';
view.container.style.left = '';
view.container.style.right = '';
}
view.view.layout(view.size, this._orthogonalSize);
@ -918,8 +925,10 @@ export class Splitview {
return 0;
}
const upIndexes = range(index, -1);
const downIndexes = range(index + 1, this.viewItems.length);
const isHorizontal = this._orientation === Orientation.HORIZONTAL;
const isRtl = hasClassInTree(this.element, 'dv-rtl');
const upIndexes = isHorizontal && isRtl && this.viewItems.length > 1 ? range(index + 1, this.viewItems.length) : range(index, -1);
const downIndexes = isHorizontal && isRtl && this.viewItems.length > 1 ? range(index, -1) : range(index + 1, this.viewItems.length);
//
if (highPriorityIndexes) {
for (const i of highPriorityIndexes) {
@ -955,7 +964,6 @@ export class Splitview {
? Number.POSITIVE_INFINITY
: downIndexes.reduce(
(_, i) => _ + sizes[i] - this.viewItems[i].minimumSize,
0
);
const minDeltaDown =
@ -1044,13 +1052,15 @@ export class Splitview {
return element;
}
private createContainer(): HTMLElement {
private createContainer(isRtl?: boolean): HTMLElement {
const element = document.createElement('div');
const orientationClassname =
this._orientation === Orientation.HORIZONTAL
? 'horizontal'
: 'vertical';
element.className = `split-view-container ${orientationClassname}`;
toggleClass(element, 'dv-rtl', isRtl === true);
toggleClass(element, 'dv-ltr', isRtl === false);
return element;
}

View File

@ -349,6 +349,7 @@ export class SplitviewComponent
this.splitview = new Splitview(this.element, {
orientation,
proportionalLayout: this.options.proportionalLayout,
isRtl: this.options.isRtl,
descriptor: {
size,
views: views.map((view) => {

View File

@ -185,9 +185,9 @@
&::after {
position: absolute;
left: 0px;
right: 0px;
top: 0px;
content: '';
width: 100%;
height: 1px;
background-color: #94527e;
z-index: 999;
@ -205,9 +205,9 @@
&::after {
position: absolute;
left: 0px;
right: 0px;
bottom: 0px;
content: '';
width: 100%;
height: 1px;
background-color: #5e3d5a;
z-index: 999;

View File

@ -77,6 +77,7 @@ export interface IDockviewReactProps {
minimumHeightWithinViewport?: number;
minimumWidthWithinViewport?: number;
};
isRtl?: boolean;
debug?: boolean;
defaultRenderer?: DockviewPanelRenderer;
}
@ -179,6 +180,7 @@ export const DockviewReact = React.forwardRef(
disableFloatingGroups: props.disableFloatingGroups,
floatingGroupBounds: props.floatingGroupBounds,
defaultRenderer: props.defaultRenderer,
isRtl: props.isRtl,
debug: props.debug,
});

View File

@ -28,6 +28,7 @@ export interface IGridviewReactProps {
className?: string;
proportionalLayout?: boolean;
disableAutoResizing?: boolean;
isRtl?: boolean;
}
export const GridviewReact = React.forwardRef(
@ -69,6 +70,7 @@ export const GridviewReact = React.forwardRef(
styles: props.hideBorders
? { separatorBorder: 'transparent' }
: undefined,
isRtl: props.isRtl,
});
const { clientWidth, clientHeight } = domRef.current;

View File

@ -27,6 +27,7 @@ export interface IPaneviewReactProps {
components: PanelCollection<IPaneviewPanelProps>;
headerComponents?: PanelCollection<IPaneviewPanelProps>;
className?: string;
isRtl?: boolean;
disableAutoResizing?: boolean;
disableDnd?: boolean;
showDndOverlay?: (event: PaneviewDndOverlayEvent) => boolean;
@ -68,6 +69,7 @@ export const PaneviewReact = React.forwardRef(
},
},
showDndOverlay: props.showDndOverlay,
isRtl: props.isRtl,
});
const api = new PaneviewApi(paneview);

View File

@ -27,6 +27,7 @@ export interface ISplitviewReactProps {
proportionalLayout?: boolean;
hideBorders?: boolean;
className?: string;
isRtl?: boolean;
disableAutoResizing?: boolean;
}
@ -62,6 +63,7 @@ export const SplitviewReact = React.forwardRef(
styles: props.hideBorders
? { separatorBorder: 'transparent' }
: undefined,
isRtl: props.isRtl,
});
const { clientWidth, clientHeight } = domRef.current!;

View File

@ -890,3 +890,34 @@ If you wish to interact with the drop event from one dockview instance in anothe
### Window-like mananger with tabs
<DockviewNative2 />
## RTL support
You can set the dockview to RTL using the `isRtl` property.
<MultiFrameworkContainer
sandboxId="simple-dockview"
react={SimpleDockview}
isRtl={true}
/>
<MultiFrameworkContainer
sandboxId="watermark-dockview"
react={DockviewWatermark}
isRtl={true}
/>
<MultiFrameworkContainer
height={600}
sandboxId="floatinggroup-dockview"
react={DockviewFloating}
isRtl={true}
/>
<MultiFrameworkContainer
sandboxId="groupcontrol-dockview"
react={DockviewGroupControl}
isRtl={true}
/>
<DockviewNative2 isRtl={true} />

View File

@ -27,7 +27,7 @@ Gridview serves a purpose when you want only the nested splitviews with no tabs
## GridviewReact Component
```tsx
import { ReactGridview } from 'dockview';
import { GridviewReact } from 'dockview';
```
<DocRef declaration="IGridviewReactProps" />
@ -233,3 +233,14 @@ You can find more details on theming <Link to="../theme">here</Link>.
react={EditorGridview}
hideThemePicker={true}
/>
## RTL support
You can set the gridview to RTL using the `isRtl` property.
<MultiFrameworkContainer
height={600}
sandboxId="simple-gridview"
react={SimpleGridview}
isRtl={true}
/>

View File

@ -93,10 +93,10 @@ SimplePaneview = () => {
## PaneviewReact Component
You can create a Paneview through the use of the `ReactPaneview` component.
You can create a Paneview through the use of the `PaneviewReact` component.
```tsx
import { ReactPaneview } from 'dockview';
import { PaneviewReact } from 'dockview';
```
<DocRef declaration="IPaneviewReactProps" />
@ -167,7 +167,7 @@ const onReady = (event: PaneviewReadyEvent) => {
};
```
This header must be defined in the collection of components provided to the `headerComponents` props for `ReactPaneivew`
This header must be defined in the collection of components provided to the `headerComponents` props for `PaneviewReact`
```tsx
import { IPaneviewPanelProps } from 'dockview';
@ -226,3 +226,9 @@ If you wish to interact with the drop event from one paneview instance in anothe
As an example see how dragging a header from one control to another will only trigger an interactable event for the developer if the checkbox is enabled.
<SideBySidePaneview />
## RTL support
You can set the paneview to RTL using the `isRtl` property.
<MultiFrameworkContainer sandboxId="simple-paneview" react={SimplePaneview} isRtl={true} />

View File

@ -194,3 +194,18 @@ api.setConstraints({
minimumSize: 400,
});
```
## RTL support
You can set the splitview to RTL using the `isRtl` property.
<div
style={{
height: '100px',
backgroundColor: 'rgb(30,30,30)',
color: 'white',
margin: '20px 0px',
}}
>
<SimpleSplitview isRtl={true} />
</div>

View File

@ -127,7 +127,7 @@ const useLocalStorage = <T,>(
];
};
export const DockviewPersistance = (props: { theme?: string }) => {
export const DockviewPersistance = (props: { isRtl?: boolean; theme?: string; }) => {
const [api, setApi] = React.useState<DockviewApi>();
const [layout, setLayout] =
useLocalStorage<SerializedDockview>('floating.layout');
@ -235,6 +235,7 @@ export const DockviewPersistance = (props: { theme?: string }) => {
rightHeaderActionsComponent={RightComponent}
disableFloatingGroups={disableFloatingGroups}
floatingGroupBounds={options}
isRtl={props.isRtl}
className={`${props.theme || 'dockview-theme-abyss'}`}
/>
</div>

View File

@ -55,7 +55,7 @@ const LeftHeaderActions = (props: IDockviewHeaderActionsProps) => {
);
};
const DockviewGroupControl = (props: { theme: string }) => {
const DockviewGroupControl = (props: { isRtl?: boolean; theme: string; }) => {
const onReady = (event: DockviewReadyEvent) => {
const panel1 = event.api.addPanel({
id: 'panel_1',
@ -97,6 +97,7 @@ const DockviewGroupControl = (props: { theme: string }) => {
components={components}
leftHeaderActionsComponent={LeftHeaderActions}
rightHeaderActionsComponent={RightHeaderActions}
isRtl={props.isRtl}
className={`${props.theme || 'dockview-theme-abyss'}`}
/>
);

View File

@ -25,7 +25,7 @@ const components = {
);
},
isolatedApp: (
props: IDockviewPanelProps<{ title: string; x?: number }>
props: IDockviewPanelProps<{ title: string; isRtl?: boolean; x?: number }>
) => {
const onReady = (event: DockviewReadyEvent) => {
const panel1 = event.api.addPanel({
@ -55,6 +55,7 @@ const components = {
onReady={onReady}
components={components}
tabComponents={tabComponents}
isRtl={props.params.isRtl}
className="dockview-theme-abyss"
/>
);
@ -82,7 +83,7 @@ const tabComponents = {
},
};
const DockviewNative2 = (props: { theme?: string }) => {
const DockviewNative2 = (props: { isRtl?: boolean; theme?: string; }) => {
const onReady = (event: DockviewReadyEvent) => {
const panel1 = event.api.addPanel({
id: 'panel_1',
@ -90,6 +91,7 @@ const DockviewNative2 = (props: { theme?: string }) => {
tabComponent: 'default',
params: {
title: 'Window 1',
isRtl: props.isRtl,
},
});
panel1.group.locked = true;
@ -100,6 +102,7 @@ const DockviewNative2 = (props: { theme?: string }) => {
tabComponent: 'default',
params: {
title: 'Window 2',
isRtl: props.isRtl,
},
position: {
direction: 'right',
@ -113,6 +116,7 @@ const DockviewNative2 = (props: { theme?: string }) => {
tabComponent: 'default',
params: {
title: 'Window 3',
isRtl: props.isRtl,
},
position: {
direction: 'below',
@ -133,6 +137,7 @@ const DockviewNative2 = (props: { theme?: string }) => {
onReady={onReady}
components={components}
tabComponents={tabComponents}
isRtl={props.isRtl}
className={`${props.theme || 'dockview-theme-abyss'}`}
singleTabMode="fullwidth"
/>

View File

@ -15,7 +15,7 @@ const components = {
},
};
export const App: React.FC = (props: { theme?: string }) => {
export const App: React.FC = (props: { isRtl?: boolean; theme?: string; }) => {
const onReady = (event: DockviewReadyEvent) => {
const panel = event.api.addPanel({
id: 'panel_1',
@ -87,6 +87,7 @@ export const App: React.FC = (props: { theme?: string }) => {
return (
<DockviewReact
components={components}
isRtl={props.isRtl}
onReady={onReady}
className={props.theme || 'dockview-theme-abyss'}
/>

View File

@ -18,7 +18,7 @@ const components = {
},
};
export const App: React.FC = (props: { theme?: string }) => {
export const App: React.FC = (props: { isRtl?: boolean; theme?: string; }) => {
const [api, setApi] = React.useState<GridviewApi>();
const onReady = (event: GridviewReadyEvent) => {
@ -135,6 +135,7 @@ export const App: React.FC = (props: { theme?: string }) => {
onReady={onReady}
// proportionalLayout={false}
orientation={Orientation.VERTICAL}
isRtl={props.isRtl}
className={props.theme || 'dockview-theme-abyss'}
/>
</div>

View File

@ -61,7 +61,7 @@ const headerComponents = {
myHeaderComponent: MyHeaderComponent,
};
export const App: React.FC = (props: { theme?: string }) => {
export const App: React.FC = (props: { isRtl?: boolean; theme?: string; }) => {
const onReady = (event: PaneviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
@ -96,6 +96,7 @@ export const App: React.FC = (props: { theme?: string }) => {
components={components}
headerComponents={headerComponents}
onReady={onReady}
isRtl={props.isRtl}
className={props.theme || 'dockview-theme-abyss'}
/>
);

View File

@ -81,7 +81,7 @@ const Watermark = (props: IWatermarkPanelProps) => {
);
};
const DockviewWatermark = (props: { theme?: string }) => {
const DockviewWatermark = (props: { isRtl?: boolean; theme?: string; }) => {
const [api, setApi] = React.useState<DockviewApi>();
const onReady = (event: DockviewReadyEvent) => {
@ -126,6 +126,7 @@ const DockviewWatermark = (props: { theme?: string }) => {
onReady={onReady}
components={components}
watermarkComponent={Watermark}
isRtl={props.isRtl}
className={`${props.theme || 'dockview-theme-abyss'}`}
/>
</div>

View File

@ -12,7 +12,7 @@ const components = {
},
};
export const SimpleSplitview = (props: { proportional?: boolean }) => {
export const SimpleSplitview = (props: { isRtl?: boolean; proportional?: boolean }) => {
const onReady = (event: SplitviewReadyEvent) => {
event.api.addPanel({
id: 'panel_1',
@ -48,6 +48,7 @@ export const SimpleSplitview = (props: { proportional?: boolean }) => {
proportionalLayout={props.proportional}
onReady={onReady}
orientation={Orientation.HORIZONTAL}
isRtl={props.isRtl}
className="dockview-theme-abyss"
/>
);

View File

@ -149,6 +149,7 @@ export const MultiFrameworkContainer2 = (props: {
typescript?: (parent: HTMLElement) => { dispose: () => void };
sandboxId: string;
height?: number;
isRtl?: boolean;
hideThemePicker?: boolean;
}) => {
const ref = React.useRef<HTMLDivElement>(null);
@ -220,7 +221,7 @@ export const MultiFrameworkContainer2 = (props: {
<Spinner />
</div>
)}
{framework === 'React' && <props.react theme={theme} />}
{framework === 'React' && <props.react isRtl={props.isRtl} theme={theme} />}
</div>
<div
style={{
@ -281,6 +282,7 @@ export const MultiFrameworkContainer = (props: {
typescript?: (parent: HTMLElement) => { dispose: () => void };
sandboxId: string;
height?: number;
isRtl?: boolean;
hideThemePicker?: boolean;
}) => {
return (

View File

@ -2074,6 +2074,11 @@
"name": "watermarkComponent",
"signature": "FunctionComponent<IWatermarkPanelProps>",
"type": "property"
},
{
"name": "isRtl",
"signature": "boolean",
"type": "property"
}
],
"IGridviewReactProps": [
@ -2111,6 +2116,11 @@
"name": "proportionalLayout",
"signature": "boolean",
"type": "property"
},
{
"name": "isRtl",
"signature": "boolean",
"type": "property"
}
],
"IPaneviewReactProps": [
@ -2153,6 +2163,11 @@
"name": "onDidDrop",
"signature": "(event: PaneviewDropEvent): void",
"type": "method"
},
{
"name": "isRtl",
"signature": "boolean",
"type": "property"
}
],
"ISplitviewReactProps": [
@ -2192,4 +2207,4 @@
"type": "property"
}
]
}
}