@cloud-ru/ds-list 1.0.0 → 1.1.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.
Files changed (34) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.js +8 -9
  3. package/dist/cjs/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.js +3 -1
  4. package/dist/cjs/components/Items/SimpleItem/components/SimpleItem/SimpleItem.js +10 -8
  5. package/dist/cjs/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.js +6 -1
  6. package/dist/cjs/components/Items/SimpleItem/styles.module.css +7 -25
  7. package/dist/cjs/components/Items/SimpleItem/utils.d.ts +2 -1
  8. package/dist/cjs/components/Items/SimpleItem/utils.js +2 -1
  9. package/dist/cjs/components/Lists/ListPrivate/ListPrivate.js +2 -2
  10. package/dist/cjs/constants.d.ts +1 -0
  11. package/dist/cjs/constants.js +1 -0
  12. package/dist/cjs/style.css +7 -25
  13. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.js +8 -9
  14. package/dist/esm/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.js +3 -1
  15. package/dist/esm/components/Items/SimpleItem/components/SimpleItem/SimpleItem.js +10 -5
  16. package/dist/esm/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.js +6 -1
  17. package/dist/esm/components/Items/SimpleItem/styles.module.css +7 -25
  18. package/dist/esm/components/Items/SimpleItem/utils.d.ts +2 -1
  19. package/dist/esm/components/Items/SimpleItem/utils.js +2 -1
  20. package/dist/esm/components/Lists/ListPrivate/ListPrivate.js +2 -2
  21. package/dist/esm/constants.d.ts +1 -0
  22. package/dist/esm/constants.js +1 -0
  23. package/dist/esm/style.css +7 -25
  24. package/dist/tsconfig.cjs.tsbuildinfo +1 -1
  25. package/dist/tsconfig.esm.tsbuildinfo +1 -1
  26. package/package.json +3 -2
  27. package/src/components/Items/SimpleItem/components/SimpleGroupBlock/SimpleGroupBlock.tsx +8 -16
  28. package/src/components/Items/SimpleItem/components/SimpleGroupBlockOverlay/SimpleGroupBlockOverlay.tsx +13 -8
  29. package/src/components/Items/SimpleItem/components/SimpleItem/SimpleItem.tsx +10 -5
  30. package/src/components/Items/SimpleItem/components/SimpleItemOverlay/SimpleItemOverlay.tsx +10 -3
  31. package/src/components/Items/SimpleItem/styles.module.scss +8 -45
  32. package/src/components/Items/SimpleItem/utils.ts +2 -1
  33. package/src/components/Lists/ListPrivate/ListPrivate.tsx +4 -2
  34. package/src/constants.ts +1 -0
