@hlang-tech/editor-ui 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/canvas/CanvasDock.css +27 -0
- package/lib/index.d.mts +16 -3
- package/lib/index.d.ts +16 -3
- package/lib/index.js +22 -11
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +22 -11
- package/lib/index.mjs.map +1 -1
- package/lib/overlays/Cheatsheet.css +13 -6
- package/lib/overlays/Toast.css +7 -2
- package/lib/shell/EditorShell.css +3 -0
- package/lib/tokens/tokens.css +1 -1
- package/package.json +4 -5
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# @hlang-tech/editor-ui
|
|
6
6
|
|
|
7
|
-
The Lumen design system for hlang: React components for a node editor built on React Flow and [`@hlang-tech/editor-react`](https://www.npmjs.com/package/@hlang-tech/editor-react). Black and silver surfaces,
|
|
7
|
+
The Lumen design system for hlang: React components for a node editor built on React Flow and [`@hlang-tech/editor-react`](https://www.npmjs.com/package/@hlang-tech/editor-react). Black and silver surfaces, pill and asset node chrome, live edges, and the panels around the canvas. It is generic: products add their own node types through its extension points.
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/@hlang-tech/editor-ui)
|
|
10
10
|
[](https://github.com/hlang-tech/hlang/blob/main/LICENSE)
|
|
@@ -12,7 +12,7 @@ The Lumen design system for hlang: React components for a node editor built on R
|
|
|
12
12
|
> **Status:** 0.x, in active development. The API can change in any minor release.
|
|
13
13
|
|
|
14
14
|
<p align="center">
|
|
15
|
-
<img src="https://raw.githubusercontent.com/hlang-tech/hlang/main/media/lumen-editor.png" alt="The Lumen editor built with editor-ui" width="100%">
|
|
15
|
+
<img src="https://raw.githubusercontent.com/hlang-tech/hlang/main/media/lumen-editor.png" alt="The Lumen editor built with editor-ui, running a flow of generic stream nodes" width="100%">
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
## Install
|
|
@@ -80,3 +80,30 @@
|
|
|
80
80
|
.hl-dock-zoom:hover {
|
|
81
81
|
background: rgba(255, 255, 255, 0.07);
|
|
82
82
|
}
|
|
83
|
+
|
|
84
|
+
/* A narrow canvas (a phone, or an editor embedded in a column) gets a tighter
|
|
85
|
+
dock. Below 400px the zoom readout is the one fit-view control. */
|
|
86
|
+
@container hl-canvas (max-width: 460px) {
|
|
87
|
+
.hl-dock {
|
|
88
|
+
bottom: 12px;
|
|
89
|
+
gap: 1px;
|
|
90
|
+
padding: 4px;
|
|
91
|
+
}
|
|
92
|
+
.hl-dock-btn {
|
|
93
|
+
width: 30px;
|
|
94
|
+
height: 30px;
|
|
95
|
+
}
|
|
96
|
+
.hl-dock-zoom {
|
|
97
|
+
min-width: 42px;
|
|
98
|
+
height: 30px;
|
|
99
|
+
padding: 0 6px;
|
|
100
|
+
}
|
|
101
|
+
.hl-dock-sep {
|
|
102
|
+
margin: 0 2px;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
@container hl-canvas (max-width: 400px) {
|
|
106
|
+
.hl-dock-fit {
|
|
107
|
+
display: none;
|
|
108
|
+
}
|
|
109
|
+
}
|
package/lib/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NodeKind, EditorNode, PortDescriptor, EditorCore, NodeId, Diagnostic, ParamValue, NodeDescriptor, ParamBag, Endpoint, IConnectionValidator, Point, IExecutionHandle } from '@hlang-tech/editor-core';
|
|
2
|
-
import { CSSProperties, ReactNode, ReactElement, MouseEvent } from 'react';
|
|
2
|
+
import { CSSProperties, ReactNode, ReactElement, MouseEvent, RefObject } from 'react';
|
|
3
3
|
import { NodeProps, EdgeProps, NodeTypes, EdgeTypes, OnConnectStart, OnConnectEnd } from '@xyflow/react';
|
|
4
4
|
import { HlangRFNode, HlangRFEdge } from '@hlang-tech/editor-react';
|
|
5
5
|
|
|
@@ -735,11 +735,23 @@ declare function useNodeSearchTriggers(core: EditorCore, search: NodeSearchContr
|
|
|
735
735
|
* service. Every action is a proper command, so it is itself undoable. The
|
|
736
736
|
* listener is on `window` but SUPPRESSED while a text input / textarea /
|
|
737
737
|
* contenteditable is focused, so typing never triggers a canvas action.
|
|
738
|
+
*
|
|
739
|
+
* When the editor is one part of a larger page, pass `scope`: shortcuts then
|
|
740
|
+
* fire only for keystrokes whose target is inside that element, and every other
|
|
741
|
+
* keystroke (copying page text, Backspace in a page control) is left untouched.
|
|
738
742
|
*/
|
|
739
743
|
|
|
740
744
|
/** True when focus is in an editable field, where shortcuts must NOT fire. */
|
|
741
745
|
declare function isEditableTarget(target: EventTarget | null): boolean;
|
|
742
|
-
|
|
746
|
+
interface EditorHotkeysOptions {
|
|
747
|
+
/**
|
|
748
|
+
* The element that owns the shortcuts. When given, only keystrokes whose
|
|
749
|
+
* target is inside it are handled; while it is not mounted, none are.
|
|
750
|
+
* Omit it when the editor fills the page.
|
|
751
|
+
*/
|
|
752
|
+
readonly scope?: RefObject<HTMLElement | null>;
|
|
753
|
+
}
|
|
754
|
+
declare function useEditorHotkeys(core: EditorCore, options?: EditorHotkeysOptions): void;
|
|
743
755
|
|
|
744
756
|
/**
|
|
745
757
|
* `useNodeContextMenu` — controller for the right-click node menu. Holds only
|
|
@@ -968,4 +980,5 @@ declare function useNodeLiveState(nodeId: string): NodeLiveState;
|
|
|
968
980
|
/** Subscribe to a single edge's flowing state. False when no store is present. */
|
|
969
981
|
declare function useEdgeFlowing(edgeId: string): boolean;
|
|
970
982
|
|
|
971
|
-
export { AssetGrid,
|
|
983
|
+
export { AssetGrid, AssetNodeChrome, CanvasChrome, CanvasDock, Cheatsheet, DiagnosticBadge, EditorShell, EditorUIThemeProvider, EmptyState, FlowEdge, HlangNode, InspectorPanel, KIND_ROLE, KIND_TOKEN, LiveSignalProvider, LiveSignalStore, NodeBodySlot, NodeChrome, NodeContextMenu, NodeInteractionProvider, NodeSearch, OutlineTree, ParamForm, PillNodeChrome, PortRow, PositionPanel, PreviewPanel, RailTabs, RunButton, SignalBar, TOKEN_NAMES, ToastProvider, ToolCluster, Toolbar, ToolbarGhostButton, ToolbarStat, UndoRedo, connectableCandidates, createHlangFlowTypes, createTheme, deriveParamSchema, descriptorCandidates, fuzzyRank, fuzzyScore, isEditableTarget, searchNodes, tokenVar, useEdgeFlowing, useEditorHotkeys, useLiveSignalStore, useLiveSignals, useNodeContextMenu, useNodeInteraction, useNodeLiveState, useNodeParams, useNodeSearch, useNodeSearchTriggers, useToast };
|
|
984
|
+
export type { AssetGridProps, AssetItem, AssetNodeChromeProps, CanvasChromeProps, CanvasDockProps, CanvasMode, CheatsheetProps, ConnectableResult, ContextMenuItem, DiagnosticBadgeProps, EdgeIndexEntry, EditorHotkeysOptions, EditorShellProps, EditorUIThemeProviderProps, EmptyStateProps, FuzzyCandidate, FuzzyMatch, FuzzyResult, HlangFlowTypes, InspectorPanelProps, LiveSignalProviderProps, LiveSignalStoreDeps, NodeBodySlotProps, NodeCandidate, NodeChromeProps, NodeContextMenuController, NodeContextMenuProps, NodeContextMenuState, NodeInteraction, NodeInteractionProviderProps, NodeLiveState, NodeParamsHandle, NodeSearchController, NodeSearchProps, NodeSearchResult, NodeSearchResultView, NodeSearchState, NodeSearchTriggerOptions, NodeSearchTriggers, OutlineTreeProps, ParamField, ParamFieldBase, ParamFormProps, PendingConnection, PillNodeChromeProps, PortRowProps, PositionPanelProps, PreviewPanelProps, RailTab, RailTabsProps, RunButtonProps, ShortcutGroup, ShortcutRow, ThemeOverride, ToastApi, ToastProviderProps, TokenName, ToolClusterProps, ToolItem, ToolbarProps, UndoRedoProps };
|
package/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { NodeKind, EditorNode, PortDescriptor, EditorCore, NodeId, Diagnostic, ParamValue, NodeDescriptor, ParamBag, Endpoint, IConnectionValidator, Point, IExecutionHandle } from '@hlang-tech/editor-core';
|
|
2
|
-
import { CSSProperties, ReactNode, ReactElement, MouseEvent } from 'react';
|
|
2
|
+
import { CSSProperties, ReactNode, ReactElement, MouseEvent, RefObject } from 'react';
|
|
3
3
|
import { NodeProps, EdgeProps, NodeTypes, EdgeTypes, OnConnectStart, OnConnectEnd } from '@xyflow/react';
|
|
4
4
|
import { HlangRFNode, HlangRFEdge } from '@hlang-tech/editor-react';
|
|
5
5
|
|
|
@@ -735,11 +735,23 @@ declare function useNodeSearchTriggers(core: EditorCore, search: NodeSearchContr
|
|
|
735
735
|
* service. Every action is a proper command, so it is itself undoable. The
|
|
736
736
|
* listener is on `window` but SUPPRESSED while a text input / textarea /
|
|
737
737
|
* contenteditable is focused, so typing never triggers a canvas action.
|
|
738
|
+
*
|
|
739
|
+
* When the editor is one part of a larger page, pass `scope`: shortcuts then
|
|
740
|
+
* fire only for keystrokes whose target is inside that element, and every other
|
|
741
|
+
* keystroke (copying page text, Backspace in a page control) is left untouched.
|
|
738
742
|
*/
|
|
739
743
|
|
|
740
744
|
/** True when focus is in an editable field, where shortcuts must NOT fire. */
|
|
741
745
|
declare function isEditableTarget(target: EventTarget | null): boolean;
|
|
742
|
-
|
|
746
|
+
interface EditorHotkeysOptions {
|
|
747
|
+
/**
|
|
748
|
+
* The element that owns the shortcuts. When given, only keystrokes whose
|
|
749
|
+
* target is inside it are handled; while it is not mounted, none are.
|
|
750
|
+
* Omit it when the editor fills the page.
|
|
751
|
+
*/
|
|
752
|
+
readonly scope?: RefObject<HTMLElement | null>;
|
|
753
|
+
}
|
|
754
|
+
declare function useEditorHotkeys(core: EditorCore, options?: EditorHotkeysOptions): void;
|
|
743
755
|
|
|
744
756
|
/**
|
|
745
757
|
* `useNodeContextMenu` — controller for the right-click node menu. Holds only
|
|
@@ -968,4 +980,5 @@ declare function useNodeLiveState(nodeId: string): NodeLiveState;
|
|
|
968
980
|
/** Subscribe to a single edge's flowing state. False when no store is present. */
|
|
969
981
|
declare function useEdgeFlowing(edgeId: string): boolean;
|
|
970
982
|
|
|
971
|
-
export { AssetGrid,
|
|
983
|
+
export { AssetGrid, AssetNodeChrome, CanvasChrome, CanvasDock, Cheatsheet, DiagnosticBadge, EditorShell, EditorUIThemeProvider, EmptyState, FlowEdge, HlangNode, InspectorPanel, KIND_ROLE, KIND_TOKEN, LiveSignalProvider, LiveSignalStore, NodeBodySlot, NodeChrome, NodeContextMenu, NodeInteractionProvider, NodeSearch, OutlineTree, ParamForm, PillNodeChrome, PortRow, PositionPanel, PreviewPanel, RailTabs, RunButton, SignalBar, TOKEN_NAMES, ToastProvider, ToolCluster, Toolbar, ToolbarGhostButton, ToolbarStat, UndoRedo, connectableCandidates, createHlangFlowTypes, createTheme, deriveParamSchema, descriptorCandidates, fuzzyRank, fuzzyScore, isEditableTarget, searchNodes, tokenVar, useEdgeFlowing, useEditorHotkeys, useLiveSignalStore, useLiveSignals, useNodeContextMenu, useNodeInteraction, useNodeLiveState, useNodeParams, useNodeSearch, useNodeSearchTriggers, useToast };
|
|
984
|
+
export type { AssetGridProps, AssetItem, AssetNodeChromeProps, CanvasChromeProps, CanvasDockProps, CanvasMode, CheatsheetProps, ConnectableResult, ContextMenuItem, DiagnosticBadgeProps, EdgeIndexEntry, EditorHotkeysOptions, EditorShellProps, EditorUIThemeProviderProps, EmptyStateProps, FuzzyCandidate, FuzzyMatch, FuzzyResult, HlangFlowTypes, InspectorPanelProps, LiveSignalProviderProps, LiveSignalStoreDeps, NodeBodySlotProps, NodeCandidate, NodeChromeProps, NodeContextMenuController, NodeContextMenuProps, NodeContextMenuState, NodeInteraction, NodeInteractionProviderProps, NodeLiveState, NodeParamsHandle, NodeSearchController, NodeSearchProps, NodeSearchResult, NodeSearchResultView, NodeSearchState, NodeSearchTriggerOptions, NodeSearchTriggers, OutlineTreeProps, ParamField, ParamFieldBase, ParamFormProps, PendingConnection, PillNodeChromeProps, PortRowProps, PositionPanelProps, PreviewPanelProps, RailTab, RailTabsProps, RunButtonProps, ShortcutGroup, ShortcutRow, ThemeOverride, ToastApi, ToastProviderProps, TokenName, ToolClusterProps, ToolItem, ToolbarProps, UndoRedoProps };
|
package/lib/index.js
CHANGED
|
@@ -636,9 +636,8 @@ function PillNodeChrome({ node, selected }) {
|
|
|
636
636
|
) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
637
637
|
"span",
|
|
638
638
|
{
|
|
639
|
-
className: "hl-pill-name
|
|
640
|
-
onClick: (
|
|
641
|
-
e.stopPropagation();
|
|
639
|
+
className: "hl-pill-name",
|
|
640
|
+
onClick: () => {
|
|
642
641
|
onNameClick();
|
|
643
642
|
},
|
|
644
643
|
title: "Double-click to rename",
|
|
@@ -962,7 +961,7 @@ function CanvasDock({
|
|
|
962
961
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "hl-dock-btn", onClick: onZoomOut, title: "Zoom out", "aria-label": "Zoom out", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "hl-dock-glyph", children: "\u2212" }) }),
|
|
963
962
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "hl-dock-zoom hl-mono", onClick: onFitView, title: "Fit view", children: pct }),
|
|
964
963
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "hl-dock-btn", onClick: onZoomIn, title: "Zoom in", "aria-label": "Zoom in", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "hl-dock-glyph", children: "+" }) }),
|
|
965
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "hl-dock-btn", onClick: onFitView, title: "Fit view", "aria-label": "Fit view", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FitIcon, {}) })
|
|
964
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { className: "hl-dock-btn hl-dock-fit", onClick: onFitView, title: "Fit view", "aria-label": "Fit view", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FitIcon, {}) })
|
|
966
965
|
] });
|
|
967
966
|
}
|
|
968
967
|
|
|
@@ -1967,11 +1966,19 @@ function isEditableTarget(target) {
|
|
|
1967
1966
|
const tag = target.tagName;
|
|
1968
1967
|
return tag === "INPUT" || tag === "TEXTAREA" || target.isContentEditable;
|
|
1969
1968
|
}
|
|
1970
|
-
function
|
|
1969
|
+
function withinScope(target, scope) {
|
|
1970
|
+
if (scope === void 0) {
|
|
1971
|
+
return true;
|
|
1972
|
+
}
|
|
1973
|
+
const root = scope.current;
|
|
1974
|
+
return root !== null && target instanceof Node && root.contains(target);
|
|
1975
|
+
}
|
|
1976
|
+
function useEditorHotkeys(core, options = {}) {
|
|
1971
1977
|
const clipboard = (0, import_editor_react5.useClipboard)(core);
|
|
1978
|
+
const { scope } = options;
|
|
1972
1979
|
(0, import_react15.useEffect)(() => {
|
|
1973
1980
|
const onKeyDown = (event) => {
|
|
1974
|
-
if (isEditableTarget(event.target)) {
|
|
1981
|
+
if (!withinScope(event.target, scope) || isEditableTarget(event.target)) {
|
|
1975
1982
|
return;
|
|
1976
1983
|
}
|
|
1977
1984
|
const mod = event.metaKey || event.ctrlKey;
|
|
@@ -2028,7 +2035,7 @@ function useEditorHotkeys(core) {
|
|
|
2028
2035
|
return () => {
|
|
2029
2036
|
window.removeEventListener("keydown", onKeyDown);
|
|
2030
2037
|
};
|
|
2031
|
-
}, [core, clipboard]);
|
|
2038
|
+
}, [core, clipboard, scope]);
|
|
2032
2039
|
}
|
|
2033
2040
|
|
|
2034
2041
|
// src/context-menu/NodeContextMenu.tsx
|
|
@@ -2256,10 +2263,14 @@ function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }) {
|
|
|
2256
2263
|
] }),
|
|
2257
2264
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "hl-cheat-grid", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("section", { className: "hl-cheat-group", children: [
|
|
2258
2265
|
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h3", { className: "hl-cheat-group-title hl-mono", children: group.title }),
|
|
2259
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "hl-cheat-rows", children: group.rows.map((row) =>
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2266
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("ul", { className: "hl-cheat-rows", children: group.rows.map((row) => (
|
|
2267
|
+
// A row is a binding: one action can have several (two ways to pan),
|
|
2268
|
+
// so neither the label nor the keys alone identify it.
|
|
2269
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("li", { className: "hl-cheat-row", children: [
|
|
2270
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("span", { className: "hl-cheat-label", children: row.label }),
|
|
2271
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("kbd", { className: "hl-cheat-keys hl-mono", children: row.keys })
|
|
2272
|
+
] }, `${row.keys}\0${row.label}`)
|
|
2273
|
+
)) })
|
|
2263
2274
|
] }, group.title)) })
|
|
2264
2275
|
]
|
|
2265
2276
|
}
|