@hlang-tech/editor-ui 0.1.0 → 0.2.0

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 CHANGED
@@ -1,10 +1,10 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/hlang-tech/hlang/main/media/logo.png" width="88" alt="hlang">
2
+ <img src="https://raw.githubusercontent.com/hlang-tech/hlang/main/media/brand/packages/editor-ui.png" alt="hlang editor-ui" width="100%">
3
3
  </p>
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, image and intent nodes, live edges, and the panels around the canvas.
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
  [![npm](https://img.shields.io/npm/v/@hlang-tech/editor-ui?color=c8ccd4&labelColor=0f1114)](https://www.npmjs.com/package/@hlang-tech/editor-ui)
10
10
  [![license](https://img.shields.io/npm/l/@hlang-tech/editor-ui?color=c8ccd4&labelColor=0f1114)](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
- declare function useEditorHotkeys(core: EditorCore): void;
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, type AssetGridProps, type AssetItem, AssetNodeChrome, type AssetNodeChromeProps, CanvasChrome, type CanvasChromeProps, CanvasDock, type CanvasDockProps, type CanvasMode, Cheatsheet, type CheatsheetProps, type ConnectableResult, type ContextMenuItem, DiagnosticBadge, type DiagnosticBadgeProps, type EdgeIndexEntry, EditorShell, type EditorShellProps, EditorUIThemeProvider, type EditorUIThemeProviderProps, EmptyState, type EmptyStateProps, FlowEdge, type FuzzyCandidate, type FuzzyMatch, type FuzzyResult, type HlangFlowTypes, HlangNode, InspectorPanel, type InspectorPanelProps, KIND_ROLE, KIND_TOKEN, LiveSignalProvider, type LiveSignalProviderProps, LiveSignalStore, type LiveSignalStoreDeps, NodeBodySlot, type NodeBodySlotProps, type NodeCandidate, NodeChrome, type NodeChromeProps, NodeContextMenu, type NodeContextMenuController, type NodeContextMenuProps, type NodeContextMenuState, type NodeInteraction, NodeInteractionProvider, type NodeInteractionProviderProps, type NodeLiveState, type NodeParamsHandle, NodeSearch, type NodeSearchController, type NodeSearchProps, type NodeSearchResult, type NodeSearchResultView, type NodeSearchState, type NodeSearchTriggerOptions, type NodeSearchTriggers, OutlineTree, type OutlineTreeProps, type ParamField, type ParamFieldBase, ParamForm, type ParamFormProps, type PendingConnection, PillNodeChrome, type PillNodeChromeProps, PortRow, type PortRowProps, PositionPanel, type PositionPanelProps, PreviewPanel, type PreviewPanelProps, type RailTab, RailTabs, type RailTabsProps, RunButton, type RunButtonProps, type ShortcutGroup, type ShortcutRow, SignalBar, TOKEN_NAMES, type ThemeOverride, type ToastApi, ToastProvider, type ToastProviderProps, type TokenName, ToolCluster, type ToolClusterProps, type ToolItem, Toolbar, ToolbarGhostButton, type ToolbarProps, ToolbarStat, UndoRedo, type UndoRedoProps, connectableCandidates, createHlangFlowTypes, createTheme, deriveParamSchema, descriptorCandidates, fuzzyRank, fuzzyScore, isEditableTarget, searchNodes, tokenVar, useEdgeFlowing, useEditorHotkeys, useLiveSignalStore, useLiveSignals, useNodeContextMenu, useNodeInteraction, useNodeLiveState, useNodeParams, useNodeSearch, useNodeSearchTriggers, useToast };
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
- declare function useEditorHotkeys(core: EditorCore): void;
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, type AssetGridProps, type AssetItem, AssetNodeChrome, type AssetNodeChromeProps, CanvasChrome, type CanvasChromeProps, CanvasDock, type CanvasDockProps, type CanvasMode, Cheatsheet, type CheatsheetProps, type ConnectableResult, type ContextMenuItem, DiagnosticBadge, type DiagnosticBadgeProps, type EdgeIndexEntry, EditorShell, type EditorShellProps, EditorUIThemeProvider, type EditorUIThemeProviderProps, EmptyState, type EmptyStateProps, FlowEdge, type FuzzyCandidate, type FuzzyMatch, type FuzzyResult, type HlangFlowTypes, HlangNode, InspectorPanel, type InspectorPanelProps, KIND_ROLE, KIND_TOKEN, LiveSignalProvider, type LiveSignalProviderProps, LiveSignalStore, type LiveSignalStoreDeps, NodeBodySlot, type NodeBodySlotProps, type NodeCandidate, NodeChrome, type NodeChromeProps, NodeContextMenu, type NodeContextMenuController, type NodeContextMenuProps, type NodeContextMenuState, type NodeInteraction, NodeInteractionProvider, type NodeInteractionProviderProps, type NodeLiveState, type NodeParamsHandle, NodeSearch, type NodeSearchController, type NodeSearchProps, type NodeSearchResult, type NodeSearchResultView, type NodeSearchState, type NodeSearchTriggerOptions, type NodeSearchTriggers, OutlineTree, type OutlineTreeProps, type ParamField, type ParamFieldBase, ParamForm, type ParamFormProps, type PendingConnection, PillNodeChrome, type PillNodeChromeProps, PortRow, type PortRowProps, PositionPanel, type PositionPanelProps, PreviewPanel, type PreviewPanelProps, type RailTab, RailTabs, type RailTabsProps, RunButton, type RunButtonProps, type ShortcutGroup, type ShortcutRow, SignalBar, TOKEN_NAMES, type ThemeOverride, type ToastApi, ToastProvider, type ToastProviderProps, type TokenName, ToolCluster, type ToolClusterProps, type ToolItem, Toolbar, ToolbarGhostButton, type ToolbarProps, ToolbarStat, UndoRedo, type UndoRedoProps, connectableCandidates, createHlangFlowTypes, createTheme, deriveParamSchema, descriptorCandidates, fuzzyRank, fuzzyScore, isEditableTarget, searchNodes, tokenVar, useEdgeFlowing, useEditorHotkeys, useLiveSignalStore, useLiveSignals, useNodeContextMenu, useNodeInteraction, useNodeLiveState, useNodeParams, useNodeSearch, useNodeSearchTriggers, useToast };
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 nodrag",
640
- onClick: (e) => {
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 useEditorHotkeys(core) {
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