@danxbot/ui 3.6.0 → 3.7.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/dist/index.js +10662 -10367
- package/dist/index.js.map +1 -1
- package/dist/types/components/Menu.d.ts +33 -0
- package/dist/types/components/kanban/KanbanBoard.d.ts +47 -1
- package/dist/types/components/kanban/recipe.d.ts +24 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/lib/dnd/geometry.d.ts +54 -6
- package/dist/types/lib/dnd/index.d.ts +1 -1
- package/dist/types/lib/use-fill-height.d.ts +26 -0
- package/package.json +1 -1
|
@@ -55,3 +55,36 @@ export declare function MenuGroup({ label, children }: MenuGroupProps): import("
|
|
|
55
55
|
export declare function MenuSeparator({ className }: {
|
|
56
56
|
className?: string;
|
|
57
57
|
}): import("react").JSX.Element;
|
|
58
|
+
export interface MenuSubProps {
|
|
59
|
+
/** The row that opens it — reads like a MenuItem and carries a trailing caret. */
|
|
60
|
+
label: ReactNode;
|
|
61
|
+
/** Optional leading icon, matching `MenuItem`'s own slot. */
|
|
62
|
+
icon?: ReactNode;
|
|
63
|
+
disabled?: boolean;
|
|
64
|
+
className?: string;
|
|
65
|
+
children: ReactNode;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* A nested menu that flies out beside its parent.
|
|
69
|
+
*
|
|
70
|
+
* WHY THIS IS A COMPONENT AND NOT A FLAT GROUP. `MenuGroup` renders its items
|
|
71
|
+
* inline under a label, which is right for two or three related actions and
|
|
72
|
+
* wrong the moment the group is a SET YOU PICK FROM — teams, workspaces,
|
|
73
|
+
* projects. Inline, that set pushes every other item down the menu, grows
|
|
74
|
+
* without bound as the account gains members, and puts a one-of-many choice at
|
|
75
|
+
* the same visual weight as "Sign out". A submenu keeps the parent menu a fixed
|
|
76
|
+
* size and says, correctly, that the thing behind this row is a list.
|
|
77
|
+
*
|
|
78
|
+
* OPENING IS HOVER *AND* KEYBOARD, which Base UI gives us: pointer-over opens
|
|
79
|
+
* after its own small delay, ArrowRight/Enter opens from the keyboard, and
|
|
80
|
+
* ArrowLeft/Escape closes back to the parent. Building this from a nested
|
|
81
|
+
* `Menu` would lose all of it — an inner Root gets its own trigger semantics
|
|
82
|
+
* and its own focus scope, so keyboard users end up in a popup the parent does
|
|
83
|
+
* not know it owns.
|
|
84
|
+
*
|
|
85
|
+
* It is positioned `side="right"` with a small negative `alignOffset` so the
|
|
86
|
+
* first child row sits level with the row that opened it; Base UI flips it to
|
|
87
|
+
* the left edge on its own when there is no room, which is the case a hard
|
|
88
|
+
* `left` would get wrong on a narrow window.
|
|
89
|
+
*/
|
|
90
|
+
export declare function MenuSub({ label, icon, disabled, className, children }: MenuSubProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
2
|
import type { DragSessionCallbacks } from "../../lib/dnd";
|
|
3
|
+
import { type DragDropProps } from "../DragDrop";
|
|
3
4
|
import type { KanbanLane, KanbanMove, KanbanRefusal } from "./types";
|
|
4
5
|
export type { KanbanLane, KanbanMove, KanbanRefusal };
|
|
5
6
|
export interface KanbanBoardProps<T> extends Omit<DragSessionCallbacks, "onDragEnd"> {
|
|
@@ -40,6 +41,51 @@ export interface KanbanBoardProps<T> extends Omit<DragSessionCallbacks, "onDragE
|
|
|
40
41
|
onRefuse?: (refusal: KanbanRefusal) => void;
|
|
41
42
|
/** Shown in a lane with no cards. */
|
|
42
43
|
emptyLane?: ReactNode;
|
|
44
|
+
/**
|
|
45
|
+
* Override any part of the announcement grammar — `DragDrop.strings`, reached
|
|
46
|
+
* through the board.
|
|
47
|
+
*
|
|
48
|
+
* IT WAS UNREACHABLE, and the omission had a symptom. The default sentence is
|
|
49
|
+
* `… Position 1 of 4 in ${containerLabel}`, which reads correctly right up
|
|
50
|
+
* until a lane is called "In review" and a screen reader says "in In review".
|
|
51
|
+
* That is a property of the lane's NAME rather than of the template, so there
|
|
52
|
+
* is no template this component could ship that is right for every board —
|
|
53
|
+
* which is precisely why the engine exposes the grammar, and precisely why a
|
|
54
|
+
* board that swallowed the prop left its consumer with no way out of a
|
|
55
|
+
* sentence they could hear was wrong. Rename the lane, or write the sentence:
|
|
56
|
+
*
|
|
57
|
+
* ```tsx
|
|
58
|
+
* strings={{ picked: (c) => `Picked up ${c.label}, ${c.containerLabel} column.` }}
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
strings?: DragDropProps["strings"];
|
|
62
|
+
/**
|
|
63
|
+
* Fill the space between the board's own top and the bottom of whatever
|
|
64
|
+
* scrolls it, so the lanes are the only thing that scrolls down.
|
|
65
|
+
*
|
|
66
|
+
* `true` — the default, and what a board IS. It was not the default until
|
|
67
|
+
* 3.7.0, and the reason is worth keeping: the height was expressed purely as
|
|
68
|
+
* a `flex-1 min-h-0` chain, which is correct and is correct only while every
|
|
69
|
+
* ancestor cooperates. One ordinary page wrapper above the board — a bare
|
|
70
|
+
* `<div className="flex flex-col gap-10">`, which is this package's own demo
|
|
71
|
+
* layout — makes `flex-1` inert, the board sizes to its tallest lane, and the
|
|
72
|
+
* PAGE takes the scrollbar that was supposed to belong to a column. Reported
|
|
73
|
+
* from a running board: "the columns should fill to the full remaining height
|
|
74
|
+
* of the page. No scroll bar vertically. Only scroll vertically per column."
|
|
75
|
+
*
|
|
76
|
+
* The height is MEASURED (`lib/use-fill-height`), not computed from a token,
|
|
77
|
+
* and re-measured whenever anything above the board changes size. It is
|
|
78
|
+
* paired with `max-h-full`, so an ancestor that genuinely does bound the board
|
|
79
|
+
* still wins and a board in a short box does not overflow it.
|
|
80
|
+
*
|
|
81
|
+
* `false` — the board is as tall as the box it is given, or as its tallest
|
|
82
|
+
* lane if nothing gives it one. For a board deliberately sized by its
|
|
83
|
+
* container (`h-[60dvh]`, a fixed-height card) or embedded in a page that is
|
|
84
|
+
* meant to scroll as a document.
|
|
85
|
+
*
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
88
|
+
fill?: boolean;
|
|
43
89
|
className?: string;
|
|
44
90
|
}
|
|
45
|
-
export declare function KanbanBoard<T>({ label, lanes, getItemId, itemLabel, renderItem, renderDragging, onMove, onRefuse, emptyLane, className, ...callbacks }: KanbanBoardProps<T>): import("react").JSX.Element;
|
|
91
|
+
export declare function KanbanBoard<T>({ label, lanes, getItemId, itemLabel, renderItem, renderDragging, onMove, onRefuse, emptyLane, strings, fill, className, ...callbacks }: KanbanBoardProps<T>): import("react").JSX.Element;
|
|
@@ -5,6 +5,14 @@ export declare const kanban: import("tailwind-variants").TVReturnType<{
|
|
|
5
5
|
};
|
|
6
6
|
false: {};
|
|
7
7
|
};
|
|
8
|
+
fill: {
|
|
9
|
+
true: {
|
|
10
|
+
root: string;
|
|
11
|
+
};
|
|
12
|
+
false: {
|
|
13
|
+
root: string;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
8
16
|
}, {
|
|
9
17
|
root: string;
|
|
10
18
|
lane: string;
|
|
@@ -22,6 +30,14 @@ export declare const kanban: import("tailwind-variants").TVReturnType<{
|
|
|
22
30
|
};
|
|
23
31
|
false: {};
|
|
24
32
|
};
|
|
33
|
+
fill: {
|
|
34
|
+
true: {
|
|
35
|
+
root: string;
|
|
36
|
+
};
|
|
37
|
+
false: {
|
|
38
|
+
root: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
25
41
|
}, {
|
|
26
42
|
root: string;
|
|
27
43
|
lane: string;
|
|
@@ -39,6 +55,14 @@ export declare const kanban: import("tailwind-variants").TVReturnType<{
|
|
|
39
55
|
};
|
|
40
56
|
false: {};
|
|
41
57
|
};
|
|
58
|
+
fill: {
|
|
59
|
+
true: {
|
|
60
|
+
root: string;
|
|
61
|
+
};
|
|
62
|
+
false: {
|
|
63
|
+
root: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
42
66
|
}, {
|
|
43
67
|
root: string;
|
|
44
68
|
lane: string;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export { Checkbox, Switch, Radio, RadioGroup, CheckboxField, SwitchField, RadioF
|
|
|
28
28
|
export { Dialog, DialogClose, AlertDialog, type DialogProps, type AlertDialogProps, } from "./components/Dialog";
|
|
29
29
|
export { Popover, PopoverClose, Tooltip, TooltipProvider, type PopoverProps, type TooltipProps, } from "./components/Popover";
|
|
30
30
|
export { Toaster, ToastProvider, useToast, type ToasterProps, type ToastProviderProps, type ToastOptions, type ToastTone, } from "./components/Toast";
|
|
31
|
-
export { Menu, MenuItem, MenuGroup, MenuRadioGroup, MenuRadioItem, MenuSeparator, type MenuProps, type MenuItemProps, type MenuGroupProps, type MenuRadioGroupProps, type MenuRadioItemProps, } from "./components/Menu";
|
|
31
|
+
export { Menu, MenuItem, MenuGroup, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, type MenuProps, type MenuItemProps, type MenuGroupProps, type MenuRadioGroupProps, type MenuRadioItemProps, type MenuSubProps, } from "./components/Menu";
|
|
32
32
|
export { ThemeMenu, type ThemeMenuProps } from "./components/ThemeMenu";
|
|
33
33
|
export { AppShell, type AppShellProps, type NavItem, type NavSection, } from "./components/AppShell";
|
|
34
34
|
export { FileUpload, type FileUploadProps, type UploadFile } from "./components/FileUpload";
|
|
@@ -90,6 +90,7 @@ export { ModelSelector, type ModelSelectorProps, type ChatModel, } from "./compo
|
|
|
90
90
|
export { EffortControl, DEFAULT_EFFORT_LEVELS, type EffortControlProps, type EffortLevel, } from "./components/chat/EffortControl";
|
|
91
91
|
export { ContextMeter, ChatStatus, formatTokens, type ContextMeterProps, type ContextSegment, type UsageLimit, type ChatStatusProps, } from "./components/chat/ContextMeter";
|
|
92
92
|
export { cn } from "./lib/cn";
|
|
93
|
+
export { useFillHeight } from "./lib/use-fill-height";
|
|
93
94
|
export { useTheme, useUiScale, useContrast, useMotionPreference, type Theme, type UiScale, type ContrastPreference, type MotionPreference, } from "./lib/preferences";
|
|
94
95
|
export { usePersistedState, readStored, writeStored, clearStored, storageKey, type PersistedStateOptions, } from "./lib/persist";
|
|
95
96
|
export { CalendarMonth, type CalendarMonthProps } from "./components/calendar/CalendarMonth";
|
|
@@ -21,6 +21,37 @@ export declare function measure(items: Iterable<ItemRegistration>, containers: I
|
|
|
21
21
|
* the innermost one.
|
|
22
22
|
*/
|
|
23
23
|
export declare function containerAt(snapshot: LayoutSnapshot, point: Point): ContainerRect | null;
|
|
24
|
+
/**
|
|
25
|
+
* The container CLOSEST to the pointer, for a pointer that is inside none of
|
|
26
|
+
* them.
|
|
27
|
+
*
|
|
28
|
+
* THE DEAD ZONE IS THE BUG THIS EXISTS FOR, AND IT IS MOST OF A BOARD. The
|
|
29
|
+
* registered container is the SCROLLER — it has to be, so auto-scroll can find
|
|
30
|
+
* its edges — and on a kanban lane the scroller is only the card list. The lane
|
|
31
|
+
* header above it, the lane's own border, the gutter between two lanes and the
|
|
32
|
+
* board's bottom padding are all outside every registered rect, so a pointer
|
|
33
|
+
* there is "over no container" while being unmistakably over a lane to the
|
|
34
|
+
* person holding the card.
|
|
35
|
+
*
|
|
36
|
+
* What used to happen there was `resolveTarget` returning null and the session
|
|
37
|
+
* keeping the PREVIOUS target — so a card dragged from lane 1 and released on
|
|
38
|
+
* lane 3's header landed in lane 2, the lane the pointer had last crossed on
|
|
39
|
+
* its way. Measured in the demo before this change: released at (1022, 419),
|
|
40
|
+
* visually the middle of "Review" whose lane box is 878–1166 × 407–939, the
|
|
41
|
+
* card landed in "Building". Not an edge case — the header is 60px of every
|
|
42
|
+
* lane's top, and a person aiming at an empty lane aims at its label.
|
|
43
|
+
*
|
|
44
|
+
* SCOPED, so "nearest" cannot mean "somewhere else entirely": the snapshot
|
|
45
|
+
* holds one `DragDrop` root's own containers and nothing else — every root
|
|
46
|
+
* builds its own `DragSession` (`use-drag.ts`) with its own registry. The
|
|
47
|
+
* nearest container to a point over the sidebar is still a lane of the board
|
|
48
|
+
* being dragged, which is the only answer a release can sensibly have.
|
|
49
|
+
*
|
|
50
|
+
* TIES GO TO THE SMALLER BOX, matching `containerAt` — a point in the gutter
|
|
51
|
+
* between two lanes is equidistant from both, and a nested container is the
|
|
52
|
+
* more specific answer for the same reason it is there.
|
|
53
|
+
*/
|
|
54
|
+
export declare function nearestContainer(snapshot: LayoutSnapshot, point: Point): ContainerRect | null;
|
|
24
55
|
/** A container's items in reading order, excluding the one being carried. */
|
|
25
56
|
export declare function remainingItems(snapshot: LayoutSnapshot, container: string, dragged: DragId | null): ItemRect[];
|
|
26
57
|
/**
|
|
@@ -41,12 +72,29 @@ export declare function indexAt(snapshot: LayoutSnapshot, container: ContainerRe
|
|
|
41
72
|
/**
|
|
42
73
|
* Where the dragged item would land if released at `point`.
|
|
43
74
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
75
|
+
* THE POINTER IS OVER THE CONTAINER IT IS NEAREST TO, not only the one whose
|
|
76
|
+
* rectangle happens to hold it. Both halves of that matter and the second one
|
|
77
|
+
* is the fix:
|
|
78
|
+
*
|
|
79
|
+
* The goal has always been that dragging a card briefly outside the board must
|
|
80
|
+
* not make the insertion marker vanish, and that a release outside every
|
|
81
|
+
* container still lands somewhere rather than reading as a silently failed
|
|
82
|
+
* drag. That was served by returning null here and having the session keep the
|
|
83
|
+
* PREVIOUS target — which achieves "the marker does not blink out" and gets
|
|
84
|
+
* "lands where you are pointing" exactly backwards. The gap between two lanes,
|
|
85
|
+
* a lane's header, a lane's border and the board's own bottom padding are all
|
|
86
|
+
* outside every registered rect; a release in any of them landed the card in
|
|
87
|
+
* the last lane the pointer had crossed, which for a drag from lane 1 to lane 3
|
|
88
|
+
* is lane 2. See `nearestContainer` for the measurement.
|
|
89
|
+
*
|
|
90
|
+
* Nearest keeps the marker alive for the same reason last-target did, and puts
|
|
91
|
+
* it where the person is aiming rather than where they have been.
|
|
92
|
+
*
|
|
93
|
+
* STILL NULL FOR A BOARD WITH NO CONTAINERS AT ALL — there is no nearest one,
|
|
94
|
+
* and the session's `?? s.over` remains the guard for that.
|
|
95
|
+
*
|
|
96
|
+
* The index then falls out of `indexAt` without a special case: a point above a
|
|
97
|
+
* lane is before every card in it, a point below is after all of them.
|
|
50
98
|
*/
|
|
51
99
|
export declare function resolveTarget(snapshot: LayoutSnapshot, point: Point, dragged: DragId | null): DropTarget | null;
|
|
52
100
|
/** Value equality — targets are recreated on every move, so `===` is useless. */
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* empty icon registry (CAV-11).
|
|
8
8
|
*/
|
|
9
9
|
export type { ContainerId, ContainerRect, ContainerRegistration, DragAxis, DragCancelEvent, DragEndEvent, DragId, DragMode, DragPhase, DragSessionCallbacks, DragStartEvent, DragState, DropTarget, ItemRect, ItemRegistration, LayoutSnapshot, Point, } from "./types";
|
|
10
|
-
export { applyMove, containerAt, indexAt, isNoOp, measure, remainingItems, resolveTarget, sameTarget, } from "./geometry";
|
|
10
|
+
export { applyMove, containerAt, indexAt, isNoOp, measure, nearestContainer, remainingItems, resolveTarget, sameTarget, } from "./geometry";
|
|
11
11
|
export { DragSession, type StartArgs } from "./session";
|
|
12
12
|
export { attachPointerSensor, attachSessionWindowListeners, type PointerActivation, type PointerSensorOptions, } from "./sensors/pointer";
|
|
13
13
|
export { attachKeyboardSensor, type KeyboardSensorOptions, } from "./sensors/keyboard";
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type RefCallback } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Size an element to the space between its own top and the bottom of the box
|
|
4
|
+
* that scrolls it, and keep it sized as the page changes around it.
|
|
5
|
+
*
|
|
6
|
+
* Returns a ref callback for the element. The height is written as inline style
|
|
7
|
+
* rather than returned as state on purpose — a returned number would re-render
|
|
8
|
+
* the subtree on every resize frame, and the value is only ever consumed by one
|
|
9
|
+
* property on one element.
|
|
10
|
+
*
|
|
11
|
+
* ```tsx
|
|
12
|
+
* const fillRef = useFillHeight(fill);
|
|
13
|
+
* <div ref={fillRef} className="max-h-full …" />
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* WHAT IT WATCHES, and why that list rather than a global observer. The number
|
|
17
|
+
* changes when a box ABOVE the element changes size: the scrollport itself, an
|
|
18
|
+
* ancestor between the two, or a sibling laid out before it. All three are
|
|
19
|
+
* observed. The element itself is deliberately NOT observed — it is the thing
|
|
20
|
+
* being written, and observing it is the loop.
|
|
21
|
+
*
|
|
22
|
+
* A sibling ADDED after mount is the known gap: the observer set is built once
|
|
23
|
+
* per attach. In practice the content above a filling element is a page header,
|
|
24
|
+
* not a live list, and a `key`ed remount covers the rest.
|
|
25
|
+
*/
|
|
26
|
+
export declare function useFillHeight(enabled?: boolean): RefCallback<HTMLElement>;
|