@danxbot/ui 20.11.0 → 20.12.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.
@@ -0,0 +1,31 @@
1
+ import type { ReactNode, Ref } from "react";
2
+ import type { BlockStatus } from "../../lib/paged-window/layout";
3
+ export interface PageBlockProps {
4
+ page: number;
5
+ status: BlockStatus;
6
+ /** The cards of a `ready` page. Ignored for every other status: they have none to show. */
7
+ children?: ReactNode;
8
+ /** How many cards a `ready` page shows (`data-count`, which the pitch measurement reads). */
9
+ count: number;
10
+ /** The height the page holds when it has no cards: items on it x the measured item height. */
11
+ height: number;
12
+ /** One item's height, for the loading rows. */
13
+ pitch: number;
14
+ /** Ref callback that returns its cleanup: how the list's observers find this block. */
15
+ blockRef: Ref<HTMLDivElement>;
16
+ errorText: string;
17
+ retryText: string;
18
+ onRetry: () => void;
19
+ }
20
+ /**
21
+ * THE ONE ELEMENT A PAGE IS, in every state. A page turns from placeholder to
22
+ * cards (a load), to placeholder again (a drop) and to an error row and back
23
+ * without this element being replaced: it is the same component type at the same
24
+ * key, so React keeps the same DOM node. That is what keeps the browser's scroll
25
+ * anchoring on the element under the viewport and keeps the observers attached
26
+ * (visibility and pitch) instead of detaching and re-attaching on every change.
27
+ * What changes is only what it holds and how it is drawn: the cards of a ready
28
+ * page, otherwise the page's height (and, while loading, faint rows; on failure,
29
+ * a Retry row).
30
+ */
31
+ export declare function PageBlock({ page, status, children, count, height, pitch, blockRef, errorText, retryText, onRetry, }: PageBlockProps): import("react").JSX.Element;
@@ -113,10 +113,10 @@ export { DragDrop, DragDropContainer, DragDropItem, DragDropHandle, DragDropSurf
113
113
  export { KanbanBoard, type KanbanBoardProps, type KanbanLane, type KanbanMove, type KanbanRefusal, } from "./components/kanban/KanbanBoard";
114
114
  export { DEFAULT_DRAG_STRINGS, DRAG_INSTRUCTIONS_ID, DragInstructions, DragLiveRegion, DragSession, DragSessionProvider, applyMove, attachAutoScroll, attachKeyboardSensor, attachPointerSensor, attachSessionWindowListeners, isNoOp, resolveTarget, sameTarget, scrollVelocity, useCreateDragSession, useDragAnnouncements, useDragSession, useDragState, useDragLive, useDraggable, useDropContainer, type ContainerId, type DragAxis, type DragCancelEvent, type DragEndEvent, type DragId, type DragMode, type DragPhase, type DragSessionCallbacks, type DragStartEvent, type DragState, type AutoScrollOptions, type DragAnnouncementContext, type DragAnnouncementOptions, type DragAnnouncements, type DragInstructionsProps, type DragLiveRegionProps, type DragStrings, type DropTarget, type KeyboardSensorOptions, type PointerActivation, } from "./lib/dnd";
115
115
  export { Board, BoardColumn, BoardCard, BoardCardSurface, type BoardProps, type BoardColumnProps, type BoardCardProps, type BoardCardSurfaceProps, } from "./components/Board";
116
- export { buildBoardModel, resolveMove, applyBoardMoves, useBoard, moveAnchor, type BoardModel, type MoveAnchor, type UseBoardResult, } from "./lib/board";
116
+ export { buildBoardModel, resolveMove, applyBoardMoves, useBoard, moveAnchor, columnLength, positionInColumn, type BoardModel, type MoveAnchor, type UseBoardResult, } from "./lib/board";
117
117
  export type { BoardAccessors, BoardColumnDef, BoardEdge, BoardColumnId, BoardColumnModel, BoardItemId, BoardMove, BoardMoveRequest, BoardMoveSource, BoardMoveVerdict, UseBoardOptions, } from "./lib/board";
118
118
  export { PagedWindowList, type PagedWindowItemPosition, type PagedWindowListProps, type PagedWindowStrings, } from "./components/PagedWindowList";
119
- export { PagedWindowStore, usePagedWindow, windowPageNumbers, type LoadPage, type LoadPageContext, type PageResponse, type PageSnapshot, type PageStatus, type PagedWindow, type PagedWindowOptions, type PagedWindowSnapshot, type UsePagedWindowOptions, } from "./lib/paged-window";
119
+ export { PagedWindowStore, usePagedWindow, windowPageNumbers, type LoadCount, type LoadPage, type LoadPageContext, type PageResponse, type PageSnapshot, type PageStatus, type PagedWindow, type PagedWindowMode, type PagedWindowOptions, type PagedWindowSnapshot, type UsePagedWindowOptions, } from "./lib/paged-window";
120
120
  export type { MessageRole, MessagePart, TextPart, CodePart, ReasoningPart, ToolPart, ToolStatus, FilePart, ComponentPart, ChatFile, ChatMessage, RenderContext, PartRenderer, PartRenderers, ChatComponentRenderer, ChatComponents, } from "./components/chat/types";
121
121
  export { Chat, ChatPopover, type ChatProps, type ChatPopoverProps, type ChatSurface, } from "./components/chat/Chat";
122
122
  export { Message, MessagePartView, ToolCall, type MessageProps, type MessageAction, type MessagePartViewProps, type ToolCallProps, } from "./components/chat/Message";
@@ -10,26 +10,42 @@
10
10
  *
11
11
  * `to.index` counts the destination's LOADED cards with the moved card already
12
12
  * removed (the board's one index rule), so the card lands before
13
- * `rest[to.index]` and after `rest[to.index - 1]`, where `rest` is the
14
- * destination's loaded cards without the moved one. Either neighbour may be
15
- * absent: at the start of the loaded run there is nothing loaded above, at the
16
- * end nothing below, and an empty destination has neither. A server that is
17
- * given `beforeId` places the card directly above it; given only `afterId`,
18
- * directly below it; given neither, the destination was empty.
13
+ * `rest[to.index]`, where `rest` is the destination's loaded cards without the
14
+ * moved one. ONE neighbour is named, because a server places a card relative to
15
+ * one: the card it lands directly above (`beforeId`) whenever there is one, and
16
+ * only at the end of the loaded run, where nothing is below, the card it lands
17
+ * directly below (`afterId`). An empty destination names nothing.
19
18
  *
20
19
  * AN EDGE INTENT TRUMPS THE NEIGHBOURS. "Move to top" in a window that starts
21
20
  * at card 221 means the top of the column, which no loaded neighbour can say,
22
21
  * so the anchor carries the edge and no ids.
23
22
  */
24
23
  import type { BoardEdge, BoardItemId, BoardMove } from "./types";
25
- export interface MoveAnchor {
26
- /** The loaded card the moved card lands directly above. */
27
- beforeId?: BoardItemId;
28
- /** The loaded card the moved card lands directly below. */
29
- afterId?: BoardItemId;
30
- /** The moved card goes to the very top or bottom of the whole column; no ids are given. */
31
- edge?: BoardEdge;
32
- }
24
+ /**
25
+ * EXACTLY ONE placement field is set — a server's lane-move takes one — or none
26
+ * for an empty destination:
27
+ * beforeId the moved card lands directly above this loaded card
28
+ * afterId it lands directly below this one: only when it lands after the last
29
+ * loaded card, where nothing is below to name
30
+ * edge it goes to the very top or bottom of the whole column
31
+ */
32
+ export type MoveAnchor = {
33
+ beforeId: BoardItemId;
34
+ afterId?: never;
35
+ edge?: never;
36
+ } | {
37
+ afterId: BoardItemId;
38
+ beforeId?: never;
39
+ edge?: never;
40
+ } | {
41
+ edge: BoardEdge;
42
+ beforeId?: never;
43
+ afterId?: never;
44
+ } | {
45
+ beforeId?: never;
46
+ afterId?: never;
47
+ edge?: never;
48
+ };
33
49
  /**
34
50
  * @param destinationItems the destination column's LOADED cards (the moved card
35
51
  * may be among them, for a same-column move).
@@ -11,5 +11,6 @@
11
11
  export type { BoardAccessors, BoardColumnDef, BoardEdge, BoardColumnId, BoardColumnModel, BoardItemId, BoardMove, BoardMoveRequest, BoardMoveSource, BoardMoveVerdict, UseBoardOptions, } from "./types";
12
12
  export { buildBoardModel, type BoardModel } from "./model";
13
13
  export { moveAnchor, type MoveAnchor } from "./anchor";
14
+ export { columnLength, positionInColumn } from "./position";
14
15
  export { applyBoardMoves, resolveMove, type ResolveMoveContext, type ResolvedMove, } from "./move";
15
16
  export { useBoard, type UseBoardResult } from "./use-board";
@@ -146,6 +146,15 @@ export declare function resolveMove<T>(context: ResolveMoveContext<T>, request:
146
146
  * column membership on every subsequent `buildBoardModel` call, and
147
147
  * `buildBoardModel` only ever reads WITHIN-column order.
148
148
  *
149
+ * `to.edge` IS NOT APPLIED HERE. This arranges the cards it was given, and in a
150
+ * windowed column an edge move lands OUTSIDE the cards that are loaded — at the
151
+ * top or bottom of a list this function cannot see — so the index it would
152
+ * splice at is only the nearest loaded position, not the place the card is
153
+ * going. A consumer of a windowed column sends the move to its server (see
154
+ * `moveAnchor`) and re-reads the affected pages (`invalidateAll`); it does not
155
+ * apply an edge move locally. In a column with every card loaded the edge IS
156
+ * the index, and this function is exactly right.
157
+ *
149
158
  * NEVER WRITES A FIELD ON ANY ITEM — ONLY REPOSITIONS. `BoardAccessors` has
150
159
  * no setter, on purpose (the file header on `types.ts` — items are opaque),
151
160
  * so this function CANNOT change what `getColumnId` reports for a moved
@@ -0,0 +1,22 @@
1
+ /**
2
+ * ==== COLUMN POSITION ====
3
+ *
4
+ * Two facts about a column that three callers each need and must not each work
5
+ * out for themselves (DX-4540): how long the column really is, and where in the
6
+ * whole column a loaded card sits. A windowed column holds only a few pages of
7
+ * a longer list, so the cards loaded are not the column.
8
+ *
9
+ * `buildBoardModel` decides the length once (the model's `count`); `resolveMove`
10
+ * works from the column DEFINITIONS before any model exists and must decide
11
+ * "is this card already at that edge" with the same rule; and the move menu
12
+ * decides what to offer from a card's place in the column. All three read these.
13
+ */
14
+ import type { BoardColumnDef } from "./types";
15
+ /**
16
+ * The column's length: its `total` when the definition gave a number, otherwise
17
+ * the cards loaded (`total` absent means every card is loaded; `null` means the
18
+ * length is still being read, so the loaded cards are all that is known).
19
+ */
20
+ export declare function columnLength(def: Pick<BoardColumnDef, "total"> | undefined, loaded: number): number;
21
+ /** The place in the whole column of the loaded card at `index`: the window's offset plus the index. */
22
+ export declare function positionInColumn(def: Pick<BoardColumnDef, "offset"> | undefined, index: number): number;
@@ -0,0 +1,21 @@
1
+ import type { PageSnapshot } from "./store";
2
+ /**
3
+ * What a page's block is showing. One name for every case, so the list renders
4
+ * ONE kind of block and only this changes:
5
+ * ready the page's cards are shown
6
+ * loading held, its request is in flight
7
+ * error held, its request failed
8
+ * waiting held and ready, but past a hole in the loaded run — not shown until
9
+ * the page that closes the hole arrives (see the store header)
10
+ * unheld outside the window: empty space of the right height
11
+ */
12
+ export type BlockStatus = "ready" | "loading" | "error" | "waiting" | "unheld";
13
+ export declare function blockStatus<T>(held: PageSnapshot<T> | undefined): BlockStatus;
14
+ /**
15
+ * How many page blocks to render. One per page of the list; before the first
16
+ * response the length is unknown but page 0 is being asked for, and one block
17
+ * stands in for it, so a new query does not flash an empty list.
18
+ */
19
+ export declare function blockCountFor(pageCount: number, heldPageCount: number): number;
20
+ /** The height of a page's placeholder: the items it holds (the last page is short) times one item's height. */
21
+ export declare function placeholderHeight(page: number, pageSize: number, total: number, pitch: number): number;
@@ -76,6 +76,12 @@ export declare class PagedWindowStore<T> {
76
76
  private epoch;
77
77
  private nextToken;
78
78
  private countRequest;
79
+ /** Answers that arrived while frozen, applied in arrival order on thaw. */
80
+ private heldAnswers;
81
+ /** Pages whose refresh was asked for while frozen. */
82
+ private queuedPages;
83
+ /** The length's refresh (count mode) was asked for while frozen. */
84
+ private queuedCount;
79
85
  private countError;
80
86
  private snapshot;
81
87
  private listeners;
@@ -92,9 +98,12 @@ export declare class PagedWindowStore<T> {
92
98
  /** The viewer moved to another page. Ignored while frozen, applied on thaw. */
93
99
  setAnchorPage(page: number): void;
94
100
  /**
95
- * While true the window neither loads nor drops pages, whatever the anchor or
96
- * the total does. A drag needs it: the carried card is mounted in its page,
97
- * and dropping that page mid-drag would unmount the card and cancel the drag.
101
+ * While true nothing about the window changes: it neither loads nor drops
102
+ * pages, starts no refresh and applies no answer, whatever the anchor or the
103
+ * total does (all of it waits for the thaw). A drag needs it: the carried card
104
+ * is mounted in its page, and dropping that page mid-drag would unmount the
105
+ * card and cancel the drag. Only `reset()` ignores it — a query change is a
106
+ * different list.
98
107
  */
99
108
  setFrozen(frozen: boolean): void;
100
109
  /** `count` holds and requests no cards, only the length (see the file header). */
@@ -121,11 +130,18 @@ export declare class PagedWindowStore<T> {
121
130
  private wanted;
122
131
  /** Bring the held pages to the wanted ones — unless frozen, when that waits for the thaw. */
123
132
  private sync;
133
+ /** `force` is `reset()`'s alone: it brings the window to its (new) list even while frozen. */
134
+ private reconcile;
135
+ /** Everything the frozen window put off, in the order the header promises. */
136
+ private thaw;
124
137
  /** Start (or restart) a page's request; whatever was in flight is abandoned. */
125
138
  private request;
126
139
  private settle;
140
+ /** Record an answer on its page — no window change, no notification: callers sync once. */
141
+ private applyPage;
127
142
  private requestCount;
128
143
  private settleCount;
144
+ private applyCount;
129
145
  private abortCount;
130
146
  private dropAll;
131
147
  /**
@@ -16,6 +16,17 @@
16
16
  *
17
17
  * A change under half a pixel is not published: re-laying-out every placeholder
18
18
  * in a long list for sub-pixel drift is cost with no picture.
19
+ *
20
+ * NOTHING IS EVER RESET, AND THAT IS DELIBERATE. A new query (another sort, a
21
+ * different time range) lists the same kind of card, so what was learned about
22
+ * its height still holds; clearing it would snap every placeholder back to the
23
+ * estimate and make the first screen of the new query jump. The measurement is
24
+ * only a sizing aid for space no card occupies, and the mean keeps correcting
25
+ * itself from every page that is shown.
26
+ *
27
+ * A block whose size does not change when it turns from placeholder to cards
28
+ * (or back) fires no resize, so its reading is picked up at the next size change;
29
+ * a placeholder is sized from the estimate in the first place.
19
30
  */
20
31
  export declare function useMeasuredPitch(estimated: number): {
21
32
  pitch: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danxbot/ui",
3
- "version": "20.11.0",
3
+ "version": "20.12.1",
4
4
  "type": "module",
5
5
  "description": "Danxbot — a domain-agnostic React design system with motion as a first-class primitive.",
6
6
  "license": "MIT",
@@ -1,21 +0,0 @@
1
- import type { Ref } from "react";
2
- export interface PlaceholderBlockProps {
3
- page: number;
4
- /** `unheld` is a page outside the window: empty space of the right height. */
5
- status: "unheld" | "loading" | "error";
6
- /** The height of the page this stands for: items on it x the measured item height. */
7
- height: number;
8
- /** One item's height, for the loading rows. */
9
- pitch: number;
10
- /** Ref callback that returns its cleanup: how the list's observers find this block. */
11
- blockRef: Ref<HTMLDivElement>;
12
- errorText: string;
13
- retryText: string;
14
- onRetry: () => void;
15
- }
16
- /**
17
- * The block of a page that has no cards to show: a page outside the window, one
18
- * on its way, or one that failed. It holds the page's height either way, so the
19
- * scrollbar does not move when the cards arrive.
20
- */
21
- export declare function PlaceholderBlock({ page, status, height, pitch, blockRef, errorText, retryText, onRetry, }: PlaceholderBlockProps): import("react").JSX.Element;