package/CHANGELOG.md CHANGED
@@ -3,6 +3,12 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # 1.1.0 (2026-08-18)
7
+
8
+ ### Features
9
+
10
+ - **FF-8802:** add common drag&drop state ([0cefbc2](https://github.com/cloud-ru-tech/snack-v2/commit/0cefbc2609aa84b110d63c55618f6c00c454c80f))
11
+
6
12
  # 1.0.0 (2026-08-18)
7
13
 
8
14
  Initial stable release under the `@cloud-ru/ds-*` scope.
@@ -5,10 +5,10 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SimpleGroupBlock = SimpleGroupBlock;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
- const core_1 = require("@dnd-kit/core");
9
8
  const sortable_1 = require("@dnd-kit/sortable");
10
9
  const utilities_1 = require("@dnd-kit/utilities");
11
10
  const bottom_sheet_1 = require("@cloud-ru/ds-bottom-sheet");
11
+ const drag_and_drop_1 = require("@cloud-ru/ds-drag-and-drop");
12
12
  const helperComponents_1 = require("../../../../../helperComponents");
13
13
  const utils_1 = require("../../../../../utils");
14
14
  const contexts_1 = require("../../../../Lists/contexts");
@@ -31,12 +31,6 @@ function SimpleGroupBlock({ id, rowIds, children, ...separatorProps }) {
31
31
  data: { container: constants_1.REORDER_TOP_LEVEL },
32
32
  animateLayoutChanges: utils_2.animateLayoutChanges,
33
33
  });
34
- // Идёт ли переупорядочивание строки этой группы (а не самой группы). Оно жёстко ограничено
35
- // своим контейнером (`container === id` в `data` строки, см. `SimpleItem`), поэтому границы
36
- // блока группы подсвечиваются — видно, что строка не выходит за пределы группы, а не «сломалась».
37
- const { active } = (0, core_1.useDndContext)();
38
- const activeContainer = active?.data.current?.container;
39
- const isReorderingWithinGroup = active != null && active.id !== id && activeContainer === id;
40
34
  const style = {
41
35
  transform: utilities_1.CSS.Translate.toString(transform),
42
36
  transition,
@@ -46,7 +40,12 @@ function SimpleGroupBlock({ id, rowIds, children, ...separatorProps }) {
46
40
  (0, utils_1.stopPropagation)(e);
47
41
  onMouseDown?.(e);
48
42
  };
49
- return ((0, jsx_runtime_1.jsxs)("div", { ref: setNodeRef, style: style, className: styles_module_scss_1.default.groupBlock, "data-dragging": isDragging || undefined, "data-reorder-boundary": isReorderingWithinGroup || undefined, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.groupHeader, "data-size": size, children: [(0, jsx_runtime_1.jsx)(DragHandle_1.DragHandle
43
+ // Динамический перенос тот же, что у строк (`SimpleItem`).
44
+ return ((0, jsx_runtime_1.jsxs)(drag_and_drop_1.DragGhost, { innerRef: setNodeRef, style: style, dragging: isDragging, mode: drag_and_drop_1.DRAG_MODE.Dynamic, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.groupHeader, "data-size": size, children: [(0, jsx_runtime_1.jsx)(DragHandle_1.DragHandle
50
45
  // Pointer-жест не доходит до BottomSheet: иначе vertical drag одновременно закрывает sheet.
51
- , { [bottom_sheet_1.NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners, onMouseDown: handleMouseDown, onClick: utils_1.stopPropagation }), (0, jsx_runtime_1.jsx)(helperComponents_1.Separator, { ...separatorProps })] }), (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, { items: rowIds, strategy: sortable_1.verticalListSortingStrategy, children: children })] }));
46
+ , { [bottom_sheet_1.NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners,
47
+ // `useSortable` ставит ручке tabIndex=0, но список ведёт свою roving-навигацию и
48
+ // перехватывает Tab (см. `useNewKeyboardNavigation`) — с ручки было некуда уйти.
49
+ // Убираем её из таб-порядка: строка остаётся доступной с клавиатуры, ручка — мышью.
50
+ tabIndex: -1, onMouseDown: handleMouseDown, onClick: utils_1.stopPropagation }), (0, jsx_runtime_1.jsx)(helperComponents_1.Separator, { ...separatorProps })] }), (0, jsx_runtime_1.jsx)(sortable_1.SortableContext, { items: rowIds, strategy: sortable_1.verticalListSortingStrategy, children: children })] }));
52
51
  }
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SimpleGroupBlockOverlay = SimpleGroupBlockOverlay;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const drag_and_drop_1 = require("@cloud-ru/ds-drag-and-drop");
9
+ const constants_1 = require("../../../../../constants");
8
10
  const helperComponents_1 = require("../../../../../helperComponents");
9
11
  const styles_module_scss_1 = __importDefault(require('../../styles.module.css'));
10
12
  const OverlayDragHandle_1 = require("../OverlayDragHandle");
@@ -15,5 +17,5 @@ const SimpleItemOverlay_1 = require("../SimpleItemOverlay");
15
17
  * подгоняет обёртку под размеры активного узла (весь блок), поэтому одним заголовком её не заполнить.
16
18
  */
17
19
  function SimpleGroupBlockOverlay({ size, rows, ...separatorProps }) {
18
- return ((0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.groupBlock, "data-overlay": true, children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.groupHeader, "data-size": size, children: [(0, jsx_runtime_1.jsx)(OverlayDragHandle_1.OverlayDragHandle, {}), (0, jsx_runtime_1.jsx)(helperComponents_1.Separator, { ...separatorProps })] }), rows.map(row => ((0, jsx_runtime_1.jsx)(SimpleItemOverlay_1.SimpleItemOverlay, { ...row, bare: true }, row.id)))] }));
20
+ return ((0, jsx_runtime_1.jsx)(drag_and_drop_1.DragPreview, { className: styles_module_scss_1.default.dragPreview, "data-test-id": constants_1.TEST_IDS.dragOverlay, children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsxs)("div", { className: styles_module_scss_1.default.groupHeader, "data-size": size, children: [(0, jsx_runtime_1.jsx)(OverlayDragHandle_1.OverlayDragHandle, {}), (0, jsx_runtime_1.jsx)(helperComponents_1.Separator, { ...separatorProps })] }), rows.map(row => ((0, jsx_runtime_1.jsx)(SimpleItemOverlay_1.SimpleItemOverlay, { ...row, bare: true }, row.id)))] }) }));
19
21
  }
@@ -1,17 +1,14 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
3
  exports.SimpleItem = SimpleItem;
7
4
  const jsx_runtime_1 = require("react/jsx-runtime");
8
5
  const sortable_1 = require("@dnd-kit/sortable");
9
6
  const utilities_1 = require("@dnd-kit/utilities");
