@stll/ui 0.37.1 → 0.39.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 +40 -75
- package/dist/components/button.d.ts +1 -1
- package/dist/components/composer.d.ts +9 -1
- package/dist/components/composer.js +19 -2
- package/dist/components/copy-button.d.ts +19 -0
- package/dist/components/copy-button.js +64 -0
- package/dist/components/list.d.ts +58 -0
- package/dist/components/list.js +160 -0
- package/dist/components/menu.js +3 -3
- package/dist/components/search-field.d.ts +20 -0
- package/dist/components/search-field.js +53 -0
- package/dist/components/sidebar.d.ts +2 -2
- package/dist/components/workspace-shell.js +4 -4
- package/dist/icons.d.ts +2 -2
- package/dist/icons.js +2 -2
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/kanban/index.d.ts +2 -5
- package/dist/kanban/index.js +1 -4
- package/dist/kanban/subgroup-board.d.ts +2 -27
- package/dist/kanban/subgroup-board.js +1 -25
- package/dist/kanban/virtual-cell.d.ts +1 -18
- package/dist/kanban/virtual-cell.js +5 -47
- package/dist/lib/control-size.d.ts +1 -1
- package/dist/styles/theme.css +7 -0
- package/package.json +13 -5
- package/dist/kanban/sortable-edge.d.ts +0 -38
- package/dist/kanban/sortable-edge.js +0 -27
- package/dist/kanban/sortable-interactions.d.ts +0 -151
- package/dist/kanban/sortable-interactions.js +0 -527
- package/dist/kanban/sortable-interactions.logic.d.ts +0 -78
- package/dist/kanban/sortable-interactions.logic.js +0 -205
|
@@ -1,205 +0,0 @@
|
|
|
1
|
-
import { closestCorners, getFirstCollision, pointerWithin } from "@dnd-kit/core";
|
|
2
|
-
//#region src/kanban/sortable-interactions.logic.ts
|
|
3
|
-
const KANBAN_DROP_TARGET_TYPES = {
|
|
4
|
-
CELL: "kanban-cell",
|
|
5
|
-
ITEM: "kanban-item"
|
|
6
|
-
};
|
|
7
|
-
const isRecord = (value) => typeof value === "object" && value !== null;
|
|
8
|
-
const isUniqueIdentifier = (value) => typeof value === "string" || typeof value === "number";
|
|
9
|
-
const isCellPosition = (value) => isRecord(value) && typeof value["column"] === "number" && typeof value["lane"] === "number" && Number.isInteger(value["column"]) && Number.isInteger(value["lane"]) && value["column"] >= 0 && value["lane"] >= 0;
|
|
10
|
-
const isKanbanCellVirtualNavigation = (value) => isRecord(value) && (value["type"] === "static" || value["type"] === "virtual" && typeof value["requestScroll"] === "function");
|
|
11
|
-
const isKanbanCellDropData = (value) => isRecord(value) && value["type"] === KANBAN_DROP_TARGET_TYPES.CELL && Array.isArray(value["itemIds"]) && value["itemIds"].every(isUniqueIdentifier) && isKanbanCellVirtualNavigation(value["navigation"]) && isCellPosition(value["position"]);
|
|
12
|
-
const isKanbanItemDropData = (value) => {
|
|
13
|
-
if (!isRecord(value) || value["type"] !== KANBAN_DROP_TARGET_TYPES.ITEM) return false;
|
|
14
|
-
const navigation = value["navigation"];
|
|
15
|
-
const current = isRecord(navigation) ? navigation["current"] : void 0;
|
|
16
|
-
return isRecord(navigation) && isRecord(current) && (current["type"] === "idle" || (current["type"] === "ready" || current["type"] === "pending") && isUniqueIdentifier(current["targetId"]));
|
|
17
|
-
};
|
|
18
|
-
const getKanbanKeyboardTargetState = (value) => isKanbanItemDropData(value) ? value.navigation.current : void 0;
|
|
19
|
-
/**
|
|
20
|
-
* dnd-kit computes collisions while rendering but publishes the resulting drop
|
|
21
|
-
* target to its sensor context a render later, and resolves a drop from that
|
|
22
|
-
* published value. A drag that ends before the two agree, which every input
|
|
23
|
-
* can do because a single move produces a single render, drops the item on the
|
|
24
|
-
* previously published target.
|
|
25
|
-
*
|
|
26
|
-
* Keyboard navigation names its target outright, so it is compared directly: a
|
|
27
|
-
* pending target is still waiting for a virtual cell to mount an offscreen row
|
|
28
|
-
* and has produced no collision at all, and a ready one is only settled once it
|
|
29
|
-
* is the published target. Until then both the collisions and the published
|
|
30
|
-
* target still describe where the board was before the user navigated away.
|
|
31
|
-
*/
|
|
32
|
-
const isKanbanDropSettled = ({ active, collisions, over }) => {
|
|
33
|
-
const target = getKanbanKeyboardTargetState(active?.data.current);
|
|
34
|
-
if (target?.type === "pending") return false;
|
|
35
|
-
if (target?.type === "ready") return over?.id === target.targetId;
|
|
36
|
-
return getFirstCollision(collisions, "id") === (over?.id ?? null);
|
|
37
|
-
};
|
|
38
|
-
const clearKanbanKeyboardTarget = (value) => {
|
|
39
|
-
if (isKanbanItemDropData(value) && value.navigation.current.type !== "idle") value.navigation.current = { type: "idle" };
|
|
40
|
-
};
|
|
41
|
-
const getSortableData = (value) => {
|
|
42
|
-
if (!isRecord(value)) return null;
|
|
43
|
-
const sortable = value["sortable"];
|
|
44
|
-
if (!isRecord(sortable) || !isUniqueIdentifier(sortable["containerId"]) || typeof sortable["index"] !== "number" || !Number.isInteger(sortable["index"]) || !Array.isArray(sortable["items"]) || !sortable["items"].every(isUniqueIdentifier)) return null;
|
|
45
|
-
return {
|
|
46
|
-
containerId: sortable["containerId"],
|
|
47
|
-
index: sortable["index"],
|
|
48
|
-
items: sortable["items"]
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
const isKanbanDroppable = ({ data }) => {
|
|
52
|
-
const value = data.current;
|
|
53
|
-
return isKanbanCellDropData(value) || isKanbanItemDropData(value);
|
|
54
|
-
};
|
|
55
|
-
/**
|
|
56
|
-
* Pointer and touch input must be inside a registered board target. Once that
|
|
57
|
-
* boundary is established, closest corners gives stable ranking across cells.
|
|
58
|
-
*/
|
|
59
|
-
const KANBAN_BOARD_COLLISION_DETECTION = (args) => {
|
|
60
|
-
const boardContainers = args.droppableContainers.filter(isKanbanDroppable);
|
|
61
|
-
if (args.pointerCoordinates === null) {
|
|
62
|
-
const activeData = args.active.data.current;
|
|
63
|
-
if (isKanbanItemDropData(activeData)) {
|
|
64
|
-
if (activeData.navigation.current.type === "pending") return [];
|
|
65
|
-
if (activeData.navigation.current.type !== "ready") return closestCorners({
|
|
66
|
-
...args,
|
|
67
|
-
droppableContainers: boardContainers
|
|
68
|
-
});
|
|
69
|
-
const { targetId } = activeData.navigation.current;
|
|
70
|
-
return boardContainers.some(({ id }) => id === targetId) ? [{ id: targetId }] : [];
|
|
71
|
-
}
|
|
72
|
-
return closestCorners({
|
|
73
|
-
...args,
|
|
74
|
-
droppableContainers: boardContainers
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
const intersections = pointerWithin({
|
|
78
|
-
...args,
|
|
79
|
-
droppableContainers: boardContainers
|
|
80
|
-
});
|
|
81
|
-
if (intersections.length === 0) return [];
|
|
82
|
-
const intersectingIds = new Set(intersections.map((intersection) => intersection.id));
|
|
83
|
-
return closestCorners({
|
|
84
|
-
...args,
|
|
85
|
-
droppableContainers: boardContainers.filter(({ id }) => intersectingIds.has(id))
|
|
86
|
-
});
|
|
87
|
-
};
|
|
88
|
-
const getAdjacentCell = (cells, current, direction) => {
|
|
89
|
-
let columnOffset = 0;
|
|
90
|
-
let laneOffset = 0;
|
|
91
|
-
switch (direction) {
|
|
92
|
-
case "down":
|
|
93
|
-
laneOffset = 1;
|
|
94
|
-
break;
|
|
95
|
-
case "left":
|
|
96
|
-
columnOffset = -1;
|
|
97
|
-
break;
|
|
98
|
-
case "right":
|
|
99
|
-
columnOffset = 1;
|
|
100
|
-
break;
|
|
101
|
-
case "up": laneOffset = -1;
|
|
102
|
-
}
|
|
103
|
-
return cells.find(({ position }) => position.column === current.position.column + columnOffset && position.lane === current.position.lane + laneOffset);
|
|
104
|
-
};
|
|
105
|
-
const getKanbanKeyboardTarget = ({ activeId, cells, currentCellId, currentOverId, direction }) => {
|
|
106
|
-
const currentCell = cells.find(({ id }) => id === currentCellId);
|
|
107
|
-
if (currentCell === void 0) return;
|
|
108
|
-
const overIndex = currentCell.itemIds.indexOf(currentOverId);
|
|
109
|
-
const activeIndex = currentCell.itemIds.indexOf(activeId);
|
|
110
|
-
const currentIndex = overIndex !== -1 ? overIndex : activeIndex;
|
|
111
|
-
if (direction === "down" && currentIndex >= 0) {
|
|
112
|
-
const nextItem = currentCell.itemIds.at(currentIndex + 1);
|
|
113
|
-
if (nextItem !== void 0) return nextItem;
|
|
114
|
-
}
|
|
115
|
-
if (direction === "up" && currentIndex > 0) return currentCell.itemIds.at(currentIndex - 1);
|
|
116
|
-
const adjacentCell = getAdjacentCell(cells, currentCell, direction);
|
|
117
|
-
if (adjacentCell === void 0) return;
|
|
118
|
-
if (adjacentCell.itemIds.length === 0) return adjacentCell.id;
|
|
119
|
-
if (direction === "down") return adjacentCell.itemIds.at(0);
|
|
120
|
-
if (direction === "up") return adjacentCell.itemIds.at(-1);
|
|
121
|
-
const targetIndex = Math.max(currentIndex, 0);
|
|
122
|
-
return adjacentCell.itemIds.at(Math.min(targetIndex, adjacentCell.itemIds.length - 1)) ?? adjacentCell.id;
|
|
123
|
-
};
|
|
124
|
-
const getDirection = (code) => {
|
|
125
|
-
switch (code) {
|
|
126
|
-
case "ArrowDown": return "down";
|
|
127
|
-
case "ArrowLeft": return "left";
|
|
128
|
-
case "ArrowRight": return "right";
|
|
129
|
-
case "ArrowUp": return "up";
|
|
130
|
-
default: return null;
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
const getCellId = (container) => {
|
|
134
|
-
const data = container.data.current;
|
|
135
|
-
if (isKanbanCellDropData(data)) return container.id;
|
|
136
|
-
if (!isKanbanItemDropData(data)) return null;
|
|
137
|
-
return getSortableData(data)?.containerId ?? null;
|
|
138
|
-
};
|
|
139
|
-
/** Ordered two-dimensional navigation over item and empty-cell targets. */
|
|
140
|
-
const kanbanKeyboardCoordinates = (event, { active, context }) => {
|
|
141
|
-
const direction = getDirection(event.code);
|
|
142
|
-
if (direction === null) return;
|
|
143
|
-
event.preventDefault();
|
|
144
|
-
const cells = context.droppableContainers.getEnabled().filter(({ data }) => {
|
|
145
|
-
const value = data.current;
|
|
146
|
-
return isKanbanCellDropData(value);
|
|
147
|
-
}).flatMap((container) => {
|
|
148
|
-
const data = container.data.current;
|
|
149
|
-
return isKanbanCellDropData(data) ? [{
|
|
150
|
-
...data,
|
|
151
|
-
id: container.id
|
|
152
|
-
}] : [];
|
|
153
|
-
});
|
|
154
|
-
const activeData = context.active?.data.current;
|
|
155
|
-
const keyboardTarget = getKanbanKeyboardTargetState(activeData);
|
|
156
|
-
const overId = keyboardTarget?.type === "ready" ? keyboardTarget.targetId : context.over?.id ?? active;
|
|
157
|
-
const overContainer = context.droppableContainers.get(overId);
|
|
158
|
-
const activeContainer = context.droppableContainers.get(active);
|
|
159
|
-
const currentCellId = (overContainer && getCellId(overContainer)) ?? (activeContainer && getCellId(activeContainer));
|
|
160
|
-
if (currentCellId === null || currentCellId === void 0) return;
|
|
161
|
-
const targetId = getKanbanKeyboardTarget({
|
|
162
|
-
activeId: active,
|
|
163
|
-
cells,
|
|
164
|
-
currentCellId,
|
|
165
|
-
currentOverId: overId,
|
|
166
|
-
direction
|
|
167
|
-
});
|
|
168
|
-
if (targetId === void 0) return;
|
|
169
|
-
const targetNode = context.droppableContainers.get(targetId)?.node.current;
|
|
170
|
-
if (targetNode === null || targetNode === void 0) {
|
|
171
|
-
const targetCell = cells.find(({ itemIds }) => itemIds.includes(targetId));
|
|
172
|
-
if (isKanbanItemDropData(activeData) && targetCell?.navigation.type === "virtual") {
|
|
173
|
-
activeData.navigation.current = {
|
|
174
|
-
targetId,
|
|
175
|
-
type: "pending"
|
|
176
|
-
};
|
|
177
|
-
targetCell.navigation.requestScroll({
|
|
178
|
-
itemId: targetId,
|
|
179
|
-
type: "item"
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
const targetRect = context.droppableRects.get(targetId);
|
|
185
|
-
if (targetRect === void 0) return;
|
|
186
|
-
if (isKanbanItemDropData(activeData)) activeData.navigation.current = {
|
|
187
|
-
targetId,
|
|
188
|
-
type: "ready"
|
|
189
|
-
};
|
|
190
|
-
requestAnimationFrame(() => {
|
|
191
|
-
requestAnimationFrame(() => {
|
|
192
|
-
targetNode.scrollIntoView({
|
|
193
|
-
behavior: "instant",
|
|
194
|
-
block: "nearest",
|
|
195
|
-
inline: "nearest"
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
return {
|
|
200
|
-
x: targetRect.left,
|
|
201
|
-
y: targetRect.top
|
|
202
|
-
};
|
|
203
|
-
};
|
|
204
|
-
//#endregion
|
|
205
|
-
export { KANBAN_BOARD_COLLISION_DETECTION, KANBAN_DROP_TARGET_TYPES, clearKanbanKeyboardTarget, getKanbanKeyboardTarget, getKanbanKeyboardTargetState, isKanbanCellDropData, isKanbanDropSettled, kanbanKeyboardCoordinates };
|