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
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
* Resizable elements display "box with handles" in the `Halo` to change the size;
* Changed element sizes are captured and restored by `RestoreGeometry` command.
- Allow to customize link template separately for each link instead of only based on its link type IRI in `linkTemplateResolver` for `Canvas`.
- Add `EditorController.applyAuthoringChanges()` method to apply current authoring changes to the diagram (i.e. change entity data, delete relations, etc) and reset the change state to be empty.
- Support keyboard hotkeys for `LinkAction` components to act on a currently selected link.

#### ⏱ Performance
- **[💥Breaking]** Canvas widgets are not automatically updated when parent canvas is rendered to reduce unnecessary re-renders, and now require explicit subscriptions:
Expand Down Expand Up @@ -51,12 +51,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
* Change CSS class for default link template from `reactodia-default-link` to `reactodia-standard-link`.
- Move "expand/collapse on double click" global element behavior to `StandardEntity` and `ClassicEntity` implementation only.
- Add `setTemplateProperty()` utility function to easily set or unset template state property.
- Add `EditorController.applyAuthoringChanges()` method to apply current authoring changes to the diagram (i.e. change entity data, delete relations, etc) and reset the change state to be empty.

#### 🐛 Fixed
- Fix `HaloLink` and visual authoring link path highlight being rendered on top on elements by placing it onto `overLinkGeometry` widget layer instead.
- Fix element template state not being restored when ungrouping entities.
- Fix missing element decorations after re-importing the same diagram.
- Fix `DraggableHandle` to avoid using stale `onDragHandle` and `onEndDragHandle` prop values.
- Fix being able to execute disabled `SelectionAction` via keyboard hotkey.

#### 🔧 Maintenance
- Use small subset of [carbon design icons](https://github.com/carbon-design-system/carbon-icons) for various buttons.
Expand Down
6 changes: 4 additions & 2 deletions src/editor/overlayController.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,10 @@ export class OverlayController {
target.focus();
} else if (target instanceof Link) {
this.model.setSelection([target]);
canvas.focus();
} else if (target instanceof LinkVertex) {
this.model.setSelection([target.link]);
canvas.focus();
} else if (!target && triggerAsClick) {
this.model.setSelection([]);
this.hideDialog();
Expand Down Expand Up @@ -432,8 +434,8 @@ interface OverlayWithInternalApi {
interface OverlayControllerInternalApi {
readonly events: Events<OverlayControllerInternalEvents>;
readonly overlays: Set<OverlayReader>;
onCanvasPointerUp(event: CanvasPointerUpEvent): void;
onCanvasKeydown(event: CanvasKeyboardEvent): void;
readonly onCanvasPointerUp: (event: CanvasPointerUpEvent) => void;
readonly onCanvasKeydown: (event: CanvasKeyboardEvent) => void;
dialog: React.ReactElement<any> | null;
spinner: React.ReactElement<any> | null;
}
Expand Down
32 changes: 27 additions & 5 deletions src/widgets/linkAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { mapAbortedToNull } from '../coreUtils/async';
import {
useEventStore, useObservedProperty, useFrameDebouncedStore, useSyncStore,
} from '../coreUtils/hooks';
import type { HotkeyString } from '../coreUtils/hotkey';

import type { MetadataCanModifyRelation } from '../data/metadataProvider';

import { useCanvas } from '../diagram/canvasApi';
import { useCanvasHotkey } from '../diagram/canvasHotkey';
import { Link } from '../diagram/elements';
import { GraphStructure } from '../diagram/model';
import { HtmlSpinner } from '../diagram/spinner';
Expand Down Expand Up @@ -88,6 +90,12 @@ export interface LinkActionStyleProps {
* Title for the action button.
*/
title?: string;
/**
* Keyboard hotkey for the action when it's mounted.
*
* Passing `null` disables a default hotkey if there is one.
*/
hotkey?: HotkeyString | null;
}

/**
Expand Down Expand Up @@ -122,14 +130,21 @@ const CLASS_NAME = 'reactodia-link-action';
* @category Components
*/
export function LinkAction(props: LinkActionProps) {
const {dockSide, dockIndex, disabled, className, title, onSelect, onMouseDown, children} = props;
const {
dockSide, dockIndex, disabled, className, title, hotkey,
onSelect, onMouseDown, children,
} = props;

const {getPosition} = useLinkActionContext();
const actionKey = useCanvasHotkey(hotkey, disabled ? undefined : onSelect);
const titleWithHotkey = title && actionKey ? `${title} (${actionKey.text})` : title;

return (
<button role='button'
className={cx(className, CLASS_NAME)}
style={getPosition(dockSide, dockIndex)}
disabled={disabled}
title={title}
title={titleWithHotkey}
onClick={onSelect}
onMouseDown={onMouseDown}>
{children}
Expand Down Expand Up @@ -231,7 +246,12 @@ export function LinkActionEdit(props: LinkActionEditProps) {
*
* @see {@link LinkActionDelete}
*/
export interface LinkActionDeleteProps extends LinkActionStyleProps {}
export interface LinkActionDeleteProps extends LinkActionStyleProps {
/**
* @default "None+Delete"
*/
hotkey?: HotkeyString | null;
}

/**
* Link action component to delete the link.
Expand All @@ -257,7 +277,7 @@ export function LinkActionDelete(props: LinkActionDeleteProps) {
}

function LinkActionDeleteRelation(props: LinkActionDeleteProps & { link: RelationLink }) {
const {link, className, title, ...otherProps} = props;
const {link, className, title, hotkey, ...otherProps} = props;
const {model, editor, translation: t} = useWorkspace();

const canModify = useCanModifyLink(link, model, editor);
Expand Down Expand Up @@ -292,6 +312,7 @@ function LinkActionDeleteRelation(props: LinkActionDeleteProps & { link: Relatio
? t.text('link_action.delete_relation.title')
: t.text('link_action.delete_relation.title_disabled')
)}
hotkey={hotkey === undefined ? 'None+Delete' : hotkey}
disabled={!canModify.canDelete}
onSelect={() => editor.deleteRelation(link.data)}
/>
Expand Down Expand Up @@ -346,7 +367,7 @@ function isSourceOrTargetDeleted(state: AuthoringState, link: RelationLink): boo
}

function LinkActionDeleteAnnotation(props: LinkActionDeleteProps & { link: AnnotationLink }) {
const {link, className, title, ...otherProps} = props;
const {link, className, title, hotkey, ...otherProps} = props;
const {editor, translation: t} = useWorkspace();
return (
<LinkAction {...otherProps}
Expand All @@ -356,6 +377,7 @@ function LinkActionDeleteAnnotation(props: LinkActionDeleteProps & { link: Annot
`${CLASS_NAME}__delete`
)}
title={title ?? t.text('link_action.delete_annotation.title')}
hotkey={hotkey === undefined ? 'None+Delete' : hotkey}
onSelect={() => editor.removeItems([link])}
/>
);
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/selectionAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export function SelectionAction(props: SelectionActionProps) {
disabled, onSelect, onMouseDown, children,
} = props;

const actionKey = useCanvasHotkey(hotkey, onSelect);
const actionKey = useCanvasHotkey(hotkey, disabled ? undefined : onSelect);
const titleWithHotkey = title && actionKey ? `${title} (${actionKey.text})` : title;

return (
Expand Down