10
7
  const bottom_sheet_1 = require("@cloud-ru/ds-bottom-sheet");
8
+ const drag_and_drop_1 = require("@cloud-ru/ds-drag-and-drop");
11
9
  const utils_1 = require("../../../../../utils");
12
10
  const BaseItem_1 = require("../../../BaseItem");
13
11
  const constants_1 = require("../../constants");
14
- const styles_module_scss_1 = __importDefault(require('../../styles.module.css'));
15
12
  const utils_2 = require("../../utils");
16
13
  const DragHandle_1 = require("../DragHandle");
17
14
  /**
@@ -26,8 +23,8 @@ function SimpleItem({ id, disabled, groupId, ...option }) {
26
23
  // `disabled` на строке отключает `Switch` и клик (`BaseItem`), но не переупорядочивание:
27
24
  // ручка всегда активна.
28
25
  // `container` читает кастомный `collisionDetection` в `ListPrivate`: drop разрешён только внутри
29
- // одного контейнера. Строка без группы (`groupId` пуст) лежит в общем контейнере верхнего уровня
30
- // вместе с группами (можно менять местами строку и группу); строка группы — в контейнере группы.
26
+ // одного контейнера. Строка без группы (`groupId` пуст) лежит в контейнере верхнего уровня,
27
+ // строка группы — в контейнере своей группы.
31
28
  data: { container: groupId ?? constants_1.REORDER_TOP_LEVEL },
32
29
  animateLayoutChanges: utils_2.animateLayoutChanges,
33
30
  });
@@ -42,7 +39,12 @@ function SimpleItem({ id, disabled, groupId, ...option }) {
42
39
  (0, utils_1.stopPropagation)(e);
43
40
  onMouseDown?.(e);
44
41
  };
45
- return ((0, jsx_runtime_1.jsx)("div", { ref: setNodeRef, style: style, className: styles_module_scss_1.default.item, "data-dragging": isDragging || undefined, children: (0, jsx_runtime_1.jsx)(BaseItem_1.BaseItem, { ...option, id: id, disabled: disabled, dragHandle: (0, jsx_runtime_1.jsx)(DragHandle_1.DragHandle
42
+ // Динамический перенос: точку вставки показывает пустой слот, поэтому линии (`DropIndicator`) нет.
43
+ return ((0, jsx_runtime_1.jsx)(drag_and_drop_1.DragGhost, { innerRef: setNodeRef, style: style, dragging: isDragging, mode: drag_and_drop_1.DRAG_MODE.Dynamic, children: (0, jsx_runtime_1.jsx)(BaseItem_1.BaseItem, { ...option, id: id, disabled: disabled, dragHandle: (0, jsx_runtime_1.jsx)(DragHandle_1.DragHandle
46
44
  // Pointer-жест не доходит до BottomSheet: иначе vertical drag одновременно закрывает sheet.
47
- , { [bottom_sheet_1.NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners, onMouseDown: handleMouseDown, onClick: utils_1.stopPropagation }) }) }));
45
+ , { [bottom_sheet_1.NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners,
46
+ // `useSortable` ставит ручке tabIndex=0, но список ведёт свою roving-навигацию и
47
+ // перехватывает Tab (см. `useNewKeyboardNavigation`) — с ручки было некуда уйти.
48
+ // Убираем её из таб-порядка: строка остаётся доступной с клавиатуры, ручка — мышью.
49
+ tabIndex: -1, onMouseDown: handleMouseDown, onClick: utils_1.stopPropagation }) }) }));
48
50
  }
@@ -5,6 +5,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.SimpleItemOverlay = SimpleItemOverlay;
7
7
  const jsx_runtime_1 = require("react/jsx-runtime");
8
+ const drag_and_drop_1 = require("@cloud-ru/ds-drag-and-drop");
9
+ const constants_1 = require("../../../../../constants");
8
10
  const BaseItem_1 = require("../../../BaseItem");
9
11
  const styles_module_scss_1 = __importDefault(require('../../styles.module.css'));
10
12
  const OverlayDragHandle_1 = require("../OverlayDragHandle");
@@ -15,5 +17,8 @@ const OverlayDragHandle_1 = require("../OverlayDragHandle");
15
17
  * это неинтерактивный снимок: ручка и содержимое статичны, перетаскивание ведёт исходная строка.
16
18
  */
