@taskctrl/canvas-timeline 0.8.0 → 0.8.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.
@@ -19,3 +19,18 @@ export declare function resolveCanResize(item: Item, globalCanResize: false | 'l
19
19
  * falling through to the global value.
20
20
  */
21
21
  export declare function resolveCanMove(item: Item, globalCanMove: boolean): boolean;
22
+ /**
23
+ * Decide which interaction (if any) a pointer-down at `edge` should start for
24
+ * `item`, given the timeline-wide `canResize`/`canMove` props. Returns `null`
25
+ * when nothing is permitted — the caller then starts no interaction (no ghost)
26
+ * and shows no affordance (default cursor). Centralising this keeps the cursor
27
+ * and the interaction decision in lockstep.
28
+ *
29
+ * An item explicitly resize-locked per-item (`item.canResize === false`) has
30
+ * inert edges: grabbing an edge returns `null` rather than falling through to a
31
+ * move, so a user trying to resize a locked item sees no UI. This is scoped to
32
+ * the *explicit* per-item override — an item inheriting a global `canResize:
33
+ * false` (field undefined) keeps the move-only behaviour where the whole item,
34
+ * edges included, is draggable.
35
+ */
36
+ export declare function resolveInteractionMode(item: Item, edge: 'left' | 'right' | 'body', globalCanResize: false | 'left' | 'right' | 'both', globalCanMove: boolean): 'move' | 'resize-left' | 'resize-right' | null;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type { Group, Item, ItemBounds, ItemState, DrawHelpers, CanvasItemRenderer, CanvasGroupItemRenderer, DayStyle, RowStyle, Dependency, TimeRangeHighlight, TimelineTheme, MarkerConfig, CanvasTimelineProps, CanvasTimelineRef, CaptureOptions, } from './types';
1
+ export type { Group, Item, ItemBounds, ItemState, DrawHelpers, CanvasItemRenderer, CanvasGroupItemRenderer, DayStyle, RowStyle, Dependency, TimeRangeHighlight, TimelineTheme, MarkerConfig, InteractionInfo, CanvasTimelineProps, CanvasTimelineRef, CaptureOptions, } from './types';
2
2
  export { DEFAULT_THEME } from './types';
3
3
  export { CanvasTimeline } from './CanvasTimeline';
4
4
  export { HierarchyEngine } from './core/HierarchyEngine';
@@ -0,0 +1,26 @@
1
+ import type { Item, InteractionInfo } from '../types';
2
+ import type { ViewState } from '../core/ViewState';
3
+ import type { IntervalTree } from '../core/IntervalTree';
4
+ import type { HierarchyEngine } from '../core/HierarchyEngine';
5
+ import type { InteractionState } from './InteractionHandler';
6
+ /** The subset of props the snap helpers need. */
7
+ export interface SnapDeps {
8
+ canvasWidth: number;
9
+ dragSnap: number;
10
+ intervalTree: IntervalTree<Item>;
11
+ hierarchyEngine: HierarchyEngine;
12
+ }
13
+ /** Snapped new start time for a move, matching the pointer-up commit path:
14
+ * item-edge snap (start edge first, then end edge) with grid snap as fallback. */
15
+ export declare function snappedMoveStart(state: InteractionState, vs: ViewState, p: SnapDeps): number;
16
+ /** Snapped edge time for a resize, matching the pointer-up commit path: item-edge
17
+ * snap with grid-snap fallback, then hierarchy resize constraints. */
18
+ export declare function snappedResizeEdge(state: InteractionState, vs: ViewState, p: SnapDeps): {
19
+ edge: 'left' | 'right';
20
+ time: number;
21
+ };
22
+ /** Build the public InteractionInfo payload for the current drag/resize state. */
23
+ export declare function buildInteractionInfo(state: InteractionState, vs: ViewState, p: SnapDeps, pointer: {
24
+ x: number;
25
+ y: number;
26
+ }): InteractionInfo;
package/dist/types.d.ts CHANGED
@@ -107,6 +107,28 @@ export interface MarkerConfig {
107
107
  width: number;
108
108
  label?: string;
109
109
  }
110
+ /** Live state of an in-progress drag/resize, emitted via `onInteractionUpdate`.
111
+ * All times are the snapped values that will commit on drop (item-edge snap +
112
+ * grid snap, plus hierarchy resize constraints) — i.e. where the item will
113
+ * actually land, matching the snap guide. The consumer-supplied
114
+ * `moveResizeValidator` is NOT applied here (it may run per frame). */
115
+ export interface InteractionInfo {
116
+ itemId: number;
117
+ mode: 'move' | 'resize-left' | 'resize-right';
118
+ /** Set for resize interactions; which edge is being dragged. */
119
+ edge?: 'left' | 'right';
120
+ /** The headline time to display: the new start for `move`/`resize-left`, the
121
+ * new end for `resize-right`. */
122
+ time: number;
123
+ /** The item's snapped start time during this interaction. */
124
+ startTime: number;
125
+ /** The item's snapped end time during this interaction. */
126
+ endTime: number;
127
+ /** Pointer position in viewport coordinates (clientX/clientY), for
128
+ * positioning a `position: fixed` tooltip without further math. */
129
+ pointerX: number;
130
+ pointerY: number;
131
+ }
110
132
  export interface CanvasTimelineProps {
111
133
  groups: Group[];
112
134
  items: Item[];
@@ -148,6 +170,11 @@ export interface CanvasTimelineProps {
148
170
  /** Validate and optionally constrain move/resize. Return the (possibly modified) time. */
149
171
  moveResizeValidator?: (action: 'move' | 'resize', itemId: number, time: number, edge?: 'left' | 'right') => number;
150
172
  onItemHover?: (itemId: number | null, e: PointerEvent) => void;
173
+ /** Fires once per animation frame during an active drag/resize, then once with
174
+ * `null` when it ends. Intended for a live "current time" tooltip. This is a
175
+ * hot path: do NOT call setState here — mutate a ref'd DOM node's text/transform
176
+ * directly so neither the library nor your app re-renders per frame. */
177
+ onInteractionUpdate?: (info: InteractionInfo | null) => void;
151
178
  onCanvasDoubleClick?: (groupId: number, time: number) => void;
152
179
  onCanvasContextMenu?: (groupId: number, time: number, e: PointerEvent) => void;
153
180
  onTimeChange?: (start: number, end: number) => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taskctrl/canvas-timeline",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "High-performance canvas-based timeline component for React",
5
5
  "scripts": {
6
6
  "build": "rimraf ./dist && tsc && vite build",