17
19
  function SimpleItemOverlay({ bare, ...item }) {
18
- return ((0, jsx_runtime_1.jsx)("div", { className: styles_module_scss_1.default.item, "data-overlay": bare ? undefined : true, children: (0, jsx_runtime_1.jsx)(BaseItem_1.BaseItem, { ...item, dragHandle: (0, jsx_runtime_1.jsx)(OverlayDragHandle_1.OverlayDragHandle, {}) }) }));
20
+ const row = (0, jsx_runtime_1.jsx)(BaseItem_1.BaseItem, { ...item, dragHandle: (0, jsx_runtime_1.jsx)(OverlayDragHandle_1.OverlayDragHandle, {}) });
21
+ if (bare)
22
+ return row;
23
+ return ((0, jsx_runtime_1.jsx)(drag_and_drop_1.DragPreview, { className: styles_module_scss_1.default.dragPreview, "data-test-id": constants_1.TEST_IDS.dragOverlay, children: row }));
19
24
  }
@@ -1,29 +1,6 @@
1
- .item[data-dragging]{
2
- position:relative;
3
- z-index:1;
4
- opacity:0.5;
5
- }
6
- .item[data-overlay]{
1
+ @charset "UTF-8";
2
+ .dragPreview{
7
3
  cursor:grabbing;
8
- opacity:0.5;
9
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
10
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
11
- }
12
-
13
- .groupBlock[data-dragging]{
14
- position:relative;
15
- z-index:1;
16
- opacity:0.5;
17
- }
18
- .groupBlock[data-overlay]{
19
- cursor:grabbing;
20
- opacity:0.5;
21
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
22
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
23
- }
24
- .groupBlock[data-reorder-boundary]{
25
- background:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
26
- box-shadow:inset 0 6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275))), inset 0 -6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275)));
27
4
  }
28
5
 
29
6
  .groupHeader{
@@ -83,6 +60,11 @@
83
60
  -moz-appearance:none;
84
61
  appearance:none;
85
62
  background:transparent;
63
+ outline:none;
64
+ }
65
+ .dragHandle:focus-visible{
66
+ outline:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px) solid var(--sn-theme-color-available-complementary, #000000);
67
+ outline-offset:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
86
68
  }
87
69
  .dragHandle svg{
88
70
  width:100%;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Отключает FLIP-анимацию перестановки после отпускания (общий контракт `SimpleItem` и `SimpleGroupBlock`).
3
3
  * Порядок применяется синхронно через `onItemsReorder`; без флага `@dnd-kit` доигрывает `transform 200ms`
4
- * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место.
4
+ * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место. Расступание соседей
5
+ * на время переноса флаг не трогает: его ведёт стратегия `SortableContext`.
5
6
  */
6
7
  export declare function animateLayoutChanges(): boolean;
@@ -4,7 +4,8 @@ exports.animateLayoutChanges = animateLayoutChanges;
4
4
  /**
5
5
  * Отключает FLIP-анимацию перестановки после отпускания (общий контракт `SimpleItem` и `SimpleGroupBlock`).
6
6
  * Порядок применяется синхронно через `onItemsReorder`; без флага `@dnd-kit` доигрывает `transform 200ms`
7
- * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место.
7
+ * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место. Расступание соседей
8
+ * на время переноса флаг не трогает: его ведёт стратегия `SortableContext`.
8
9
  */
9
10
  function animateLayoutChanges() {
10
11
  return false;
@@ -56,8 +56,8 @@ exports.ListPrivate = (0, react_1.forwardRef)(({ items, pinTop, pinBottom, onKey
56
56
  const virtualized = virtualizedProp && !onDragEnd;
57
57
  const sensors = (0, core_1.useSensors)((0, core_1.useSensor)(core_1.MouseSensor, draggingOptions), (0, core_1.useSensor)(core_1.TouchSensor, {}), (0, core_1.useSensor)(core_1.KeyboardSensor, { coordinateGetter: sortable_1.sortableKeyboardCoordinates }));
58
58
  // Id перетаскиваемой строки — для рендера её копии в `DragOverlay`. Копия живёт в портале
59
- // над страницей и не режется `overflow: hidden` контейнера `List` (исходная строка остаётся
60
- // на месте «призраком»). `null`, когда перетаскивание не идёт.
59
+ // над страницей и не режется `overflow: hidden` контейнера `List` (сама строка на время
60
+ // переноса уступает место — её слот пустеет). `null`, когда перетаскивание не идёт.
61
61
  const [activeDragId, setActiveDragId] = (0, react_1.useState)(null);
62
62
  const handleDragStart = (0, react_1.useCallback)((event) => setActiveDragId(event.active.id), []);
63
63
  const handleDragEnd = (0, react_1.useCallback)((event) => {
@@ -43,6 +43,7 @@ export declare const TEST_IDS: {
43
43
  readonly accordionItem: "list__accordion-item";
44
44
  readonly groupIndicator: "list__group-indicator";
45
45
  readonly dragHandle: "list__drag-handle";
46
+ readonly dragOverlay: "list__drag-overlay";
46
47
  readonly mobileDroplistRoot: "list__mobile-droplist-root";
47
48
  readonly mobileDroplistTrigger: "list__mobile-droplist-trigger";
48
49
  };
@@ -46,6 +46,7 @@ exports.TEST_IDS = {
46
46
  accordionItem: 'list__accordion-item',
47
47
  groupIndicator: 'list__group-indicator',
48
48
  dragHandle: 'list__drag-handle',
49
+ dragOverlay: 'list__drag-overlay',
49
50
  mobileDroplistRoot: 'list__mobile-droplist-root',
50
51
  mobileDroplistTrigger: 'list__mobile-droplist-trigger',
51
52
  };
@@ -335,32 +335,9 @@
335
335
  outline:var(--sn-theme-color-available-complementary, #000000) solid var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
336
336
  outline-offset:calc(0px - var(--sn-primitive-strokeWeight-strokeSemiBold, 2px));
337
337
  }
338
- .item[data-dragging]{
339
- position:relative;
340
- z-index:1;
341
- opacity:0.5;
342
- }
343
- .item[data-overlay]{
344
- cursor:grabbing;
345
- opacity:0.5;
346
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
347
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
348
- }
349
-
350
- .groupBlock[data-dragging]{
351
- position:relative;
352
- z-index:1;
353
- opacity:0.5;
354
- }
355
- .groupBlock[data-overlay]{
338
+ @charset "UTF-8";
339
+ .dragPreview{
356
340
  cursor:grabbing;
357
- opacity:0.5;
358
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
359
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
360
- }
361
- .groupBlock[data-reorder-boundary]{
362
- background:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
363
- box-shadow:inset 0 6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275))), inset 0 -6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275)));
364
341
  }
365
342
 
366
343
  .groupHeader{
@@ -420,6 +397,11 @@
420
397
  -moz-appearance:none;
421
398
  appearance:none;
422
399
  background:transparent;
400
+ outline:none;
401
+ }
402
+ .dragHandle:focus-visible{
403
+ outline:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px) solid var(--sn-theme-color-available-complementary, #000000);
404
+ outline-offset:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
423
405
  }
424
406
  .dragHandle svg{
425
407
  width:100%;
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useDndContext } from '@dnd-kit/core';
3
2
  import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
4
3
  import { CSS } from '@dnd-kit/utilities';
5
4
  import { NO_DRAG_ATTRIBUTE } from '@cloud-ru/ds-bottom-sheet';
5
+ import { DRAG_MODE, DragGhost } from '@cloud-ru/ds-drag-and-drop';
6
6
  import { Separator } from '../../../../../helperComponents/index.js';
7
7
  import { stopPropagation } from '../../../../../utils.js';
8
8
  import { useNewListContext } from '../../../../Lists/contexts/index.js';
@@ -25,12 +25,6 @@ export function SimpleGroupBlock({ id, rowIds, children, ...separatorProps }) {
25
25
  data: { container: REORDER_TOP_LEVEL },
26
26
  animateLayoutChanges,
27
27
  });
28
- // Идёт ли переупорядочивание строки этой группы (а не самой группы). Оно жёстко ограничено
29
- // своим контейнером (`container === id` в `data` строки, см. `SimpleItem`), поэтому границы
30
- // блока группы подсвечиваются — видно, что строка не выходит за пределы группы, а не «сломалась».
31
- const { active } = useDndContext();
32
- const activeContainer = active?.data.current?.container;
33
- const isReorderingWithinGroup = active != null && active.id !== id && activeContainer === id;
34
28
  const style = {
35
29
  transform: CSS.Translate.toString(transform),
36
30
  transition,
@@ -40,7 +34,12 @@ export function SimpleGroupBlock({ id, rowIds, children, ...separatorProps }) {
40
34
  stopPropagation(e);
41
35
  onMouseDown?.(e);
42
36
  };
43
- return (_jsxs("div", { ref: setNodeRef, style: style, className: styles.groupBlock, "data-dragging": isDragging || undefined, "data-reorder-boundary": isReorderingWithinGroup || undefined, children: [_jsxs("div", { className: styles.groupHeader, "data-size": size, children: [_jsx(DragHandle
37
+ // Динамический перенос тот же, что у строк (`SimpleItem`).
38
+ return (_jsxs(DragGhost, { innerRef: setNodeRef, style: style, dragging: isDragging, mode: DRAG_MODE.Dynamic, children: [_jsxs("div", { className: styles.groupHeader, "data-size": size, children: [_jsx(DragHandle
44
39
  // Pointer-жест не доходит до BottomSheet: иначе vertical drag одновременно закрывает sheet.
45
- , { [NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners, onMouseDown: handleMouseDown, onClick: stopPropagation }), _jsx(Separator, { ...separatorProps })] }), _jsx(SortableContext, { items: rowIds, strategy: verticalListSortingStrategy, children: children })] }));
40
+ , { [NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners,
41
+ // `useSortable` ставит ручке tabIndex=0, но список ведёт свою roving-навигацию и
42
+ // перехватывает Tab (см. `useNewKeyboardNavigation`) — с ручки было некуда уйти.
43
+ // Убираем её из таб-порядка: строка остаётся доступной с клавиатуры, ручка — мышью.
44
+ tabIndex: -1, onMouseDown: handleMouseDown, onClick: stopPropagation }), _jsx(Separator, { ...separatorProps })] }), _jsx(SortableContext, { items: rowIds, strategy: verticalListSortingStrategy, children: children })] }));
46
45
  }
@@ -1,4 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { DragPreview } from '@cloud-ru/ds-drag-and-drop';
3
+ import { TEST_IDS } from '../../../../../constants.js';
2
4
  import { Separator } from '../../../../../helperComponents/index.js';
3
5
  import styles from '../../styles.module.css';
4
6
  import { OverlayDragHandle } from '../OverlayDragHandle/index.js';
@@ -9,5 +11,5 @@ import { SimpleItemOverlay } from '../SimpleItemOverlay/index.js';
9
11
  * подгоняет обёртку под размеры активного узла (весь блок), поэтому одним заголовком её не заполнить.
10
12
  */
11
13
  export function SimpleGroupBlockOverlay({ size, rows, ...separatorProps }) {
12
- return (_jsxs("div", { className: styles.groupBlock, "data-overlay": true, children: [_jsxs("div", { className: styles.groupHeader, "data-size": size, children: [_jsx(OverlayDragHandle, {}), _jsx(Separator, { ...separatorProps })] }), rows.map(row => (_jsx(SimpleItemOverlay, { ...row, bare: true }, row.id)))] }));
14
+ return (_jsx(DragPreview, { className: styles.dragPreview, "data-test-id": TEST_IDS.dragOverlay, children: _jsxs("div", { children: [_jsxs("div", { className: styles.groupHeader, "data-size": size, children: [_jsx(OverlayDragHandle, {}), _jsx(Separator, { ...separatorProps })] }), rows.map(row => (_jsx(SimpleItemOverlay, { ...row, bare: true }, row.id)))] }) }));
13
15
  }
@@ -2,10 +2,10 @@ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useSortable } from '@dnd-kit/sortable';
3
3
  import { CSS } from '@dnd-kit/utilities';
4
4
  import { NO_DRAG_ATTRIBUTE } from '@cloud-ru/ds-bottom-sheet';
5
+ import { DRAG_MODE, DragGhost } from '@cloud-ru/ds-drag-and-drop';
5
6
  import { stopPropagation } from '../../../../../utils.js';
6
7
  import { BaseItem } from '../../../BaseItem/index.js';
7
8
  import { REORDER_TOP_LEVEL } from '../../constants.js';
8
- import styles from '../../styles.module.css';
9
9
  import { animateLayoutChanges } from '../../utils.js';
10
10
  import { DragHandle } from '../DragHandle/index.js';
11
11
  /**
@@ -20,8 +20,8 @@ export function SimpleItem({ id, disabled, groupId, ...option }) {
20
20
  // `disabled` на строке отключает `Switch` и клик (`BaseItem`), но не переупорядочивание:
21
21
  // ручка всегда активна.
22
22
  // `container` читает кастомный `collisionDetection` в `ListPrivate`: drop разрешён только внутри
23
- // одного контейнера. Строка без группы (`groupId` пуст) лежит в общем контейнере верхнего уровня
24
- // вместе с группами (можно менять местами строку и группу); строка группы — в контейнере группы.
23
+ // одного контейнера. Строка без группы (`groupId` пуст) лежит в контейнере верхнего уровня,
24
+ // строка группы — в контейнере своей группы.
25
25
  data: { container: groupId ?? REORDER_TOP_LEVEL },
26
26
  animateLayoutChanges,
27
27
  });
@@ -36,7 +36,12 @@ export function SimpleItem({ id, disabled, groupId, ...option }) {
36
36
  stopPropagation(e);
37
37
  onMouseDown?.(e);
38
38
  };
39
- return (_jsx("div", { ref: setNodeRef, style: style, className: styles.item, "data-dragging": isDragging || undefined, children: _jsx(BaseItem, { ...option, id: id, disabled: disabled, dragHandle: _jsx(DragHandle
39
+ // Динамический перенос: точку вставки показывает пустой слот, поэтому линии (`DropIndicator`) нет.
40
+ return (_jsx(DragGhost, { innerRef: setNodeRef, style: style, dragging: isDragging, mode: DRAG_MODE.Dynamic, children: _jsx(BaseItem, { ...option, id: id, disabled: disabled, dragHandle: _jsx(DragHandle
40
41
  // Pointer-жест не доходит до BottomSheet: иначе vertical drag одновременно закрывает sheet.
41
- , { [NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners, onMouseDown: handleMouseDown, onClick: stopPropagation }) }) }));
42
+ , { [NO_DRAG_ATTRIBUTE]: '', ...attributes, ...restListeners,
43
+ // `useSortable` ставит ручке tabIndex=0, но список ведёт свою roving-навигацию и
44
+ // перехватывает Tab (см. `useNewKeyboardNavigation`) — с ручки было некуда уйти.
45
+ // Убираем её из таб-порядка: строка остаётся доступной с клавиатуры, ручка — мышью.
46
+ tabIndex: -1, onMouseDown: handleMouseDown, onClick: stopPropagation }) }) }));
42
47
  }
@@ -1,4 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { DragPreview } from '@cloud-ru/ds-drag-and-drop';
3
+ import { TEST_IDS } from '../../../../../constants.js';
2
4
  import { BaseItem } from '../../../BaseItem/index.js';
3
5
  import styles from '../../styles.module.css';
4
6
  import { OverlayDragHandle } from '../OverlayDragHandle/index.js';
@@ -9,5 +11,8 @@ import { OverlayDragHandle } from '../OverlayDragHandle/index.js';
9
11
  * это неинтерактивный снимок: ручка и содержимое статичны, перетаскивание ведёт исходная строка.
10
12
  */
11
13
  export function SimpleItemOverlay({ bare, ...item }) {
12
- return (_jsx("div", { className: styles.item, "data-overlay": bare ? undefined : true, children: _jsx(BaseItem, { ...item, dragHandle: _jsx(OverlayDragHandle, {}) }) }));
14
+ const row = _jsx(BaseItem, { ...item, dragHandle: _jsx(OverlayDragHandle, {}) });
15
+ if (bare)
16
+ return row;
17
+ return (_jsx(DragPreview, { className: styles.dragPreview, "data-test-id": TEST_IDS.dragOverlay, children: row }));
13
18
  }
@@ -1,29 +1,6 @@
1
- .item[data-dragging]{
2
- position:relative;
3
- z-index:1;
4
- opacity:0.5;
5
- }
6
- .item[data-overlay]{
1
+ @charset "UTF-8";
2
+ .dragPreview{
7
3
  cursor:grabbing;
8
- opacity:0.5;
9
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
10
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
11
- }
12
-
13
- .groupBlock[data-dragging]{
14
- position:relative;
15
- z-index:1;
16
- opacity:0.5;
17
- }
18
- .groupBlock[data-overlay]{
19
- cursor:grabbing;
20
- opacity:0.5;
21
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
22
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
23
- }
24
- .groupBlock[data-reorder-boundary]{
25
- background:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
26
- box-shadow:inset 0 6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275))), inset 0 -6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275)));
27
4
  }
28
5
 
29
6
  .groupHeader{
@@ -83,6 +60,11 @@
83
60
  -moz-appearance:none;
84
61
  appearance:none;
85
62
  background:transparent;
63
+ outline:none;
64
+ }
65
+ .dragHandle:focus-visible{
66
+ outline:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px) solid var(--sn-theme-color-available-complementary, #000000);
67
+ outline-offset:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
86
68
  }
87
69
  .dragHandle svg{
88
70
  width:100%;
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Отключает FLIP-анимацию перестановки после отпускания (общий контракт `SimpleItem` и `SimpleGroupBlock`).
3
3
  * Порядок применяется синхронно через `onItemsReorder`; без флага `@dnd-kit` доигрывает `transform 200ms`
4
- * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место.
4
+ * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место. Расступание соседей
5
+ * на время переноса флаг не трогает: его ведёт стратегия `SortableContext`.
5
6
  */
6
7
  export declare function animateLayoutChanges(): boolean;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Отключает FLIP-анимацию перестановки после отпускания (общий контракт `SimpleItem` и `SimpleGroupBlock`).
3
3
  * Порядок применяется синхронно через `onItemsReorder`; без флага `@dnd-kit` доигрывает `transform 200ms`
4
- * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место.
4
+ * из старого слота в новый — отпущенная строка дёргается обратно и уезжает на место. Расступание соседей
5
+ * на время переноса флаг не трогает: его ведёт стратегия `SortableContext`.
5
6
  */
6
7
  export function animateLayoutChanges() {
7
8
  return false;
@@ -50,8 +50,8 @@ export const ListPrivate = forwardRef(({ items, pinTop, pinBottom, onKeyDown, on
50
50
  const virtualized = virtualizedProp && !onDragEnd;
51
51
  const sensors = useSensors(useSensor(MouseSensor, draggingOptions), useSensor(TouchSensor, {}), useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }));
52
52
  // Id перетаскиваемой строки — для рендера её копии в `DragOverlay`. Копия живёт в портале
53
- // над страницей и не режется `overflow: hidden` контейнера `List` (исходная строка остаётся
54
- // на месте «призраком»). `null`, когда перетаскивание не идёт.
53
+ // над страницей и не режется `overflow: hidden` контейнера `List` (сама строка на время
54
+ // переноса уступает место — её слот пустеет). `null`, когда перетаскивание не идёт.
55
55
  const [activeDragId, setActiveDragId] = useState(null);
56
56
  const handleDragStart = useCallback((event) => setActiveDragId(event.active.id), []);
57
57
  const handleDragEnd = useCallback((event) => {
@@ -43,6 +43,7 @@ export declare const TEST_IDS: {
43
43
  readonly accordionItem: "list__accordion-item";
44
44
  readonly groupIndicator: "list__group-indicator";
45
45
  readonly dragHandle: "list__drag-handle";
46
+ readonly dragOverlay: "list__drag-overlay";
46
47
  readonly mobileDroplistRoot: "list__mobile-droplist-root";
47
48
  readonly mobileDroplistTrigger: "list__mobile-droplist-trigger";
48
49
  };
@@ -43,6 +43,7 @@ export const TEST_IDS = {
43
43
  accordionItem: 'list__accordion-item',
44
44
  groupIndicator: 'list__group-indicator',
45
45
  dragHandle: 'list__drag-handle',
46
+ dragOverlay: 'list__drag-overlay',
46
47
  mobileDroplistRoot: 'list__mobile-droplist-root',
47
48
  mobileDroplistTrigger: 'list__mobile-droplist-trigger',
48
49
  };
@@ -335,32 +335,9 @@
335
335
  outline:var(--sn-theme-color-available-complementary, #000000) solid var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
336
336
  outline-offset:calc(0px - var(--sn-primitive-strokeWeight-strokeSemiBold, 2px));
337
337
  }
338
- .item[data-dragging]{
339
- position:relative;
340
- z-index:1;
341
- opacity:0.5;
342
- }
343
- .item[data-overlay]{
344
- cursor:grabbing;
345
- opacity:0.5;
346
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
347
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
348
- }
349
-
350
- .groupBlock[data-dragging]{
351
- position:relative;
352
- z-index:1;
353
- opacity:0.5;
354
- }
355
- .groupBlock[data-overlay]{
338
+ @charset "UTF-8";
339
+ .dragPreview{
356
340
  cursor:grabbing;
357
- opacity:0.5;
358
- background:var(--sn-theme-color-neutral-background2Level, var(--sn-brand-color-neutral-99, var(--sn-primitive-color-gray-99, #ffffff)));
359
- box-shadow:var(--sn-boxShadow-elevation-level2, var(--sn-theme-effect-shadow-level2-layer1-positionX, 0) var(--sn-theme-effect-shadow-level2-layer1-positionY, 0) var(--sn-theme-effect-shadow-level2-layer1-blur, 4px) var(--sn-theme-effect-shadow-level2-layer1-speed, 0) var(--sn-theme-effect-shadow-layer1Color, rgba(0, 0, 0, 0.0784313725)), var(--sn-theme-effect-shadow-level2-layer2-positionX, 0) var(--sn-theme-effect-shadow-level2-layer2-positionY, 4px) var(--sn-theme-effect-shadow-level2-layer2-blur, 8px) var(--sn-theme-effect-shadow-level2-layer2-speed, 2px) var(--sn-theme-effect-shadow-layer2Color, rgba(0, 0, 0, 0.0784313725)));
360
- }
361
- .groupBlock[data-reorder-boundary]{
362
- background:var(--sn-theme-color-neutral-background1Level, var(--sn-brand-color-neutral-95, var(--sn-primitive-color-gray-95, #fdfdfd)));
363
- box-shadow:inset 0 6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275))), inset 0 -6px 12px -12px var(--sn-theme-color-blackout, var(--sn-brand-color-overlay-forLightMode-blackout, rgba(0, 0, 0, 0.3215686275)));
364
341
  }
365
342
 
366
343
  .groupHeader{
@@ -420,6 +397,11 @@
420
397
  -moz-appearance:none;
421
398
  appearance:none;
422
399
  background:transparent;
400
+ outline:none;
401
+ }
402
+ .dragHandle:focus-visible{
403
+ outline:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px) solid var(--sn-theme-color-available-complementary, #000000);
404
+ outline-offset:var(--sn-primitive-strokeWeight-strokeSemiBold, 2px);
423
405
  }
424
406
  .dragHandle svg{
425
407
  width:100%;