ics-ui-kit 0.1.15 → 0.1.16

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.
@@ -1,9 +1,9 @@
1
1
  import { T as r } from "./index-BVqs-uqP.js";
2
- const n = {
3
- selected: "hsl(var(--alpha-high-05))",
2
+ const s = {
3
+ selected: "hsl(var(--alpha-accent-high-secondary))",
4
4
  inactive: "hsl(var(--status-error) / 5%)"
5
- }, l = (...e) => {
6
- const a = e.filter(Boolean).map((t) => `linear-gradient(${t},${t})`);
5
+ }, l = (...t) => {
6
+ const a = t.filter(Boolean).map((e) => `linear-gradient(${e},${e})`);
7
7
  return a.length ? { "--table-row-tints": a.join(",") } : {};
8
8
  }, i = "bg-[image:var(--table-row-tints,none)]", o = "after:bg-[image:var(--table-row-tints,none)]", b = r({
9
9
  base: [
@@ -22,10 +22,10 @@ const n = {
22
22
  }
23
23
  });
24
24
  export {
25
- n as T,
25
+ s as T,
26
26
  i as a,
27
27
  o as b,
28
28
  b as o,
29
29
  l as t
30
30
  };
31
- //# sourceMappingURL=opaqueCell-SGaiyL54.js.map
31
+ //# sourceMappingURL=opaqueCell-D95h1mFM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opaqueCell-D95h1mFM.js","sources":["../src/components/table/rowTint.ts","../src/components/table/opaqueCell.ts"],"sourcesContent":["import type { CSSProperties } from \"react\";\n\n/**\n * Подкраска строки таблицы — стопка полупрозрачных слоёв поверх её заливки.\n *\n * **Когда нужно.** Когда состояний у строки больше одного. Заливка у строки одна\n * (`background-color`), и второе состояние вытеснило бы первое: выделенная деактивированная\n * строка выглядела бы просто выделенной. Слои же складываются альфами — и между собой,\n * и с заливкой, какой бы она ни была, включая заданную вами `className=\"bg-…\"`.\n *\n * **Почему это не пропсы строки.** `TableRow` не знает ни про «выделено», ни про «отключено»:\n * что означает подсветка и когда её включать — знание прикладного кода. Кит даёт механизм\n * (слои), готовые цвета (`TABLE_ROW_TINT`) и рисующие их классы; собирает их потребитель.\n *\n * @example\n * <TableRow style={tableRowTints(isSelected && TABLE_ROW_TINT.selected, isInactive && TABLE_ROW_TINT.inactive)}>\n */\n\n/**\n * Готовые цвета подкрасок: `selected` — выделенная строка, `inactive` — деактивированная.\n *\n * Оба полупрозрачные, поэтому сочетаются и друг с другом, и с наведением: наведение красит\n * заливку под слоями, и выделенная строка под курсором темнеет.\n *\n * Список открытый: свои состояния задавайте своими значениями, слоем годится любой\n * полупрозрачный CSS-цвет.\n */\nexport const TABLE_ROW_TINT = {\n\tselected: \"hsl(var(--alpha-accent-high-secondary))\",\n\tinactive: \"hsl(var(--status-error) / 5%)\"\n} as const;\n\n/**\n * Слои подкраски для `style` строки. Первый аргумент — верхний слой, каждый следующий\n * ложится под ним, под всеми — заливка строки.\n *\n * **Цвета должны быть полупрозрачными**, и следит за этим вызывающий код: значения уходят\n * в `background-image` как есть. Непрозрачный цвет закроет всё, что под ним, — остальные\n * слои и заливку вместе с наведением.\n *\n * Ложные значения отбрасываются, поэтому условия пишутся прямо в аргументах:\n * `tableRowTints(isSelected && TABLE_ROW_TINT.selected)`. Без единого слоя строка красится\n * одной заливкой.\n *\n * Результат — инлайновый стиль с CSS-переменной; она наследуется от `tr` к ячейкам, поэтому\n * закреплённые и перетаскиваемые колонки подхватывают подкраску сами.\n *\n * @example\n * <TableRow\n * style={tableRowTints(\n * isSelected && TABLE_ROW_TINT.selected,\n * isOverdue && \"hsl(var(--status-warning) / 12%)\"\n * )}\n * >\n */\nexport const tableRowTints = (...tints: (string | false | null | undefined)[]): CSSProperties => {\n\tconst layers = tints.filter(Boolean).map((tint) => `linear-gradient(${tint},${tint})`);\n\n\t// `linear-gradient(цвет, цвет)` — способ подать сплошную заливку как изображение: слоями\n\t// умеет быть только `background-image`, а `background-color` — единственный и последний.\n\treturn layers.length ? ({ \"--table-row-tints\": layers.join(\",\") } as CSSProperties) : {};\n};\n\n/**\n * Класс, рисующий слои подкраски на строке. Уже применён к `TableRow` — нужен, только если\n * вы рисуете строку своим элементом.\n */\nexport const TABLE_ROW_TINT_LAYERS = \"bg-[image:var(--table-row-tints,none)]\";\n\n/** То же самое для слоя `::after` непрозрачной ячейки — см. `opaqueCellStyles`. */\nexport const TABLE_ROW_TINT_LAYERS_AFTER = \"after:bg-[image:var(--table-row-tints,none)]\";\n","import { tv } from \"tailwind-variants\";\nimport { TABLE_ROW_TINT_LAYERS_AFTER } from \"./rowTint\";\n\n/**\n * Ячейка с непрозрачным фоном, сохраняющая подсветку строки.\n *\n * Нужна везде, где ячейка выезжает из потока и под ней оказывается чужое содержимое:\n * закреплённая колонка (`stickyCellStyles`) и колонка, которую перетаскивают\n * (`useColumnReorder`). Обе задачи одинаковые, поэтому рецепт один.\n *\n * **Почему фон нельзя просто задать.** Строка прозрачна — красит подложка секции\n * (`TableBody`, `TableHeader`), и такой ячейке нужен свой непрозрачный фон. Но подменять\n * им подсветку строки нельзя: `hover:bg-*` положил бы поверх полупрозрачный цвет, и чужое\n * содержимое снова стало бы просвечивать. Поэтому подсветку рисует слой `::after` теми же\n * переменными, что и сама строка, — заливкой (`--table-row-bg`, `--table-row-bg-hover`)\n * и списком слоёв (`--table-row-tints`). Переменные наследуются от `tr` к ячейке сами,\n * связывать их не нужно.\n *\n * Повторяются обе части: если рисовать только заливку, у закреплённой колонки пропадёт любая\n * подкраска — и выделение, и деактивация, и что там ещё собрал потребитель.\n *\n * `transition-colors` совпадает с переходом у `TableRow`, поэтому строка подсвечивается\n * целиком, а не двумя рывками. Разделители слой не задевает: `inset-0` у абсолютного\n * потомка отсчитывается от padding-box, а границы лежат снаружи него.\n *\n * **Требует контекста позиционирования** — `sticky` у закреплённой ячейки, `relative`\n * у перетаскиваемой: иначе `::after` растянется не по ячейке, а по ближайшему\n * позиционированному предку.\n *\n * @example\n * <TableCell className={opaqueCellStyles({ className: \"relative\" })}>…</TableCell>\n * <TableHead className={opaqueCellStyles({ part: \"head\", className: \"relative\" })}>…</TableHead>\n */\nexport const opaqueCellStyles = tv({\n\tbase: [\n\t\t\"after:pointer-events-none after:absolute after:inset-0 after:transition-colors\",\n\t\t\"after:bg-[color:var(--table-row-bg)] [tr:hover>&]:after:bg-[color:var(--table-row-bg-hover)]\",\n\t\tTABLE_ROW_TINT_LAYERS_AFTER\n\t],\n\tvariants: {\n\t\tpart: {\n\t\t\tcell: \"bg-secondary-bg\",\n\t\t\thead: \"bg-primary-bg\"\n\t\t}\n\t},\n\tdefaultVariants: {\n\t\tpart: \"cell\"\n\t}\n});\n"],"names":["TABLE_ROW_TINT","tableRowTints","tints","layers","tint","TABLE_ROW_TINT_LAYERS","TABLE_ROW_TINT_LAYERS_AFTER","opaqueCellStyles","tv"],"mappings":";AA2BO,MAAMA,IAAiB;AAAA,EAC7B,UAAU;AAAA,EACV,UAAU;AACX,GAyBaC,IAAgB,IAAIC,MAAgE;AAChG,QAAMC,IAASD,EAAM,OAAO,OAAO,EAAE,IAAI,CAACE,MAAS,mBAAmBA,CAAI,IAAIA,CAAI,GAAG;AAI9E,SAAAD,EAAO,SAAU,EAAE,qBAAqBA,EAAO,KAAK,GAAG,EAAE,IAAsB,CAAC;AACxF,GAMaE,IAAwB,0CAGxBC,IAA8B,gDCrC9BC,IAAmBC,EAAG;AAAA,EAClC,MAAM;AAAA,IACL;AAAA,IACA;AAAA,IACAF;AAAA,EACD;AAAA,EACA,UAAU;AAAA,IACT,MAAM;AAAA,MACL,MAAM;AAAA,MACN,MAAM;AAAA,IAAA;AAAA,EAER;AAAA,EACA,iBAAiB;AAAA,IAChB,MAAM;AAAA,EAAA;AAER,CAAC;"}
@@ -142,8 +142,10 @@
142
142
  --alpha-high-80: 229 84% 5% / 80%;
143
143
  --alpha-high-90: 229 84% 5% / 90%;
144
144
 
145
- --alpha-accent-primary: 210 40% 96% / 12%;
145
+ --alpha-accent-primary: 210 40% 96% / 16%;
146
146
  --alpha-accent-secondary: 210 40% 96% / 8%;
147
+ --alpha-accent-high-primary: 222 47% 11% / 16%;
148
+ --alpha-accent-high-secondary: 222 47% 11% / 8%;
147
149
 
148
150
  /** Autofill **/
149
151
  --autofill-bg: 213 100% 96%;
@@ -310,8 +312,10 @@
310
312
  --alpha-high-80: 210 40% 96% / 80%;
311
313
  --alpha-high-90: 210 40% 96% / 90%;
312
314
 
313
- --alpha-accent-primary: 222 47% 11% / 8%;
314
- --alpha-accent-secondary: 222 47% 11% / 5%;
315
+ --alpha-accent-primary: 222 47% 11% / 16%;
316
+ --alpha-accent-secondary: 222 47% 11% / 8%;
317
+ --alpha-accent-high-primary: 210 40% 96% / 16%;
318
+ --alpha-accent-high-secondary: 210 40% 96% / 8%;
315
319
 
316
320
  /** Palette **/
317
321
  --peony: 340 35% 47%;
@@ -1591,10 +1595,6 @@
1591
1595
  margin-top: 0.25rem;
1592
1596
  margin-bottom: 0.25rem;
1593
1597
  }
1594
- .ui-kit .my-2 {
1595
- margin-top: 0.5rem;
1596
- margin-bottom: 0.5rem;
1597
- }
1598
1598
  .ui-kit .my-4 {
1599
1599
  margin-top: 1rem;
1600
1600
  margin-bottom: 1rem;
@@ -2839,6 +2839,9 @@
2839
2839
  .ui-kit .overflow-x-hidden {
2840
2840
  overflow-x: hidden;
2841
2841
  }
2842
+ .ui-kit .overflow-y-hidden {
2843
+ overflow-y: hidden;
2844
+ }
2842
2845
  .ui-kit .truncate {
2843
2846
  overflow: hidden;
2844
2847
  text-overflow: ellipsis;
@@ -4347,6 +4350,9 @@
4347
4350
  .ui-kit .\[mask-image\:linear-gradient\(to_left\2c rgba\(255\2c 255\2c 255\2c 0\)\2c \#fff_30\%\)\] {
4348
4351
  mask-image: linear-gradient(to left,rgba(255,255,255,0),#fff 30%);
4349
4352
  }
4353
+ .ui-kit .\[scrollbar-gutter\:stable\] {
4354
+ scrollbar-gutter: stable;
4355
+ }
4350
4356
  .ui-kit .\[scrollbar-width\:none\] {
4351
4357
  scrollbar-width: none;
4352
4358
  }
package/dist/styles.css CHANGED
@@ -142,8 +142,10 @@
142
142
  --alpha-high-80: 229 84% 5% / 80%;
143
143
  --alpha-high-90: 229 84% 5% / 90%;
144
144
 
145
- --alpha-accent-primary: 210 40% 96% / 12%;
145
+ --alpha-accent-primary: 210 40% 96% / 16%;
146
146
  --alpha-accent-secondary: 210 40% 96% / 8%;
147
+ --alpha-accent-high-primary: 222 47% 11% / 16%;
148
+ --alpha-accent-high-secondary: 222 47% 11% / 8%;
147
149
 
148
150
  /** Autofill **/
149
151
  --autofill-bg: 213 100% 96%;
@@ -310,8 +312,10 @@
310
312
  --alpha-high-80: 210 40% 96% / 80%;
311
313
  --alpha-high-90: 210 40% 96% / 90%;
312
314
 
313
- --alpha-accent-primary: 222 47% 11% / 8%;
314
- --alpha-accent-secondary: 222 47% 11% / 5%;
315
+ --alpha-accent-primary: 222 47% 11% / 16%;
316
+ --alpha-accent-secondary: 222 47% 11% / 8%;
317
+ --alpha-accent-high-primary: 210 40% 96% / 16%;
318
+ --alpha-accent-high-secondary: 210 40% 96% / 8%;
315
319
 
316
320
  /** Palette **/
317
321
  --peony: 340 35% 47%;
@@ -1576,10 +1580,6 @@ body {
1576
1580
  margin-top: 0.25rem;
1577
1581
  margin-bottom: 0.25rem;
1578
1582
  }
1579
- .my-2 {
1580
- margin-top: 0.5rem;
1581
- margin-bottom: 0.5rem;
1582
- }
1583
1583
  .my-4 {
1584
1584
  margin-top: 1rem;
1585
1585
  margin-bottom: 1rem;
@@ -2824,6 +2824,9 @@ body {
2824
2824
  .overflow-x-hidden {
2825
2825
  overflow-x: hidden;
2826
2826
  }
2827
+ .overflow-y-hidden {
2828
+ overflow-y: hidden;
2829
+ }
2827
2830
  .truncate {
2828
2831
  overflow: hidden;
2829
2832
  text-overflow: ellipsis;
@@ -4336,6 +4339,9 @@ body {
4336
4339
  .\[mask-image\:linear-gradient\(to_left\2c rgba\(255\2c 255\2c 255\2c 0\)\2c \#fff_30\%\)\] {
4337
4340
  mask-image: linear-gradient(to left,rgba(255,255,255,0),#fff 30%);
4338
4341
  }
4342
+ .\[scrollbar-gutter\:stable\] {
4343
+ scrollbar-gutter: stable;
4344
+ }
4339
4345
  .\[scrollbar-width\:none\] {
4340
4346
  scrollbar-width: none;
4341
4347
  }
package/dist/theme.css CHANGED
@@ -141,8 +141,10 @@
141
141
  --alpha-high-80: 229 84% 5% / 80%;
142
142
  --alpha-high-90: 229 84% 5% / 90%;
143
143
 
144
- --alpha-accent-primary: 210 40% 96% / 12%;
144
+ --alpha-accent-primary: 210 40% 96% / 16%;
145
145
  --alpha-accent-secondary: 210 40% 96% / 8%;
146
+ --alpha-accent-high-primary: 222 47% 11% / 16%;
147
+ --alpha-accent-high-secondary: 222 47% 11% / 8%;
146
148
 
147
149
  /** Autofill **/
148
150
  --autofill-bg: 213 100% 96%;
@@ -310,8 +312,10 @@
310
312
  --alpha-high-80: 210 40% 96% / 80%;
311
313
  --alpha-high-90: 210 40% 96% / 90%;
312
314
 
313
- --alpha-accent-primary: 222 47% 11% / 8%;
314
- --alpha-accent-secondary: 222 47% 11% / 5%;
315
+ --alpha-accent-primary: 222 47% 11% / 16%;
316
+ --alpha-accent-secondary: 222 47% 11% / 8%;
317
+ --alpha-accent-high-primary: 210 40% 96% / 16%;
318
+ --alpha-accent-high-secondary: 210 40% 96% / 8%;
315
319
 
316
320
  /** Palette **/
317
321
  --peony: 340 35% 47%;
@@ -4,7 +4,7 @@ import { T as n } from "./index-BVqs-uqP.js";
4
4
  import { I as A } from "./Icon-DH3ev9GK.js";
5
5
  import { S as G } from "./ScrollShadowContainer-DdrnF8qU.js";
6
6
  import { STICKY_HEADER as F, STICKY_FOOTER as P } from "./components/table/sticky.js";
7
- import { a as j } from "./opaqueCell-SGaiyL54.js";
7
+ import { a as j } from "./opaqueCell-D95h1mFM.js";
8
8
  import { c as u } from "./cn-dsXlqdJg.js";
9
9
  import { M as k } from "./minus-BltQa7Q2.js";
10
10
  import { P as Y } from "./plus-BpxYPnAG.js";
@@ -316,4 +316,4 @@ export {
316
316
  xe as w,
317
317
  Te as x
318
318
  };
319
- //# sourceMappingURL=treeModel-BlPWVj4W.js.map
319
+ //# sourceMappingURL=treeModel-jvOXFZvK.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"treeModel-BlPWVj4W.js","sources":["../src/components/table/Table.tsx","../src/components/table/tree/treeGeometry.ts","../src/components/table/tree/TableTree.tsx","../src/components/table/tree/treeModel.ts"],"sourcesContent":["import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { ScrollShadowContainer } from \"../scroll-shadow-container\";\nimport { STICKY_FOOTER, STICKY_HEADER } from \"./sticky/stickyCell\";\nimport { ScrollShadowContainerProps } from \"../scroll-shadow-container/ScrollShadowContainer\";\nimport { TABLE_ROW_TINT_LAYERS } from \"./rowTint\";\n\nconst tableStyles = tv({\n\tslots: {\n\t\twrapper: \"relative w-full overflow-x-auto rounded-lg border border-secondary-border\",\n\n\t\t// Раздельная модель границ вместо схлопнутой (умолчание Tailwind для таблиц).\n\t\t// В схлопнутой модели граница принадлежит сетке таблицы, а не ячейке: `position: sticky`\n\t\t// и `transform` уносят ячейку, а линия остаётся стоять на старом месте — из-за этого\n\t\t// прилипающим шапке и колонке приходилось гасить границу и рисовать её inset-тенью.\n\t\t// В раздельной модели граница входит в бокс ячейки и едет вместе с ней.\n\t\t//\n\t\t// Плата: `border` у групп строк (`thead`, `tbody`, `tfoot`) и у самих `tr` браузер\n\t\t// обязан игнорировать, поэтому все разделители живут на ячейках — см. `TABLE_ROW_ANATOMY`,\n\t\t// `tableHeaderStyles` и `tableFooterStyles`.\n\t\ttable: \"w-full caption-bottom border-separate border-spacing-0 text-xs\"\n\t}\n});\n\nexport type TableProps = React.HTMLAttributes<HTMLTableElement> & {\n\tcontainerClassName?: string;\n\tcontainerRef?: React.Ref<HTMLDivElement>;\n};\n\nexport const Table = React.forwardRef<HTMLTableElement, TableProps>(\n\t({ className, containerClassName, containerRef, ...props }, ref) => {\n\t\tconst styles = tableStyles();\n\n\t\treturn (\n\t\t\t<div ref={containerRef} className={styles.wrapper({ className: containerClassName })}>\n\t\t\t\t<table ref={ref} className={styles.table({ className })} {...props} />\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nTable.displayName = \"Table\";\n\nconst tableHeaderStyles = tv({\n\t// Линия под шапкой — на ячейках, а не на `thead`: `border` у групп строк в раздельной\n\t// модели игнорируется (см. `tableStyles`). Заодно это ровно то, что нужно прилипающей\n\t// шапке: граница ячейки уезжает вместе с ячейкой, а не остаётся в сетке таблицы.\n\t//\n\t// Ту же нижнюю границу ячейкам шапки даёт и `TableRow`; дубль намеренный — разделитель\n\t// шапки и тела это контракт самого `TableHeader`, и он не должен пропадать из-за голого\n\t// `<tr>` в разметке потребителя. Одинаковые объявления одного свойства линию не задваивают.\n\t//\n\tbase: \"bg-primary-bg [&_th]:border-b [&_th]:border-secondary-border [&_tr]:[--table-row-bg-hover:transparent]\",\n\tvariants: {\n\t\tsticky: {\n\t\t\ttrue: STICKY_HEADER\n\t\t}\n\t}\n});\n\nexport type TableHeaderProps = React.HTMLAttributes<HTMLTableSectionElement> & {\n\t/**\n\t * Шапка остаётся на месте при вертикальной прокрутке.\n\t *\n\t * Прокручивается контейнер таблицы, поэтому ему нужна ограниченная высота\n\t * (`containerClassName=\"max-h-80\"`): без неё прокручивать нечего и `position: sticky`\n\t * ничего не делает.\n\t *\n\t * Проп, а не набор классов в `className`, потому что вместе со `sticky` требуется\n\t * `z-index`, согласованный с закреплёнными колонками, — это знание кита, а не\n\t * потребителя (см. `STICKY_HEADER`).\n\t */\n\tsticky?: boolean;\n};\n\nexport const TableHeader = React.forwardRef<HTMLTableSectionElement, TableHeaderProps>(\n\t({ className, sticky, ...props }, ref) => (\n\t\t<thead ref={ref} className={tableHeaderStyles({ sticky, className })} {...props} />\n\t)\n);\n\nTableHeader.displayName = \"TableHeader\";\n\nconst tableBodyStyles = tv({\n\tbase: \"bg-secondary-bg [&_tr:last-child>*]:border-b-0\"\n});\n\nexport const TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(\n\t({ className, ...props }, ref) => <tbody ref={ref} className={tableBodyStyles({ className })} {...props} />\n);\n\nTableBody.displayName = \"TableBody\";\n\nconst tableBodyContainerStyles = tv({\n\tbase: \"overflow-x-hidden\"\n});\n\nexport type TableBodyContainerProps = React.HTMLAttributes<HTMLTableSectionElement> & {\n\tcontainerClassName?: string;\n\tshadowSize?: ScrollShadowContainerProps[\"shadowSize\"];\n};\n\nexport const TableBodyContainer = React.forwardRef<HTMLTableSectionElement, TableBodyContainerProps>(\n\t({ className, containerClassName, shadowSize, ...props }, ref) => (\n\t\t<ScrollShadowContainer\n\t\t\tclassName={tableBodyContainerStyles({ className: containerClassName })}\n\t\t\tshadowSize={shadowSize}\n\t\t>\n\t\t\t<tbody ref={ref} className={tableBodyStyles({ className })} {...props} />\n\t\t</ScrollShadowContainer>\n\t)\n);\n\nTableBodyContainer.displayName = \"TableBodyContainer\";\n\nconst tableFooterStyles = tv({\n\t// Верхняя граница — на ячейках первой строки, нижняя снимается с ячеек последней:\n\t// собственный `border` у `tfoot` в раздельной модели игнорируется (см. `tableStyles`).\n\tbase: [\n\t\t\"bg-primary-bg font-medium\",\n\t\t\"[&>tr:first-child>*]:border-t [&>tr:first-child>*]:border-secondary-border\",\n\t\t\"[&>tr:last-child>*]:border-b-0\"\n\t],\n\tvariants: {\n\t\tsticky: {\n\t\t\ttrue: STICKY_FOOTER\n\t\t}\n\t}\n});\n\nexport type TableFooterProps = React.HTMLAttributes<HTMLTableSectionElement> & {\n\t/**\n\t * Итоги остаются на месте при вертикальной прокрутке.\n\t *\n\t * Зеркало `sticky` у `TableHeader`, и требует того же: прокручивается контейнер таблицы,\n\t * поэтому у него должна быть ограниченная высота — без неё прокручивать нечего.\n\t *\n\t * Проп, а не классы в `className`, по той же причине, что и у шапки: вместе со `sticky`\n\t * нужен `z-index`, согласованный с закреплёнными колонками (см. `STICKY_FOOTER`).\n\t */\n\tsticky?: boolean;\n};\n\nexport const TableFooter = React.forwardRef<HTMLTableSectionElement, TableFooterProps>(\n\t({ className, sticky, ...props }, ref) => (\n\t\t<tfoot ref={ref} className={tableFooterStyles({ sticky, className })} {...props} />\n\t)\n);\n\nTableFooter.displayName = \"TableFooter\";\n\nconst TABLE_ROW_ANATOMY = \"[&>*]:border-b [&>*]:border-secondary-border transition-colors\";\n\n/**\n * Строка красится двумя вещами: заливкой и слоями подкраски поверх неё.\n *\n * **Заливка** — `--table-row-bg` и `--table-row-bg-hover`: обычная строка и наведённая.\n * Это всё, что кит знает про цвет строки; ни выделения, ни деактивации у примитива нет —\n * что означает подсветка и когда её включать, знает прикладной код (см. `rowTint.ts`).\n *\n * **Слои подкраски** — `--table-row-tints`, их выставляет потребитель через `tableRowTints()`.\n * Полупрозрачные цвета поверх заливки: альфы складываются и между собой, и с заливкой, поэтому\n * выделенная деактивированная строка показывает обе подсветки, а не одну.\n *\n * Заливка и слои разведены не только по смыслу, но и по свойству: `background-color` против\n * `background-image`. Поэтому `className=\"bg-…\"` вытесняет заливку — и только её: слои\n * останутся на месте и лягут поверх любого цвета, который выбрал потребитель.\n */\nconst tableRowStyles = tv({\n\tbase: [\n\t\tTABLE_ROW_ANATOMY,\n\n\t\t// Заливку читает ровно один класс на состояние — обычный `bg-*` и `hover:bg-*`, —\n\t\t// поэтому любой `bg-*` из `className` вытесняет её штатно, без `!important`\n\t\t// и без повторения модификаторов.\n\t\t\"bg-[color:var(--table-row-bg)] hover:bg-[color:var(--table-row-bg-hover)]\",\n\n\t\t// Обычная строка: подложку даёт `TableBody`, ховер — нейтральная альфа поверх неё\n\t\t// (`alpha/high/97` в макете подписана как состояние строки `hover`).\n\t\t\"[--table-row-bg-hover:hsl(var(--alpha-high-03))] [--table-row-bg:transparent]\",\n\n\t\tTABLE_ROW_TINT_LAYERS\n\t]\n});\n\nexport type TableRowProps = React.HTMLAttributes<HTMLTableRowElement>;\n\n/**\n * Строка таблицы.\n *\n * **Как перекрасить.** Обычными классами: `className=\"bg-… hover:bg-…\"`. Они выигрывают\n * штатно — ни `!important`, ни повторения модификаторов не нужно. Кто хочет сохранить\n * встроенное наведение и подменить только палитру — выставляет переменные `--table-row-bg`\n * и `--table-row-bg-hover`.\n *\n * **Как подсветить.** Слоями: `style={tableRowTints(…)}`, готовые цвета — в `TABLE_ROW_TINT`.\n * Слои складываются друг с другом и ложатся поверх заливки, какой бы она ни была, поэтому\n * подсветка и перекраска не конфликтуют. Подробности — в `rowTint.ts`.\n *\n * **Почему цвет читают отдельные классы, а не состояния.** Раньше `base` красил строку\n * четырьмя классами (`hover:bg-*`, `data-[state=selected]:bg-*`,\n * `data-[state=selected]:hover:bg-*`), и перебить их снаружи было нечем: `tailwind-merge`\n * снимает конфликт только между классами с одинаковым набором модификаторов, поэтому `bg-x`\n * из `className` не вытеснял ни один из них, а `data-[state=selected]:bg-*` вдобавок выигрывал\n * по специфичности — 0,2,0 против 0,1,0. Потребителю приходилось вручную повторять все четыре\n * комбинации модификаторов.\n */\nexport const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(({ className, ...props }, ref) => (\n\t<tr ref={ref} className={tableRowStyles({ className })} {...props} />\n));\n\nTableRow.displayName = \"TableRow\";\n\nconst tableHeadStyles = tv({\n\tbase: \"border-r border-secondary-border px-3 py-2.5 text-left align-middle font-medium text-muted last:border-r-0\",\n\tvariants: {\n\t\tinteractive: {\n\t\t\ttrue: [\n\t\t\t\t\"cursor-pointer p-0 transition-colors\",\n\t\t\t\t\"hover:bg-secondary-bg-hover\",\n\t\t\t\t\"data-[state=open]:bg-primary-bg-hover [&:has([data-state=open])]:bg-primary-bg-hover\"\n\t\t\t]\n\t\t}\n\t}\n});\n\nexport type TableHeadProps = React.ThHTMLAttributes<HTMLTableCellElement> & {\n\t/**\n\t * Вся ячейка — интерактивная зона: меняет фон на наведении и на раскрытом меню,\n\t * и снимает собственный паддинг в пользу растянутого на всю ячейку триггера.\n\t */\n\tinteractive?: boolean;\n};\n\nexport const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(\n\t({ className, interactive, ...props }, ref) => (\n\t\t<th ref={ref} className={tableHeadStyles({ interactive, className })} {...props} />\n\t)\n);\n\nTableHead.displayName = \"TableHead\";\n\nconst tableCellStyles = tv({\n\tbase: \"border-r border-secondary-border px-3 py-2.5 align-middle last:border-r-0 [&:has([role=checkbox])]:pr-0\"\n});\n\nexport const TableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(\n\t({ className, ...props }, ref) => <td ref={ref} className={tableCellStyles({ className })} {...props} />\n);\n\nTableCell.displayName = \"TableCell\";\n\nconst tableResizeHandleStyles = tv({\n\tbase: [\n\t\t\"absolute right-0 top-0 z-10 h-full w-2 translate-x-1/2 cursor-col-resize touch-none select-none\",\n\t\t\"after:absolute after:left-1/2 after:top-0 after:h-full after:w-0.5 after:-translate-x-1/2\",\n\t\t\"after:bg-primary-border after:opacity-0 after:transition-opacity hover:after:opacity-100\"\n\t],\n\tvariants: {\n\t\tactive: {\n\t\t\ttrue: \"after:opacity-100\"\n\t\t}\n\t}\n});\n\nexport type TableResizeHandleProps = React.HTMLAttributes<HTMLDivElement> & {\n\t/** Держит индикатор подсвеченным во время drag-сессии, когда курсор уже ушёл с ручки. */\n\tactive?: boolean;\n};\n\n/**\n * Зона захвата для ресайза колонки. Кладётся внутрь `TableHead`, которому нужен `relative`.\n * Саму ширину не считает — работает в паре с `useColumnResize` из `./column-resize`.\n * Работает только если у `TableHead` нет `overflow: hidden`.\n */\nexport const TableResizeHandle = React.forwardRef<HTMLDivElement, TableResizeHandleProps>(\n\t({ className, active, ...props }, ref) => (\n\t\t<div\n\t\t\tref={ref}\n\t\t\trole=\"separator\"\n\t\t\taria-orientation=\"vertical\"\n\t\t\tclassName={tableResizeHandleStyles({ active, className })}\n\t\t\t{...props}\n\t\t/>\n\t)\n);\n\nTableResizeHandle.displayName = \"TableResizeHandle\";\n\nconst tableCaptionStyles = tv({\n\tbase: \"mt-4 text-muted\"\n});\n\nexport const TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(\n\t({ className, ...props }, ref) => <caption ref={ref} className={tableCaptionStyles({ className })} {...props} />\n);\n\nTableCaption.displayName = \"TableCaption\";\n","/**\n * Геометрия линий иерархии.\n *\n * Значения связаны между собой — менять их можно только согласованно, поэтому производные\n * выражены формулами, а не числами.\n *\n * ```\n * ┌────────────────────────────────────────┐\n * │ ┌───┐ │\n * │ │ − │ Родитель │\n * │ └─┬─┘ │\n * ├─────┼──────────────────────────────────┤ ← граница ячеек; линию продлевает TREE_OVERHANG\n * │ │ ┌───┐ │\n * │ └────┤ + │ Потомок │ ← TREE_CONNECTOR_Y (центр первой строки)\n * │ └───┘ │\n * └────────────────────────────────────────┘\n *\n * ├─────┤ TREE_LINE_OFFSET — до вертикали нулевого уровня\n * ├──────┤ TREE_INDENT — шаг между вертикалями соседних уровней\n * ├────┤ TREE_STUB — отвод до левого края раскрывателя\n * ├───┤ TREE_TOGGLE — сторона квадрата, центр на своей вертикали\n * ```\n *\n * Схема не в масштабе — важны отношения величин, а не пропорции на картинке.\n */\n\n/** Шаг отступа на один уровень вложенности. */\nexport const TREE_INDENT = 18;\n\n/** Отступ от левого края ячейки до вертикали нулевой колонки. */\nexport const TREE_LINE_OFFSET = 13;\n\n/**\n * Сторона квадрата-раскрывателя. Центрируется ровно на вертикали своего уровня.\n *\n * Совпадает с чекбоксом (`size-4`): в одной строке они стоят рядом, и разный размер\n * у двух одинаковых по смыслу квадратов читается как небрежность.\n *\n * Сверху ограничен `2 * TREE_LINE_OFFSET` — иначе `treeCellPaddingLeft(0)` уходит в минус,\n * и раскрыватель корня вылезает за левый край ячейки. Практический потолок ниже:\n * при стороне больше `TREE_INDENT` обнуляется `TREE_STUB` и отвод к узлу исчезает.\n */\nexport const TREE_TOGGLE = 16;\n\n/**\n * Длина горизонтального отвода — от вертикали предка до левого края раскрывателя.\n *\n * Обязана равняться `TREE_INDENT - TREE_TOGGLE / 2`: раскрыватель смещён от своей вертикали\n * влево на половину стороны, и при любом другом значении между отводом и квадратом\n * остаётся щель либо отвод заезжает под квадрат.\n */\nexport const TREE_STUB = TREE_INDENT - TREE_TOGGLE / 2;\n\n/** Вертикальный паддинг ячейки таблицы (`py-2.5`). */\nconst TREE_CELL_PADDING_TOP = 10;\n\n/** Высота строки текста при `text-xs`. */\nconst TREE_TEXT_LINE_HEIGHT = 16;\n\n/**\n * Вертикальная позиция коннектора — центр ПЕРВОЙ строки текста, а не середина ячейки.\n *\n * Это принципиально для строк переменной высоты: при `top: 50%` середина ячейки уезжает вниз\n * от подписи, как только контент переносится, и уголок перестаёт указывать на узел.\n */\nexport const TREE_CONNECTOR_Y = TREE_CELL_PADDING_TOP + TREE_TEXT_LINE_HEIGHT / 2;\n\n/**\n * Насколько линии вылезают за padding-box ячейки сверху и снизу.\n *\n * Нижняя граница ячейки лежит вне её padding-box, и без этого выноса вертикаль обрывалась бы\n * на каждой границе — вместо сплошной линии получался пунктир.\n */\nexport const TREE_OVERHANG = 1;\n\n/**\n * Отступ раскрывателя сверху, при котором его центр совпадает с коннектором.\n *\n * Раньше здесь стоял `mt-0.5`, подобранный под сторону 12px. Теперь это разность:\n * содержимое ячейки начинается на `TREE_CELL_PADDING_TOP`, а центр квадрата должен\n * попасть на `TREE_CONNECTOR_Y`. При достаточно крупном раскрывателе значение\n * становится отрицательным — квадрат заходит в верхний паддинг, и это нормально.\n */\nexport const TREE_TOGGLE_MARGIN_TOP = TREE_CONNECTOR_Y - TREE_CELL_PADDING_TOP - TREE_TOGGLE / 2;\n\n/**\n * Горизонтальная позиция вертикали для колонки отступа.\n *\n * @example\n * treeLineX(0); // 13\n * treeLineX(2); // 49\n */\nexport const treeLineX = (column: number) => TREE_LINE_OFFSET + column * TREE_INDENT;\n\n/**\n * Левый отступ ячейки, при котором раскрыватель встаёт по центру вертикали своего уровня.\n *\n * @example\n * <TableCell style={{ paddingLeft: treeCellPaddingLeft(row.level) }}> // уровень 2 → 41px\n */\nexport const treeCellPaddingLeft = (level: number) => treeLineX(level) - TREE_TOGGLE / 2;\n","import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { Minus, Plus } from \"lucide-react\";\nimport { Icon } from \"../../icon/Icon\";\nimport { TableCell } from \"../Table\";\nimport { cn } from \"../../../lib/utils/cn\";\nimport {\n\tTREE_CONNECTOR_Y,\n\tTREE_OVERHANG,\n\tTREE_STUB,\n\tTREE_TOGGLE,\n\tTREE_TOGGLE_MARGIN_TOP,\n\ttreeCellPaddingLeft,\n\ttreeLineX\n} from \"./treeGeometry\";\nimport type { TreeLine, TreeRow } from \"./treeModel\";\n\nconst treeLineStyles = tv({\n\tbase: \"absolute bg-primary-border\",\n\tvariants: {\n\t\taxis: {\n\t\t\tvertical: \"w-px\",\n\t\t\thorizontal: \"h-px\"\n\t\t}\n\t}\n});\n\nexport type TableTreeLinesProps = {\n\t/**\n\t * Модель линий, по одному элементу на колонку отступа. Считается `flattenTree`.\n\t * Длина массива задаёт глубину узла — отдельный проп `level` не нужен.\n\t */\n\tlines: TreeLine[];\n\t/** Спуск от раскрывателя вниз, к первому потомку. Ставится у раскрытых узлов с потомками. */\n\tdescends?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Линии связи для строки дерева или группы.\n *\n * Кладётся в ячейку с `position: relative` и `padding-left: treeCellPaddingLeft(level)` —\n * обычно этим занимается `TableTreeCell`.\n *\n * Все линии — абсолютно позиционированные блоки в 1px, а не рамки контейнеров: уровни\n * вложенности в таблице не образуют вложенных DOM-узлов, поэтому рисовать `border-left`\n * на контейнере уровня попросту негде.\n *\n * Разметка повторяет модель один в один и размечена data-атрибутами: на обёртке лежит вся\n * модель строки (`data-tree-lines=\"pass none end\"`), на каждом элементе — его роль\n * (`data-tree-line`) и номер колонки. Это делает отладку в DevTools прямой: видно не только\n * то, что нарисовано, но и то, что было велено нарисовать.\n *\n * @example\n * <TableCell className=\"relative\" style={{ paddingLeft: treeCellPaddingLeft(row.level) }}>\n * <TableTreeLines lines={row.lines} descends={row.descends} />\n * {row.node.name}\n * </TableCell>\n */\nexport const TableTreeLines = ({ lines, descends = false, className }: TableTreeLinesProps) => (\n\t<span\n\t\taria-hidden\n\t\tdata-tree-lines={lines.join(\" \")}\n\t\tdata-tree-level={lines.length}\n\t\tclassName={cn(\"pointer-events-none absolute inset-0\", className)}\n\t>\n\t\t{lines.map((kind, column) => {\n\t\t\tif (kind === \"none\") return null;\n\n\t\t\treturn (\n\t\t\t\t<React.Fragment key={column}>\n\t\t\t\t\t<span\n\t\t\t\t\t\tdata-tree-line={kind}\n\t\t\t\t\t\tdata-tree-column={column}\n\t\t\t\t\t\tclassName={treeLineStyles({ axis: \"vertical\" })}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tleft: treeLineX(column),\n\t\t\t\t\t\t\ttop: -TREE_OVERHANG,\n\t\t\t\t\t\t\t// `end` — уголок: вертикаль обрывается на коннекторе, иначе протекла бы\n\t\t\t\t\t\t\t// под следующие строки, где ветки этого предка уже нет.\n\t\t\t\t\t\t\t...(kind === \"end\"\n\t\t\t\t\t\t\t\t? { height: TREE_CONNECTOR_Y + TREE_OVERHANG }\n\t\t\t\t\t\t\t\t: { bottom: -TREE_OVERHANG })\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t\t{kind !== \"pass\" && (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tdata-tree-line=\"stub\"\n\t\t\t\t\t\t\tdata-tree-column={column}\n\t\t\t\t\t\t\tclassName={treeLineStyles({ axis: \"horizontal\" })}\n\t\t\t\t\t\t\tstyle={{ left: treeLineX(column), top: TREE_CONNECTOR_Y, width: TREE_STUB }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</React.Fragment>\n\t\t\t);\n\t\t})}\n\n\t\t{descends && (\n\t\t\t<span\n\t\t\t\tdata-tree-line=\"spur\"\n\t\t\t\tdata-tree-column={lines.length}\n\t\t\t\tclassName={treeLineStyles({ axis: \"vertical\" })}\n\t\t\t\tstyle={{\n\t\t\t\t\tleft: treeLineX(lines.length),\n\t\t\t\t\ttop: TREE_CONNECTOR_Y + TREE_TOGGLE / 2,\n\t\t\t\t\tbottom: -TREE_OVERHANG\n\t\t\t\t}}\n\t\t\t/>\n\t\t)}\n\t</span>\n);\n\nTableTreeLines.displayName = \"TableTreeLines\";\n\nconst tableTreeToggleStyles = tv({\n\tbase: [\n\t\t// `z-10` поднимает раскрыватель над линиями, непрозрачный фон разрывает вертикаль под ним.\n\t\t\"relative z-10 flex shrink-0 items-center justify-center\",\n\t\t// Рамка, фон и скругление — как у `Checkbox`: в строке они стоят рядом и должны\n\t\t// читаться одинаково.\n\t\t\"rounded-sm border border-primary-border bg-secondary-bg text-muted\",\n\t\t\"hover:text-primary-fg focus-visible:shadow-focus focus-visible:outline-none\",\n\t\t// Невидимое расширение зоны нажатия до 24px. Именно псевдоэлементом, а не паддингом\n\t\t// или размером: квадрат обязан остаться на сетке линий, а промахиваться по 16px\n\t\t// на строке высотой 36px легко.\n\t\t\"before:absolute before:left-1/2 before:top-1/2 before:size-6 before:-translate-x-1/2 before:-translate-y-1/2\"\n\t]\n});\n\nexport type TableTreeToggleProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"children\"> & {\n\texpanded: boolean;\n};\n\n/** Квадрат раскрытия ветки. Иконка и `aria-expanded` следуют за `expanded`. */\nexport const TableTreeToggle = React.forwardRef<HTMLButtonElement, TableTreeToggleProps>(\n\t({ className, expanded, style, ...props }, ref) => (\n\t\t<button\n\t\t\tref={ref}\n\t\t\ttype=\"button\"\n\t\t\taria-expanded={expanded}\n\t\t\tclassName={tableTreeToggleStyles({ className })}\n\t\t\tstyle={{ width: TREE_TOGGLE, height: TREE_TOGGLE, marginTop: TREE_TOGGLE_MARGIN_TOP, ...style }}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Icon icon={expanded ? Minus : Plus} className=\"size-3\" />\n\t\t</button>\n\t)\n);\n\nTableTreeToggle.displayName = \"TableTreeToggle\";\n\n/**\n * Распорка на месте раскрывателя у листьев.\n *\n * Нужна, чтобы подписи узлов с потомками и без выравнивались по одной вертикали.\n * Отдельным компонентом, а не режимом `TableTreeToggle`, чтобы у листа не было\n * ни кнопки, ни `aria-expanded`.\n */\nexport const TableTreeSpacer = ({ className }: { className?: string }) => (\n\t<span aria-hidden className={cn(\"shrink-0\", className)} style={{ width: TREE_TOGGLE }} />\n);\n\nTableTreeSpacer.displayName = \"TableTreeSpacer\";\n\n/**\n * Всё, что ячейка иерархии знает о строке: где она стоит и что у неё с потомками.\n *\n * Структурный тип, а не generic: ячейке безразличен сам узел, поэтому в неё проходит любой\n * `TreeRow<T>` — и любой собранный вручную объект с этими пятью полями. Второе нужно там,\n * где дерева в памяти нет: список пришёл плоским, с готовым `level`, а линии считаются\n * `childTreeLines`.\n *\n * Инвариант: `lines.length === level`. Отступ берётся из `level`, а линии расставляются по\n * индексам `lines` — при расхождении уголок промахнётся мимо отступа.\n */\nexport type TableTreeCellRow = Pick<TreeRow<unknown>, \"level\" | \"lines\" | \"descends\" | \"hasChildren\" | \"isExpanded\">;\n\nexport type TableTreeCellProps = React.TdHTMLAttributes<HTMLTableCellElement> & {\n\t/**\n\t * Положение строки в иерархии: `level` — отступ, `lines` — линии связи, `descends` — спуск\n\t * к первому потомку, `hasChildren` — раскрыватель либо распорка на его месте, `isExpanded` —\n\t * знак в раскрывателе и `aria-expanded`.\n\t */\n\trow: TableTreeCellRow;\n\t/** Клик по раскрывателю. Без него раскрыватель рисуется, но ничего не делает. */\n\tonToggle?: React.MouseEventHandler<HTMLButtonElement>;\n\ttoggleLabel?: string;\n};\n\n/**\n * Ячейка с отступом, линиями и раскрывателем — весь столбец иерархии целиком.\n *\n * Собирает три вещи, которые иначе пришлось бы согласовывать вручную в каждой таблице:\n * `padding-left` по глубине, линии и раскрыватель либо распорку на его месте. Содержимое\n * остаётся за потребителем — внутрь идёт что угодно, от подписи до бейджей.\n *\n * `align-top` не косметика: при переносе текста в соседних колонках содержимое, выровненное\n * по центру, уедет вниз от коннектора, который привязан к первой строке.\n *\n * @example\n * <TableTreeCell row={row} onToggle={() => toggle(row.node.id)}>\n * {row.node.name}\n * </TableTreeCell>\n */\nexport const TableTreeCell = React.forwardRef<HTMLTableCellElement, TableTreeCellProps>(\n\t({ row, onToggle, toggleLabel, className, style, children, ...props }, ref) => (\n\t\t<TableCell\n\t\t\tref={ref}\n\t\t\tdata-tree-level={row.level}\n\t\t\tclassName={cn(\"relative align-top\", className)}\n\t\t\tstyle={{ paddingLeft: treeCellPaddingLeft(row.level), ...style }}\n\t\t\t{...props}\n\t\t>\n\t\t\t<TableTreeLines lines={row.lines} descends={row.descends} />\n\t\t\t<span className=\"flex items-start gap-1.5\">\n\t\t\t\t{row.hasChildren ? (\n\t\t\t\t\t<TableTreeToggle\n\t\t\t\t\t\texpanded={row.isExpanded}\n\t\t\t\t\t\taria-label={toggleLabel ?? (row.isExpanded ? \"Свернуть\" : \"Развернуть\")}\n\t\t\t\t\t\tonClick={onToggle}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<TableTreeSpacer />\n\t\t\t\t)}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t</TableCell>\n\t)\n);\n\nTableTreeCell.displayName = \"TableTreeCell\";\n","/**\n * Модель строки дерева: что рисовать в каждой колонке отступа.\n *\n * Ровно эти четыре состояния использует классический вывод `tree` и почти все табличные\n * гриды (AG Grid, TanStack Table, rc-tree) — набор проверен и закрывает все случаи:\n *\n * - `pass` — сквозная вертикаль `│`: ветка предка продолжается ниже этой строки;\n * - `branch` — `├`: отвод к узлу, и у узла есть следующие соседи;\n * - `end` — `└`: отвод к последнему соседу, вертикаль обрывается на уголке;\n * - `none` — пусто: ветка предка закончилась выше.\n *\n * Ключевой инвариант: **индекс в массиве равен номеру колонки**, а `lines.length` равно\n * глубине узла. `branch`/`end` встречается только в последней колонке, `pass`/`none` — только\n * в предыдущих. Именно этот инвариант убирает класс ошибок «сдвиг на единицу»: раньше\n * массив хранил флаги предков, и колонка `level - 1` управлялась флагом родителя, хотя\n * должна была — признаком `isLast` самого узла. Сравнивать модель с картинкой теперь можно\n * глазами: `[\"pass\", \"none\", \"end\"]` читается как `│ └`.\n */\nexport type TreeLine = \"none\" | \"pass\" | \"branch\" | \"end\";\n\n/** Строка плоского списка со всем, что нужно для отрисовки узла дерева. */\nexport type TreeRow<T> = {\n\tnode: T;\n\t/** Родительский узел, `null` у корней. */\n\tparent: T | null;\n\t/** Глубина, 0 — корень. Равна `lines.length`. */\n\tlevel: number;\n\t/** Позиция среди соседей. */\n\tindex: number;\n\t/** Последний ли среди соседей — от этого зависит `└` вместо `├`. */\n\tisLast: boolean;\n\thasChildren: boolean;\n\t/** Раскрыт ли узел. У листьев всегда `false`. */\n\tisExpanded: boolean;\n\t/**\n\t * Нужен ли спуск от раскрывателя вниз, к первому потомку.\n\t *\n\t * Вертикаль потомка начинается от его собственной строки, поэтому участок между\n\t * раскрывателем и низом строки родителя рисует именно родитель.\n\t */\n\tdescends: boolean;\n\tlines: TreeLine[];\n\t/** Индексы от корня: `[0, 2, 1]`. Годится как стабильный ключ и как «1.3.2» в интерфейсе. */\n\tpath: number[];\n};\n\nexport type FlattenTreeOptions<T> = {\n\t/**\n\t * Потомки узла. Это функция поиска, а не имя поля: плоскому списку с `parentId` хватит\n\t * индекса `Map<parentId, T[]>`, перекладывать данные в узлы с `children` не нужно.\n\t */\n\tgetChildren: (node: T) => T[] | undefined;\n\t/** Раскрыт ли узел. Свёрнутые не отдают потомков. По умолчанию раскрыты все. */\n\tisExpanded?: (node: T) => boolean;\n};\n\n/**\n * Линии потомка, выведенные из линий родителя.\n *\n * Весь алгоритм — в двух строчках: у предков уголок превращается в продолжение (`branch` →\n * `pass`), а обрыв — в пустоту (`end` → `none`); своя колонка получает уголок по `isLast`.\n * Экспортируется отдельно, чтобы линии можно было считать и без обхода дерева — например,\n * для виртуализованного или подгружаемого списка, где полного дерева в памяти нет.\n *\n * Родительские линии в плоском списке удобно держать бегущим массивом `linesByLevel[level]`:\n * в списке, упорядоченном как при выводе, родитель всегда встречается раньше потомка.\n *\n * @example\n * childTreeLines([\"pass\", \"branch\"], false); // [\"pass\", \"pass\", \"branch\"]\n * childTreeLines([\"pass\", \"branch\"], true); // [\"pass\", \"pass\", \"end\"]\n */\nexport const childTreeLines = (parentLines: TreeLine[], isLast: boolean): TreeLine[] => [\n\t...parentLines.map((line): TreeLine => (line === \"pass\" || line === \"branch\" ? \"pass\" : \"none\")),\n\tisLast ? \"end\" : \"branch\"\n];\n\n/**\n * Разворачивает дерево в плоский список строк и попутно считает модель линий.\n *\n * Порядок — как при отображении: узел, затем его раскрытые потомки.\n *\n * @example\n * const rows = flattenTree(nodes, {\n * getChildren: (node) => node.children,\n * isExpanded: (node) => expanded.has(node.id)\n * });\n *\n * rows.map((row) => (\n * <TableRow key={row.path.join(\".\")}>\n * <TableTreeCell row={row} onToggle={() => toggle(row.node.id)}>{row.node.name}</TableTreeCell>\n * </TableRow>\n * ));\n */\nexport function flattenTree<T>(roots: T[], options: FlattenTreeOptions<T>): TreeRow<T>[] {\n\tconst { getChildren, isExpanded = () => true } = options;\n\tconst rows: TreeRow<T>[] = [];\n\n\tconst walk = (nodes: T[], parent: T | null, level: number, parentLines: TreeLine[], parentPath: number[]) => {\n\t\tnodes.forEach((node, index) => {\n\t\t\tconst isLast = index === nodes.length - 1;\n\t\t\tconst children = getChildren(node);\n\t\t\tconst hasChildren = Boolean(children?.length);\n\t\t\tconst expanded = hasChildren && isExpanded(node);\n\t\t\t// У корней нет предка — значит, нет и колонок отступа.\n\t\t\tconst lines = level === 0 ? [] : childTreeLines(parentLines, isLast);\n\t\t\tconst path = [...parentPath, index];\n\n\t\t\trows.push({\n\t\t\t\tnode,\n\t\t\t\tparent,\n\t\t\t\tlevel,\n\t\t\t\tindex,\n\t\t\t\tisLast,\n\t\t\t\thasChildren,\n\t\t\t\tisExpanded: expanded,\n\t\t\t\tdescends: expanded,\n\t\t\t\tlines,\n\t\t\t\tpath\n\t\t\t});\n\n\t\t\tif (expanded) walk(children!, node, level + 1, lines, path);\n\t\t});\n\t};\n\n\twalk(roots, null, 0, [], []);\n\treturn rows;\n}\n"],"names":["tableStyles","tv","Table","React","className","containerClassName","containerRef","props","ref","styles","jsx","tableHeaderStyles","STICKY_HEADER","TableHeader","sticky","tableBodyStyles","TableBody","tableBodyContainerStyles","TableBodyContainer","shadowSize","ScrollShadowContainer","tableFooterStyles","STICKY_FOOTER","TableFooter","TABLE_ROW_ANATOMY","tableRowStyles","TABLE_ROW_TINT_LAYERS","TableRow","tableHeadStyles","TableHead","interactive","tableCellStyles","TableCell","tableResizeHandleStyles","TableResizeHandle","active","tableCaptionStyles","TableCaption","TREE_INDENT","TREE_LINE_OFFSET","TREE_TOGGLE","TREE_STUB","TREE_CELL_PADDING_TOP","TREE_TEXT_LINE_HEIGHT","TREE_CONNECTOR_Y","TREE_OVERHANG","TREE_TOGGLE_MARGIN_TOP","treeLineX","column","treeCellPaddingLeft","level","treeLineStyles","TableTreeLines","lines","descends","jsxs","cn","kind","tableTreeToggleStyles","TableTreeToggle","expanded","style","Icon","Minus","Plus","TableTreeSpacer","TableTreeCell","row","onToggle","toggleLabel","children","childTreeLines","parentLines","isLast","line","flattenTree","roots","options","getChildren","isExpanded","rows","walk","nodes","parent","parentPath","node","index","hasChildren","path"],"mappings":"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"}
1
+ {"version":3,"file":"treeModel-jvOXFZvK.js","sources":["../src/components/table/Table.tsx","../src/components/table/tree/treeGeometry.ts","../src/components/table/tree/TableTree.tsx","../src/components/table/tree/treeModel.ts"],"sourcesContent":["import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { ScrollShadowContainer } from \"../scroll-shadow-container\";\nimport { STICKY_FOOTER, STICKY_HEADER } from \"./sticky/stickyCell\";\nimport { ScrollShadowContainerProps } from \"../scroll-shadow-container/ScrollShadowContainer\";\nimport { TABLE_ROW_TINT_LAYERS } from \"./rowTint\";\n\nconst tableStyles = tv({\n\tslots: {\n\t\twrapper: \"relative w-full overflow-x-auto rounded-lg border border-secondary-border\",\n\n\t\t// Раздельная модель границ вместо схлопнутой (умолчание Tailwind для таблиц).\n\t\t// В схлопнутой модели граница принадлежит сетке таблицы, а не ячейке: `position: sticky`\n\t\t// и `transform` уносят ячейку, а линия остаётся стоять на старом месте — из-за этого\n\t\t// прилипающим шапке и колонке приходилось гасить границу и рисовать её inset-тенью.\n\t\t// В раздельной модели граница входит в бокс ячейки и едет вместе с ней.\n\t\t//\n\t\t// Плата: `border` у групп строк (`thead`, `tbody`, `tfoot`) и у самих `tr` браузер\n\t\t// обязан игнорировать, поэтому все разделители живут на ячейках — см. `TABLE_ROW_ANATOMY`,\n\t\t// `tableHeaderStyles` и `tableFooterStyles`.\n\t\ttable: \"w-full caption-bottom border-separate border-spacing-0 text-xs\"\n\t}\n});\n\nexport type TableProps = React.HTMLAttributes<HTMLTableElement> & {\n\tcontainerClassName?: string;\n\tcontainerRef?: React.Ref<HTMLDivElement>;\n};\n\nexport const Table = React.forwardRef<HTMLTableElement, TableProps>(\n\t({ className, containerClassName, containerRef, ...props }, ref) => {\n\t\tconst styles = tableStyles();\n\n\t\treturn (\n\t\t\t<div ref={containerRef} className={styles.wrapper({ className: containerClassName })}>\n\t\t\t\t<table ref={ref} className={styles.table({ className })} {...props} />\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nTable.displayName = \"Table\";\n\nconst tableHeaderStyles = tv({\n\t// Линия под шапкой — на ячейках, а не на `thead`: `border` у групп строк в раздельной\n\t// модели игнорируется (см. `tableStyles`). Заодно это ровно то, что нужно прилипающей\n\t// шапке: граница ячейки уезжает вместе с ячейкой, а не остаётся в сетке таблицы.\n\t//\n\t// Ту же нижнюю границу ячейкам шапки даёт и `TableRow`; дубль намеренный — разделитель\n\t// шапки и тела это контракт самого `TableHeader`, и он не должен пропадать из-за голого\n\t// `<tr>` в разметке потребителя. Одинаковые объявления одного свойства линию не задваивают.\n\t//\n\tbase: \"bg-primary-bg [&_th]:border-b [&_th]:border-secondary-border [&_tr]:[--table-row-bg-hover:transparent]\",\n\tvariants: {\n\t\tsticky: {\n\t\t\ttrue: STICKY_HEADER\n\t\t}\n\t}\n});\n\nexport type TableHeaderProps = React.HTMLAttributes<HTMLTableSectionElement> & {\n\t/**\n\t * Шапка остаётся на месте при вертикальной прокрутке.\n\t *\n\t * Прокручивается контейнер таблицы, поэтому ему нужна ограниченная высота\n\t * (`containerClassName=\"max-h-80\"`): без неё прокручивать нечего и `position: sticky`\n\t * ничего не делает.\n\t *\n\t * Проп, а не набор классов в `className`, потому что вместе со `sticky` требуется\n\t * `z-index`, согласованный с закреплёнными колонками, — это знание кита, а не\n\t * потребителя (см. `STICKY_HEADER`).\n\t */\n\tsticky?: boolean;\n};\n\nexport const TableHeader = React.forwardRef<HTMLTableSectionElement, TableHeaderProps>(\n\t({ className, sticky, ...props }, ref) => (\n\t\t<thead ref={ref} className={tableHeaderStyles({ sticky, className })} {...props} />\n\t)\n);\n\nTableHeader.displayName = \"TableHeader\";\n\nconst tableBodyStyles = tv({\n\tbase: \"bg-secondary-bg [&_tr:last-child>*]:border-b-0\"\n});\n\nexport const TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(\n\t({ className, ...props }, ref) => <tbody ref={ref} className={tableBodyStyles({ className })} {...props} />\n);\n\nTableBody.displayName = \"TableBody\";\n\nconst tableBodyContainerStyles = tv({\n\tbase: \"overflow-x-hidden\"\n});\n\nexport type TableBodyContainerProps = React.HTMLAttributes<HTMLTableSectionElement> & {\n\tcontainerClassName?: string;\n\tshadowSize?: ScrollShadowContainerProps[\"shadowSize\"];\n};\n\nexport const TableBodyContainer = React.forwardRef<HTMLTableSectionElement, TableBodyContainerProps>(\n\t({ className, containerClassName, shadowSize, ...props }, ref) => (\n\t\t<ScrollShadowContainer\n\t\t\tclassName={tableBodyContainerStyles({ className: containerClassName })}\n\t\t\tshadowSize={shadowSize}\n\t\t>\n\t\t\t<tbody ref={ref} className={tableBodyStyles({ className })} {...props} />\n\t\t</ScrollShadowContainer>\n\t)\n);\n\nTableBodyContainer.displayName = \"TableBodyContainer\";\n\nconst tableFooterStyles = tv({\n\t// Верхняя граница — на ячейках первой строки, нижняя снимается с ячеек последней:\n\t// собственный `border` у `tfoot` в раздельной модели игнорируется (см. `tableStyles`).\n\tbase: [\n\t\t\"bg-primary-bg font-medium\",\n\t\t\"[&>tr:first-child>*]:border-t [&>tr:first-child>*]:border-secondary-border\",\n\t\t\"[&>tr:last-child>*]:border-b-0\"\n\t],\n\tvariants: {\n\t\tsticky: {\n\t\t\ttrue: STICKY_FOOTER\n\t\t}\n\t}\n});\n\nexport type TableFooterProps = React.HTMLAttributes<HTMLTableSectionElement> & {\n\t/**\n\t * Итоги остаются на месте при вертикальной прокрутке.\n\t *\n\t * Зеркало `sticky` у `TableHeader`, и требует того же: прокручивается контейнер таблицы,\n\t * поэтому у него должна быть ограниченная высота — без неё прокручивать нечего.\n\t *\n\t * Проп, а не классы в `className`, по той же причине, что и у шапки: вместе со `sticky`\n\t * нужен `z-index`, согласованный с закреплёнными колонками (см. `STICKY_FOOTER`).\n\t */\n\tsticky?: boolean;\n};\n\nexport const TableFooter = React.forwardRef<HTMLTableSectionElement, TableFooterProps>(\n\t({ className, sticky, ...props }, ref) => (\n\t\t<tfoot ref={ref} className={tableFooterStyles({ sticky, className })} {...props} />\n\t)\n);\n\nTableFooter.displayName = \"TableFooter\";\n\nconst TABLE_ROW_ANATOMY = \"[&>*]:border-b [&>*]:border-secondary-border transition-colors\";\n\n/**\n * Строка красится двумя вещами: заливкой и слоями подкраски поверх неё.\n *\n * **Заливка** — `--table-row-bg` и `--table-row-bg-hover`: обычная строка и наведённая.\n * Это всё, что кит знает про цвет строки; ни выделения, ни деактивации у примитива нет —\n * что означает подсветка и когда её включать, знает прикладной код (см. `rowTint.ts`).\n *\n * **Слои подкраски** — `--table-row-tints`, их выставляет потребитель через `tableRowTints()`.\n * Полупрозрачные цвета поверх заливки: альфы складываются и между собой, и с заливкой, поэтому\n * выделенная деактивированная строка показывает обе подсветки, а не одну.\n *\n * Заливка и слои разведены не только по смыслу, но и по свойству: `background-color` против\n * `background-image`. Поэтому `className=\"bg-…\"` вытесняет заливку — и только её: слои\n * останутся на месте и лягут поверх любого цвета, который выбрал потребитель.\n */\nconst tableRowStyles = tv({\n\tbase: [\n\t\tTABLE_ROW_ANATOMY,\n\n\t\t// Заливку читает ровно один класс на состояние — обычный `bg-*` и `hover:bg-*`, —\n\t\t// поэтому любой `bg-*` из `className` вытесняет её штатно, без `!important`\n\t\t// и без повторения модификаторов.\n\t\t\"bg-[color:var(--table-row-bg)] hover:bg-[color:var(--table-row-bg-hover)]\",\n\n\t\t// Обычная строка: подложку даёт `TableBody`, ховер — нейтральная альфа поверх неё\n\t\t// (`alpha/high/97` в макете подписана как состояние строки `hover`).\n\t\t\"[--table-row-bg-hover:hsl(var(--alpha-high-03))] [--table-row-bg:transparent]\",\n\n\t\tTABLE_ROW_TINT_LAYERS\n\t]\n});\n\nexport type TableRowProps = React.HTMLAttributes<HTMLTableRowElement>;\n\n/**\n * Строка таблицы.\n *\n * **Как перекрасить.** Обычными классами: `className=\"bg-… hover:bg-…\"`. Они выигрывают\n * штатно — ни `!important`, ни повторения модификаторов не нужно. Кто хочет сохранить\n * встроенное наведение и подменить только палитру — выставляет переменные `--table-row-bg`\n * и `--table-row-bg-hover`.\n *\n * **Как подсветить.** Слоями: `style={tableRowTints(…)}`, готовые цвета — в `TABLE_ROW_TINT`.\n * Слои складываются друг с другом и ложатся поверх заливки, какой бы она ни была, поэтому\n * подсветка и перекраска не конфликтуют. Подробности — в `rowTint.ts`.\n *\n * **Почему цвет читают отдельные классы, а не состояния.** Раньше `base` красил строку\n * четырьмя классами (`hover:bg-*`, `data-[state=selected]:bg-*`,\n * `data-[state=selected]:hover:bg-*`), и перебить их снаружи было нечем: `tailwind-merge`\n * снимает конфликт только между классами с одинаковым набором модификаторов, поэтому `bg-x`\n * из `className` не вытеснял ни один из них, а `data-[state=selected]:bg-*` вдобавок выигрывал\n * по специфичности — 0,2,0 против 0,1,0. Потребителю приходилось вручную повторять все четыре\n * комбинации модификаторов.\n */\nexport const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(({ className, ...props }, ref) => (\n\t<tr ref={ref} className={tableRowStyles({ className })} {...props} />\n));\n\nTableRow.displayName = \"TableRow\";\n\nconst tableHeadStyles = tv({\n\tbase: \"border-r border-secondary-border px-3 py-2.5 text-left align-middle font-medium text-muted last:border-r-0\",\n\tvariants: {\n\t\tinteractive: {\n\t\t\ttrue: [\n\t\t\t\t\"cursor-pointer p-0 transition-colors\",\n\t\t\t\t\"hover:bg-secondary-bg-hover\",\n\t\t\t\t\"data-[state=open]:bg-primary-bg-hover [&:has([data-state=open])]:bg-primary-bg-hover\"\n\t\t\t]\n\t\t}\n\t}\n});\n\nexport type TableHeadProps = React.ThHTMLAttributes<HTMLTableCellElement> & {\n\t/**\n\t * Вся ячейка — интерактивная зона: меняет фон на наведении и на раскрытом меню,\n\t * и снимает собственный паддинг в пользу растянутого на всю ячейку триггера.\n\t */\n\tinteractive?: boolean;\n};\n\nexport const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps>(\n\t({ className, interactive, ...props }, ref) => (\n\t\t<th ref={ref} className={tableHeadStyles({ interactive, className })} {...props} />\n\t)\n);\n\nTableHead.displayName = \"TableHead\";\n\nconst tableCellStyles = tv({\n\tbase: \"border-r border-secondary-border px-3 py-2.5 align-middle last:border-r-0 [&:has([role=checkbox])]:pr-0\"\n});\n\nexport const TableCell = React.forwardRef<HTMLTableCellElement, React.TdHTMLAttributes<HTMLTableCellElement>>(\n\t({ className, ...props }, ref) => <td ref={ref} className={tableCellStyles({ className })} {...props} />\n);\n\nTableCell.displayName = \"TableCell\";\n\nconst tableResizeHandleStyles = tv({\n\tbase: [\n\t\t\"absolute right-0 top-0 z-10 h-full w-2 translate-x-1/2 cursor-col-resize touch-none select-none\",\n\t\t\"after:absolute after:left-1/2 after:top-0 after:h-full after:w-0.5 after:-translate-x-1/2\",\n\t\t\"after:bg-primary-border after:opacity-0 after:transition-opacity hover:after:opacity-100\"\n\t],\n\tvariants: {\n\t\tactive: {\n\t\t\ttrue: \"after:opacity-100\"\n\t\t}\n\t}\n});\n\nexport type TableResizeHandleProps = React.HTMLAttributes<HTMLDivElement> & {\n\t/** Держит индикатор подсвеченным во время drag-сессии, когда курсор уже ушёл с ручки. */\n\tactive?: boolean;\n};\n\n/**\n * Зона захвата для ресайза колонки. Кладётся внутрь `TableHead`, которому нужен `relative`.\n * Саму ширину не считает — работает в паре с `useColumnResize` из `./column-resize`.\n * Работает только если у `TableHead` нет `overflow: hidden`.\n */\nexport const TableResizeHandle = React.forwardRef<HTMLDivElement, TableResizeHandleProps>(\n\t({ className, active, ...props }, ref) => (\n\t\t<div\n\t\t\tref={ref}\n\t\t\trole=\"separator\"\n\t\t\taria-orientation=\"vertical\"\n\t\t\tclassName={tableResizeHandleStyles({ active, className })}\n\t\t\t{...props}\n\t\t/>\n\t)\n);\n\nTableResizeHandle.displayName = \"TableResizeHandle\";\n\nconst tableCaptionStyles = tv({\n\tbase: \"mt-4 text-muted\"\n});\n\nexport const TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(\n\t({ className, ...props }, ref) => <caption ref={ref} className={tableCaptionStyles({ className })} {...props} />\n);\n\nTableCaption.displayName = \"TableCaption\";\n","/**\n * Геометрия линий иерархии.\n *\n * Значения связаны между собой — менять их можно только согласованно, поэтому производные\n * выражены формулами, а не числами.\n *\n * ```\n * ┌────────────────────────────────────────┐\n * │ ┌───┐ │\n * │ │ − │ Родитель │\n * │ └─┬─┘ │\n * ├─────┼──────────────────────────────────┤ ← граница ячеек; линию продлевает TREE_OVERHANG\n * │ │ ┌───┐ │\n * │ └────┤ + │ Потомок │ ← TREE_CONNECTOR_Y (центр первой строки)\n * │ └───┘ │\n * └────────────────────────────────────────┘\n *\n * ├─────┤ TREE_LINE_OFFSET — до вертикали нулевого уровня\n * ├──────┤ TREE_INDENT — шаг между вертикалями соседних уровней\n * ├────┤ TREE_STUB — отвод до левого края раскрывателя\n * ├───┤ TREE_TOGGLE — сторона квадрата, центр на своей вертикали\n * ```\n *\n * Схема не в масштабе — важны отношения величин, а не пропорции на картинке.\n */\n\n/** Шаг отступа на один уровень вложенности. */\nexport const TREE_INDENT = 18;\n\n/** Отступ от левого края ячейки до вертикали нулевой колонки. */\nexport const TREE_LINE_OFFSET = 13;\n\n/**\n * Сторона квадрата-раскрывателя. Центрируется ровно на вертикали своего уровня.\n *\n * Совпадает с чекбоксом (`size-4`): в одной строке они стоят рядом, и разный размер\n * у двух одинаковых по смыслу квадратов читается как небрежность.\n *\n * Сверху ограничен `2 * TREE_LINE_OFFSET` — иначе `treeCellPaddingLeft(0)` уходит в минус,\n * и раскрыватель корня вылезает за левый край ячейки. Практический потолок ниже:\n * при стороне больше `TREE_INDENT` обнуляется `TREE_STUB` и отвод к узлу исчезает.\n */\nexport const TREE_TOGGLE = 16;\n\n/**\n * Длина горизонтального отвода — от вертикали предка до левого края раскрывателя.\n *\n * Обязана равняться `TREE_INDENT - TREE_TOGGLE / 2`: раскрыватель смещён от своей вертикали\n * влево на половину стороны, и при любом другом значении между отводом и квадратом\n * остаётся щель либо отвод заезжает под квадрат.\n */\nexport const TREE_STUB = TREE_INDENT - TREE_TOGGLE / 2;\n\n/** Вертикальный паддинг ячейки таблицы (`py-2.5`). */\nconst TREE_CELL_PADDING_TOP = 10;\n\n/** Высота строки текста при `text-xs`. */\nconst TREE_TEXT_LINE_HEIGHT = 16;\n\n/**\n * Вертикальная позиция коннектора — центр ПЕРВОЙ строки текста, а не середина ячейки.\n *\n * Это принципиально для строк переменной высоты: при `top: 50%` середина ячейки уезжает вниз\n * от подписи, как только контент переносится, и уголок перестаёт указывать на узел.\n */\nexport const TREE_CONNECTOR_Y = TREE_CELL_PADDING_TOP + TREE_TEXT_LINE_HEIGHT / 2;\n\n/**\n * Насколько линии вылезают за padding-box ячейки сверху и снизу.\n *\n * Нижняя граница ячейки лежит вне её padding-box, и без этого выноса вертикаль обрывалась бы\n * на каждой границе — вместо сплошной линии получался пунктир.\n */\nexport const TREE_OVERHANG = 1;\n\n/**\n * Отступ раскрывателя сверху, при котором его центр совпадает с коннектором.\n *\n * Раньше здесь стоял `mt-0.5`, подобранный под сторону 12px. Теперь это разность:\n * содержимое ячейки начинается на `TREE_CELL_PADDING_TOP`, а центр квадрата должен\n * попасть на `TREE_CONNECTOR_Y`. При достаточно крупном раскрывателе значение\n * становится отрицательным — квадрат заходит в верхний паддинг, и это нормально.\n */\nexport const TREE_TOGGLE_MARGIN_TOP = TREE_CONNECTOR_Y - TREE_CELL_PADDING_TOP - TREE_TOGGLE / 2;\n\n/**\n * Горизонтальная позиция вертикали для колонки отступа.\n *\n * @example\n * treeLineX(0); // 13\n * treeLineX(2); // 49\n */\nexport const treeLineX = (column: number) => TREE_LINE_OFFSET + column * TREE_INDENT;\n\n/**\n * Левый отступ ячейки, при котором раскрыватель встаёт по центру вертикали своего уровня.\n *\n * @example\n * <TableCell style={{ paddingLeft: treeCellPaddingLeft(row.level) }}> // уровень 2 → 41px\n */\nexport const treeCellPaddingLeft = (level: number) => treeLineX(level) - TREE_TOGGLE / 2;\n","import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { Minus, Plus } from \"lucide-react\";\nimport { Icon } from \"../../icon/Icon\";\nimport { TableCell } from \"../Table\";\nimport { cn } from \"../../../lib/utils/cn\";\nimport {\n\tTREE_CONNECTOR_Y,\n\tTREE_OVERHANG,\n\tTREE_STUB,\n\tTREE_TOGGLE,\n\tTREE_TOGGLE_MARGIN_TOP,\n\ttreeCellPaddingLeft,\n\ttreeLineX\n} from \"./treeGeometry\";\nimport type { TreeLine, TreeRow } from \"./treeModel\";\n\nconst treeLineStyles = tv({\n\tbase: \"absolute bg-primary-border\",\n\tvariants: {\n\t\taxis: {\n\t\t\tvertical: \"w-px\",\n\t\t\thorizontal: \"h-px\"\n\t\t}\n\t}\n});\n\nexport type TableTreeLinesProps = {\n\t/**\n\t * Модель линий, по одному элементу на колонку отступа. Считается `flattenTree`.\n\t * Длина массива задаёт глубину узла — отдельный проп `level` не нужен.\n\t */\n\tlines: TreeLine[];\n\t/** Спуск от раскрывателя вниз, к первому потомку. Ставится у раскрытых узлов с потомками. */\n\tdescends?: boolean;\n\tclassName?: string;\n};\n\n/**\n * Линии связи для строки дерева или группы.\n *\n * Кладётся в ячейку с `position: relative` и `padding-left: treeCellPaddingLeft(level)` —\n * обычно этим занимается `TableTreeCell`.\n *\n * Все линии — абсолютно позиционированные блоки в 1px, а не рамки контейнеров: уровни\n * вложенности в таблице не образуют вложенных DOM-узлов, поэтому рисовать `border-left`\n * на контейнере уровня попросту негде.\n *\n * Разметка повторяет модель один в один и размечена data-атрибутами: на обёртке лежит вся\n * модель строки (`data-tree-lines=\"pass none end\"`), на каждом элементе — его роль\n * (`data-tree-line`) и номер колонки. Это делает отладку в DevTools прямой: видно не только\n * то, что нарисовано, но и то, что было велено нарисовать.\n *\n * @example\n * <TableCell className=\"relative\" style={{ paddingLeft: treeCellPaddingLeft(row.level) }}>\n * <TableTreeLines lines={row.lines} descends={row.descends} />\n * {row.node.name}\n * </TableCell>\n */\nexport const TableTreeLines = ({ lines, descends = false, className }: TableTreeLinesProps) => (\n\t<span\n\t\taria-hidden\n\t\tdata-tree-lines={lines.join(\" \")}\n\t\tdata-tree-level={lines.length}\n\t\tclassName={cn(\"pointer-events-none absolute inset-0\", className)}\n\t>\n\t\t{lines.map((kind, column) => {\n\t\t\tif (kind === \"none\") return null;\n\n\t\t\treturn (\n\t\t\t\t<React.Fragment key={column}>\n\t\t\t\t\t<span\n\t\t\t\t\t\tdata-tree-line={kind}\n\t\t\t\t\t\tdata-tree-column={column}\n\t\t\t\t\t\tclassName={treeLineStyles({ axis: \"vertical\" })}\n\t\t\t\t\t\tstyle={{\n\t\t\t\t\t\t\tleft: treeLineX(column),\n\t\t\t\t\t\t\ttop: -TREE_OVERHANG,\n\t\t\t\t\t\t\t// `end` — уголок: вертикаль обрывается на коннекторе, иначе протекла бы\n\t\t\t\t\t\t\t// под следующие строки, где ветки этого предка уже нет.\n\t\t\t\t\t\t\t...(kind === \"end\"\n\t\t\t\t\t\t\t\t? { height: TREE_CONNECTOR_Y + TREE_OVERHANG }\n\t\t\t\t\t\t\t\t: { bottom: -TREE_OVERHANG })\n\t\t\t\t\t\t}}\n\t\t\t\t\t/>\n\t\t\t\t\t{kind !== \"pass\" && (\n\t\t\t\t\t\t<span\n\t\t\t\t\t\t\tdata-tree-line=\"stub\"\n\t\t\t\t\t\t\tdata-tree-column={column}\n\t\t\t\t\t\t\tclassName={treeLineStyles({ axis: \"horizontal\" })}\n\t\t\t\t\t\t\tstyle={{ left: treeLineX(column), top: TREE_CONNECTOR_Y, width: TREE_STUB }}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</React.Fragment>\n\t\t\t);\n\t\t})}\n\n\t\t{descends && (\n\t\t\t<span\n\t\t\t\tdata-tree-line=\"spur\"\n\t\t\t\tdata-tree-column={lines.length}\n\t\t\t\tclassName={treeLineStyles({ axis: \"vertical\" })}\n\t\t\t\tstyle={{\n\t\t\t\t\tleft: treeLineX(lines.length),\n\t\t\t\t\ttop: TREE_CONNECTOR_Y + TREE_TOGGLE / 2,\n\t\t\t\t\tbottom: -TREE_OVERHANG\n\t\t\t\t}}\n\t\t\t/>\n\t\t)}\n\t</span>\n);\n\nTableTreeLines.displayName = \"TableTreeLines\";\n\nconst tableTreeToggleStyles = tv({\n\tbase: [\n\t\t// `z-10` поднимает раскрыватель над линиями, непрозрачный фон разрывает вертикаль под ним.\n\t\t\"relative z-10 flex shrink-0 items-center justify-center\",\n\t\t// Рамка, фон и скругление — как у `Checkbox`: в строке они стоят рядом и должны\n\t\t// читаться одинаково.\n\t\t\"rounded-sm border border-primary-border bg-secondary-bg text-muted\",\n\t\t\"hover:text-primary-fg focus-visible:shadow-focus focus-visible:outline-none\",\n\t\t// Невидимое расширение зоны нажатия до 24px. Именно псевдоэлементом, а не паддингом\n\t\t// или размером: квадрат обязан остаться на сетке линий, а промахиваться по 16px\n\t\t// на строке высотой 36px легко.\n\t\t\"before:absolute before:left-1/2 before:top-1/2 before:size-6 before:-translate-x-1/2 before:-translate-y-1/2\"\n\t]\n});\n\nexport type TableTreeToggleProps = Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"children\"> & {\n\texpanded: boolean;\n};\n\n/** Квадрат раскрытия ветки. Иконка и `aria-expanded` следуют за `expanded`. */\nexport const TableTreeToggle = React.forwardRef<HTMLButtonElement, TableTreeToggleProps>(\n\t({ className, expanded, style, ...props }, ref) => (\n\t\t<button\n\t\t\tref={ref}\n\t\t\ttype=\"button\"\n\t\t\taria-expanded={expanded}\n\t\t\tclassName={tableTreeToggleStyles({ className })}\n\t\t\tstyle={{ width: TREE_TOGGLE, height: TREE_TOGGLE, marginTop: TREE_TOGGLE_MARGIN_TOP, ...style }}\n\t\t\t{...props}\n\t\t>\n\t\t\t<Icon icon={expanded ? Minus : Plus} className=\"size-3\" />\n\t\t</button>\n\t)\n);\n\nTableTreeToggle.displayName = \"TableTreeToggle\";\n\n/**\n * Распорка на месте раскрывателя у листьев.\n *\n * Нужна, чтобы подписи узлов с потомками и без выравнивались по одной вертикали.\n * Отдельным компонентом, а не режимом `TableTreeToggle`, чтобы у листа не было\n * ни кнопки, ни `aria-expanded`.\n */\nexport const TableTreeSpacer = ({ className }: { className?: string }) => (\n\t<span aria-hidden className={cn(\"shrink-0\", className)} style={{ width: TREE_TOGGLE }} />\n);\n\nTableTreeSpacer.displayName = \"TableTreeSpacer\";\n\n/**\n * Всё, что ячейка иерархии знает о строке: где она стоит и что у неё с потомками.\n *\n * Структурный тип, а не generic: ячейке безразличен сам узел, поэтому в неё проходит любой\n * `TreeRow<T>` — и любой собранный вручную объект с этими пятью полями. Второе нужно там,\n * где дерева в памяти нет: список пришёл плоским, с готовым `level`, а линии считаются\n * `childTreeLines`.\n *\n * Инвариант: `lines.length === level`. Отступ берётся из `level`, а линии расставляются по\n * индексам `lines` — при расхождении уголок промахнётся мимо отступа.\n */\nexport type TableTreeCellRow = Pick<TreeRow<unknown>, \"level\" | \"lines\" | \"descends\" | \"hasChildren\" | \"isExpanded\">;\n\nexport type TableTreeCellProps = React.TdHTMLAttributes<HTMLTableCellElement> & {\n\t/**\n\t * Положение строки в иерархии: `level` — отступ, `lines` — линии связи, `descends` — спуск\n\t * к первому потомку, `hasChildren` — раскрыватель либо распорка на его месте, `isExpanded` —\n\t * знак в раскрывателе и `aria-expanded`.\n\t */\n\trow: TableTreeCellRow;\n\t/** Клик по раскрывателю. Без него раскрыватель рисуется, но ничего не делает. */\n\tonToggle?: React.MouseEventHandler<HTMLButtonElement>;\n\ttoggleLabel?: string;\n};\n\n/**\n * Ячейка с отступом, линиями и раскрывателем — весь столбец иерархии целиком.\n *\n * Собирает три вещи, которые иначе пришлось бы согласовывать вручную в каждой таблице:\n * `padding-left` по глубине, линии и раскрыватель либо распорку на его месте. Содержимое\n * остаётся за потребителем — внутрь идёт что угодно, от подписи до бейджей.\n *\n * `align-top` не косметика: при переносе текста в соседних колонках содержимое, выровненное\n * по центру, уедет вниз от коннектора, который привязан к первой строке.\n *\n * @example\n * <TableTreeCell row={row} onToggle={() => toggle(row.node.id)}>\n * {row.node.name}\n * </TableTreeCell>\n */\nexport const TableTreeCell = React.forwardRef<HTMLTableCellElement, TableTreeCellProps>(\n\t({ row, onToggle, toggleLabel, className, style, children, ...props }, ref) => (\n\t\t<TableCell\n\t\t\tref={ref}\n\t\t\tdata-tree-level={row.level}\n\t\t\tclassName={cn(\"relative align-top\", className)}\n\t\t\tstyle={{ paddingLeft: treeCellPaddingLeft(row.level), ...style }}\n\t\t\t{...props}\n\t\t>\n\t\t\t<TableTreeLines lines={row.lines} descends={row.descends} />\n\t\t\t<span className=\"flex items-start gap-1.5\">\n\t\t\t\t{row.hasChildren ? (\n\t\t\t\t\t<TableTreeToggle\n\t\t\t\t\t\texpanded={row.isExpanded}\n\t\t\t\t\t\taria-label={toggleLabel ?? (row.isExpanded ? \"Свернуть\" : \"Развернуть\")}\n\t\t\t\t\t\tonClick={onToggle}\n\t\t\t\t\t/>\n\t\t\t\t) : (\n\t\t\t\t\t<TableTreeSpacer />\n\t\t\t\t)}\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t</TableCell>\n\t)\n);\n\nTableTreeCell.displayName = \"TableTreeCell\";\n","/**\n * Модель строки дерева: что рисовать в каждой колонке отступа.\n *\n * Ровно эти четыре состояния использует классический вывод `tree` и почти все табличные\n * гриды (AG Grid, TanStack Table, rc-tree) — набор проверен и закрывает все случаи:\n *\n * - `pass` — сквозная вертикаль `│`: ветка предка продолжается ниже этой строки;\n * - `branch` — `├`: отвод к узлу, и у узла есть следующие соседи;\n * - `end` — `└`: отвод к последнему соседу, вертикаль обрывается на уголке;\n * - `none` — пусто: ветка предка закончилась выше.\n *\n * Ключевой инвариант: **индекс в массиве равен номеру колонки**, а `lines.length` равно\n * глубине узла. `branch`/`end` встречается только в последней колонке, `pass`/`none` — только\n * в предыдущих. Именно этот инвариант убирает класс ошибок «сдвиг на единицу»: раньше\n * массив хранил флаги предков, и колонка `level - 1` управлялась флагом родителя, хотя\n * должна была — признаком `isLast` самого узла. Сравнивать модель с картинкой теперь можно\n * глазами: `[\"pass\", \"none\", \"end\"]` читается как `│ └`.\n */\nexport type TreeLine = \"none\" | \"pass\" | \"branch\" | \"end\";\n\n/** Строка плоского списка со всем, что нужно для отрисовки узла дерева. */\nexport type TreeRow<T> = {\n\tnode: T;\n\t/** Родительский узел, `null` у корней. */\n\tparent: T | null;\n\t/** Глубина, 0 — корень. Равна `lines.length`. */\n\tlevel: number;\n\t/** Позиция среди соседей. */\n\tindex: number;\n\t/** Последний ли среди соседей — от этого зависит `└` вместо `├`. */\n\tisLast: boolean;\n\thasChildren: boolean;\n\t/** Раскрыт ли узел. У листьев всегда `false`. */\n\tisExpanded: boolean;\n\t/**\n\t * Нужен ли спуск от раскрывателя вниз, к первому потомку.\n\t *\n\t * Вертикаль потомка начинается от его собственной строки, поэтому участок между\n\t * раскрывателем и низом строки родителя рисует именно родитель.\n\t */\n\tdescends: boolean;\n\tlines: TreeLine[];\n\t/** Индексы от корня: `[0, 2, 1]`. Годится как стабильный ключ и как «1.3.2» в интерфейсе. */\n\tpath: number[];\n};\n\nexport type FlattenTreeOptions<T> = {\n\t/**\n\t * Потомки узла. Это функция поиска, а не имя поля: плоскому списку с `parentId` хватит\n\t * индекса `Map<parentId, T[]>`, перекладывать данные в узлы с `children` не нужно.\n\t */\n\tgetChildren: (node: T) => T[] | undefined;\n\t/** Раскрыт ли узел. Свёрнутые не отдают потомков. По умолчанию раскрыты все. */\n\tisExpanded?: (node: T) => boolean;\n};\n\n/**\n * Линии потомка, выведенные из линий родителя.\n *\n * Весь алгоритм — в двух строчках: у предков уголок превращается в продолжение (`branch` →\n * `pass`), а обрыв — в пустоту (`end` → `none`); своя колонка получает уголок по `isLast`.\n * Экспортируется отдельно, чтобы линии можно было считать и без обхода дерева — например,\n * для виртуализованного или подгружаемого списка, где полного дерева в памяти нет.\n *\n * Родительские линии в плоском списке удобно держать бегущим массивом `linesByLevel[level]`:\n * в списке, упорядоченном как при выводе, родитель всегда встречается раньше потомка.\n *\n * @example\n * childTreeLines([\"pass\", \"branch\"], false); // [\"pass\", \"pass\", \"branch\"]\n * childTreeLines([\"pass\", \"branch\"], true); // [\"pass\", \"pass\", \"end\"]\n */\nexport const childTreeLines = (parentLines: TreeLine[], isLast: boolean): TreeLine[] => [\n\t...parentLines.map((line): TreeLine => (line === \"pass\" || line === \"branch\" ? \"pass\" : \"none\")),\n\tisLast ? \"end\" : \"branch\"\n];\n\n/**\n * Разворачивает дерево в плоский список строк и попутно считает модель линий.\n *\n * Порядок — как при отображении: узел, затем его раскрытые потомки.\n *\n * @example\n * const rows = flattenTree(nodes, {\n * getChildren: (node) => node.children,\n * isExpanded: (node) => expanded.has(node.id)\n * });\n *\n * rows.map((row) => (\n * <TableRow key={row.path.join(\".\")}>\n * <TableTreeCell row={row} onToggle={() => toggle(row.node.id)}>{row.node.name}</TableTreeCell>\n * </TableRow>\n * ));\n */\nexport function flattenTree<T>(roots: T[], options: FlattenTreeOptions<T>): TreeRow<T>[] {\n\tconst { getChildren, isExpanded = () => true } = options;\n\tconst rows: TreeRow<T>[] = [];\n\n\tconst walk = (nodes: T[], parent: T | null, level: number, parentLines: TreeLine[], parentPath: number[]) => {\n\t\tnodes.forEach((node, index) => {\n\t\t\tconst isLast = index === nodes.length - 1;\n\t\t\tconst children = getChildren(node);\n\t\t\tconst hasChildren = Boolean(children?.length);\n\t\t\tconst expanded = hasChildren && isExpanded(node);\n\t\t\t// У корней нет предка — значит, нет и колонок отступа.\n\t\t\tconst lines = level === 0 ? [] : childTreeLines(parentLines, isLast);\n\t\t\tconst path = [...parentPath, index];\n\n\t\t\trows.push({\n\t\t\t\tnode,\n\t\t\t\tparent,\n\t\t\t\tlevel,\n\t\t\t\tindex,\n\t\t\t\tisLast,\n\t\t\t\thasChildren,\n\t\t\t\tisExpanded: expanded,\n\t\t\t\tdescends: expanded,\n\t\t\t\tlines,\n\t\t\t\tpath\n\t\t\t});\n\n\t\t\tif (expanded) walk(children!, node, level + 1, lines, path);\n\t\t});\n\t};\n\n\twalk(roots, null, 0, [], []);\n\treturn rows;\n}\n"],"names":["tableStyles","tv","Table","React","className","containerClassName","containerRef","props","ref","styles","jsx","tableHeaderStyles","STICKY_HEADER","TableHeader","sticky","tableBodyStyles","TableBody","tableBodyContainerStyles","TableBodyContainer","shadowSize","ScrollShadowContainer","tableFooterStyles","STICKY_FOOTER","TableFooter","TABLE_ROW_ANATOMY","tableRowStyles","TABLE_ROW_TINT_LAYERS","TableRow","tableHeadStyles","TableHead","interactive","tableCellStyles","TableCell","tableResizeHandleStyles","TableResizeHandle","active","tableCaptionStyles","TableCaption","TREE_INDENT","TREE_LINE_OFFSET","TREE_TOGGLE","TREE_STUB","TREE_CELL_PADDING_TOP","TREE_TEXT_LINE_HEIGHT","TREE_CONNECTOR_Y","TREE_OVERHANG","TREE_TOGGLE_MARGIN_TOP","treeLineX","column","treeCellPaddingLeft","level","treeLineStyles","TableTreeLines","lines","descends","jsxs","cn","kind","tableTreeToggleStyles","TableTreeToggle","expanded","style","Icon","Minus","Plus","TableTreeSpacer","TableTreeCell","row","onToggle","toggleLabel","children","childTreeLines","parentLines","isLast","line","flattenTree","roots","options","getChildren","isExpanded","rows","walk","nodes","parent","parentPath","node","index","hasChildren","path"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { useState as Y, useRef as p, useMemo as J, useEffect as Q } from "react";
2
- import { o as V } from "./opaqueCell-SGaiyL54.js";
2
+ import { o as V } from "./opaqueCell-D95h1mFM.js";
3
3
  const O = "data-column-key", X = 200, Z = 3;
4
4
  function rt({
5
5
  columns: T,
@@ -116,4 +116,4 @@ export {
116
116
  O as C,
117
117
  rt as u
118
118
  };
119
- //# sourceMappingURL=useColumnReorder-BxVZQ_Y5.js.map
119
+ //# sourceMappingURL=useColumnReorder-tE5pMONm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useColumnReorder-BxVZQ_Y5.js","sources":["../src/components/table/column-reorder/useColumnReorder.ts"],"sourcesContent":["import { type PointerEvent as ReactPointerEvent, useEffect, useMemo, useRef, useState } from \"react\";\nimport { opaqueCellStyles } from \"../opaqueCell\";\n\n/** Атрибут, по которому хук находит в DOM все ячейки одной колонки. */\nexport const COLUMN_KEY_ATTRIBUTE = \"data-column-key\";\n\n/** Сколько миллисекунд колонки разъезжаются и укладываются на место. */\nconst TRANSITION_MS = 200;\n\n/** Порог в пикселях, до которого нажатие считается кликом, а не началом перетаскивания. */\nconst DRAG_THRESHOLD = 3;\n\n/** Инлайновые свойства, которые хук пишет ячейкам на время перетаскивания. */\ntype TouchedStyles = Pick<CSSStyleDeclaration, \"transform\" | \"transition\" | \"position\" | \"zIndex\" | \"boxShadow\">;\n\nexport interface UseColumnReorderOptions<K extends string> {\n\t/** Полный видимый порядок колонок — включая те, что двигать нельзя. */\n\tcolumns: K[];\n\t/** Ширины колонок: из них считаются границы слотов. Обычно это `widths` из `useColumnResize`. */\n\twidths: Record<K, number>;\n\t/** Новый порядок. Хук ничего не хранит — состояние остаётся у вызывающей стороны. */\n\tonReorder: (next: K[]) => void;\n\t/**\n\t * Колонки, которые нельзя ни таскать, ни занимать: например колонка иерархии,\n\t * которая обязана оставаться первой. Свой индекс они сохраняют при любой перестановке.\n\t */\n\tlocked?: K[];\n}\n\nexport interface UseColumnReorderResult<K extends string> {\n\t/** Колонка, которую тащат прямо сейчас. Годится для подсветки грипа. */\n\tdragKey: K | null;\n\t/** Пропы для ручки-грипа. Драг начинается только с неё. */\n\tgetGripProps: (key: K) => {\n\t\tonPointerDown: (event: ReactPointerEvent) => void;\n\t\tstyle: { touchAction: \"none\" };\n\t};\n\t/** Пропы для каждой ячейки колонки — и в шапке, и в теле. Без них колонка не поедет. */\n\tgetColumnProps: (key: K) => Record<string, string>;\n}\n\n/**\n * Перетаскивание колонок таблицы: колонка едет за курсором, соседи разъезжаются, отпускание\n * укладывает её в новый слот.\n *\n * **Почему не библиотека.** Универсальные DnD-библиотеки (dnd-kit и подобные) существуют ради\n * произвольной геометрии: они измеряют узлы, ищут коллизии, держат подписку на каждый\n * перетаскиваемый элемент. Здесь ничего этого не нужно — колонки лежат в один ряд, а их ширины\n * уже известны из `useColumnResize`, так что смещение слота это префиксная сумма, а выбор цели —\n * ближайший центр. Ровно то же самое делает `closestCenter`, только без обхода DOM.\n *\n * Вторая причина — цена на большой таблице. Библиотечный подход требует хука на **каждую**\n * ячейку, включая ячейки тела, иначе колонка не поедет целиком: на таблице 7×34 это больше\n * двухсот подписок и столько же ререндеров на каждое движение мыши. Здесь во время драга\n * React не участвует вовсе: трансформации пишутся прямо в DOM, а состояние меняется один раз,\n * когда кнопку отпустили. Тот же приём и по той же причине используется в `useColumnResize`.\n *\n * **Оговорка про инлайновые стили.** На время драга хук пишет ячейкам `transform`,\n * `transition`, `position`, `z-index` и `box-shadow` — последний рисует левый край, которого\n * у плывущей колонки нет (см. `setColumnSeparator`). Свои значения этих свойств ячейка\n * получает обратно после отпускания: хук снимает их при первом касании и возвращает\n * в конце. Классы при этом не трогаются вовсе, поэтому оформление классами живёт своей\n * жизнью, а тень от хука просто лежит поверх на время перетаскивания.\n *\n * **Оговорка про фон.** Плывущая колонка на время перетаскивания получает классы\n * `opaqueCellStyles`: строка прозрачна, и без непрозрачного фона колонка едет поверх соседей\n * вместе с их текстом, наложенным на свой. Тот же рецепт, что у закреплённой колонки, — и по\n * той же причине. Подсветку строки он сохраняет, поэтому наведение и `selected` под колонкой\n * не пропадают.\n *\n * **Чего нет.** Перетаскивания с клавиатуры: правильный клавиатурный аналог — пункты меню\n * «сдвинуть влево / вправо», а не имитация драга. Автопрокрутки контейнера у края тоже нет —\n * при перетаскивании за пределы видимой области колонка просто упрётся в край.\n *\n * **Как подключается.** `getGripProps` — на ручку, `getColumnProps` — на `TableHead`\n * и на каждую `TableCell` этой колонки. Драг начинается только с ручки: `pointerdown`\n * по всей ячейке конфликтовал бы с ресайзером, который начинается так же.\n *\n * @example\n * const [order, setOrder] = useState([\"tree\", \"client\", \"sum\"]);\n *\n * const { getGripProps, getColumnProps } = useColumnReorder({\n * columns: order,\n * widths, // из useColumnResize\n * onReorder: setOrder,\n * locked: [\"tree\"]\n * });\n *\n * <TableHead {...getColumnProps(key)}>\n * <span {...getGripProps(key)}>⠿</span>\n * </TableHead>\n * <TableCell {...getColumnProps(key)}>…</TableCell>\n */\nexport function useColumnReorder<K extends string>({\n\tcolumns,\n\twidths,\n\tonReorder,\n\tlocked\n}: UseColumnReorderOptions<K>): UseColumnReorderResult<K> {\n\tconst [dragKey, setDragKey] = useState<K | null>(null);\n\n\t/** Всё, что живёт только на время одного перетаскивания. */\n\tconst sessionRef = useRef<{\n\t\tkey: K;\n\t\ttable: HTMLElement;\n\t\tstartX: number;\n\t\t/** Индексы в `columns`, доступные для перестановки. */\n\t\tmovable: number[];\n\t\t/** Левая граница каждой колонки внутри таблицы. */\n\t\toffsets: number[];\n\t\t/**\n\t\t * Цвет разделителя колонок, снятый с живой ячейки, — им рисуется левый край плывущей\n\t\t * колонки. Читается один раз на старте: во время драга `getComputedStyle` на каждую\n\t\t * ячейку — это принудительный пересчёт раскладки в каждом кадре.\n\t\t */\n\t\tborderColor?: string;\n\t\tfrom: number;\n\t\tto: number;\n\t\tstarted: boolean;\n\t} | null>(null);\n\n\tconst settleTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n\t/** Ячейки, которым драг выдал непрозрачный фон, и ровно те классы, которые были выданы. */\n\tconst opaqueCells = useRef(new Map<HTMLElement, string[]>());\n\n\t/**\n\t * Инлайновые стили ячеек в том виде, в каком хук их застал.\n\t *\n\t * Снимаются один раз, при первом касании ячейки, и возвращаются на место после\n\t * перетаскивания. Инлайновый `box-shadow` или `transform` — законный инструмент\n\t * потребителя (рамка выделенного диапазона, своя анимация), и колонка, проехавшая\n\t * поверх такой ячейки, оставляет её ровно такой же, какой взяла.\n\t */\n\tconst touchedCells = useRef(new Map<HTMLElement, TouchedStyles>());\n\n\tconst lockedSet = useMemo(() => new Set(locked ?? []), [locked]);\n\n\t// Актуальные значения нужны обработчикам на `window`, которые подписываются один раз\n\t// за перетаскивание и иначе замкнулись бы на устаревшие пропы.\n\tconst latest = useRef({ columns, widths, onReorder, lockedSet });\n\tlatest.current = { columns, widths, onReorder, lockedSet };\n\n\tuseEffect(() => () => clearTimeout(settleTimer.current), []);\n\n\t/** Все ячейки колонки — заголовок и тело разом. */\n\tconst cellsOf = (table: HTMLElement, key: K) =>\n\t\tArray.from(table.querySelectorAll<HTMLElement>(`[${COLUMN_KEY_ATTRIBUTE}=\"${key}\"]`));\n\n\t/**\n\t * Непрозрачный фон плывущей колонке.\n\t *\n\t * Выданные классы запоминаются поштучно: те, что у ячейки уже были (закреплённая колонка\n\t * несёт тот же набор), не выдаются и не снимаются — иначе после перетаскивания она\n\t * осталась бы без фона.\n\t */\n\tconst markOpaque = (cell: HTMLElement) => {\n\t\tconst classes = opaqueCellStyles({ part: cell.closest(\"thead\") ? \"head\" : \"cell\" })\n\t\t\t.split(\" \")\n\t\t\t.filter((className) => className && !cell.classList.contains(className));\n\t\tcell.classList.add(...classes);\n\t\topaqueCells.current.set(cell, classes);\n\t};\n\n\tconst clearOpaque = () => {\n\t\topaqueCells.current.forEach((classes, cell) => cell.classList.remove(...classes));\n\t\topaqueCells.current.clear();\n\t};\n\n\t/** Снимок инлайновых стилей ячейки до того, как хук в них написал. */\n\tconst rememberCell = (cell: HTMLElement) => {\n\t\tif (touchedCells.current.has(cell)) return;\n\t\tconst { transform, transition, position, zIndex, boxShadow } = cell.style;\n\t\ttouchedCells.current.set(cell, { transform, transition, position, zIndex, boxShadow });\n\t};\n\n\t/**\n\t * Левый край перетаскиваемой колонки.\n\t *\n\t * Правый край едет с колонкой сам: разделители у кита лежат на ячейках (`border-r`),\n\t * а раздельная модель границ (`border-separate` у `Table`) включает границу в бокс ячейки.\n\t * Левый край принадлежит соседу слева и уезжает вместе с ним, поэтому его рисует тень —\n\t * и рисует всегда: у последней колонки своей правой границы нет (`last:border-r-0`),\n\t * и без тени она уплывала бы вовсе без краёв.\n\t *\n\t * По той же причине левый край нужен колонке справа от пустого слота: слева от неё стоит\n\t * не сосед, а дырка, в которую сядет плывущая колонка, и её правый борт рисовать некому.\n\t *\n\t * Тот же приём, что и в референсе на dnd-kit, где разделитель нарисован псевдоэлементом\n\t * `::before` — с той разницей, что здесь ничего не требуется от разметки потребителя.\n\t */\n\tconst setColumnSeparator = (cell: HTMLElement, leftEdge: string | undefined) => {\n\t\tcell.style.boxShadow = leftEdge ? `inset 1px 0 0 0 ${leftEdge}` : \"\";\n\t};\n\n\tconst setColumnTransform = (table: HTMLElement, key: K, shift: number, dragged: boolean, leftEdge?: string) => {\n\t\tconst moving = shift !== 0 || dragged;\n\t\tcellsOf(table, key).forEach((cell) => {\n\t\t\trememberCell(cell);\n\t\t\tcell.style.transform = shift ? `translateX(${shift}px)` : \"\";\n\t\t\t// Перетаскиваемая колонка идёт поверх соседей и следует за курсором без задержки;\n\t\t\t// разъезжающиеся соседи, наоборот, должны двигаться плавно.\n\t\t\tcell.style.transition = dragged ? \"none\" : `transform ${TRANSITION_MS}ms ease`;\n\t\t\tcell.style.position = moving ? \"relative\" : \"\";\n\t\t\tcell.style.zIndex = dragged ? \"20\" : \"\";\n\t\t\t// Край рисуется независимо от того, едет ли колонка: у соседа справа от пустого\n\t\t\t// слота сдвиг нулевой, а борт ему всё равно нужен.\n\t\t\tsetColumnSeparator(cell, leftEdge);\n\t\t});\n\t};\n\n\t/** Возврат ячеек в исходное состояние: ровно те стили и классы, что были до драга. */\n\tconst clearTransforms = () => {\n\t\ttouchedCells.current.forEach((styles, cell) => Object.assign(cell.style, styles));\n\t\ttouchedCells.current.clear();\n\t\tclearOpaque();\n\t};\n\n\t/**\n\t * Куда встанет колонка при текущем сдвиге: ближайший по центру доступный слот.\n\t *\n\t * Именно так выбирает цель и `closestCenter` в dnd-kit — с той разницей, что центры\n\t * слотов здесь известны заранее и обходить DOM не требуется.\n\t */\n\tconst targetIndex = (session: NonNullable<typeof sessionRef.current>, dx: number) => {\n\t\tconst { widths: currentWidths } = latest.current;\n\t\tconst draggedCenter = session.offsets[session.from] + currentWidths[session.key] / 2 + dx;\n\n\t\tlet best = session.from;\n\t\tlet bestDistance = Infinity;\n\t\tsession.movable.forEach((index) => {\n\t\t\tconst center = session.offsets[index] + currentWidths[latest.current.columns[index]] / 2;\n\t\t\tconst distance = Math.abs(center - draggedCenter);\n\t\t\tif (distance < bestDistance) {\n\t\t\t\tbestDistance = distance;\n\t\t\t\tbest = index;\n\t\t\t}\n\t\t});\n\t\treturn best;\n\t};\n\n\t/**\n\t * Сдвиг колонки при перестановке `from → to`.\n\t *\n\t * Двигаются только те, кто оказался между исходным и целевым слотом; закреплённые\n\t * не двигаются никогда, потому что в перестановке не участвуют.\n\t */\n\tconst shiftOf = (session: NonNullable<typeof sessionRef.current>, index: number, to: number) => {\n\t\tconst width = latest.current.widths[session.key];\n\t\tconst { from } = session;\n\t\tif (index === from || !session.movable.includes(index)) return 0;\n\t\tif (from < to && index > from && index <= to) return -width;\n\t\tif (from > to && index >= to && index < from) return width;\n\t\treturn 0;\n\t};\n\n\t/** Порядок колонок после перестановки `from → to`. Закреплённые сохраняют свои индексы. */\n\tconst orderAfter = (session: NonNullable<typeof sessionRef.current>, to: number) => {\n\t\tconst { columns: currentColumns } = latest.current;\n\t\tconst next = [...currentColumns];\n\t\tconst movableKeys = session.movable.map((index) => currentColumns[index]);\n\t\tconst [moved] = movableKeys.splice(session.movable.indexOf(session.from), 1);\n\t\tmovableKeys.splice(session.movable.indexOf(to), 0, moved);\n\t\tsession.movable.forEach((index, slot) => (next[index] = movableKeys[slot]));\n\t\treturn next;\n\t};\n\n\t/**\n\t * Левый край плывущей колонки в раскладке, которая получится после перестановки.\n\t *\n\t * Считается по будущему порядку, а не как `offsets[to]`. При движении вправо соседи между\n\t * слотами уезжают влево, и колонка встаёт не на левый край целевого слота, а на его правый\n\t * край минус собственная ширина; `offsets[to]` промахивается ровно на разницу ширин целевой\n\t * и перетаскиваемой колонок. На колонках равной ширины это ноль, на разных — заметный\n\t * скачок в момент, когда анимация закончилась и трансформации сняты.\n\t */\n\tconst offsetAfter = (session: NonNullable<typeof sessionRef.current>, to: number) => {\n\t\tconst { widths: currentWidths } = latest.current;\n\t\tconst next = orderAfter(session, to);\n\t\treturn next.slice(0, next.indexOf(session.key)).reduce((sum, columnKey) => sum + currentWidths[columnKey], 0);\n\t};\n\n\tconst finish = (commit: boolean) => {\n\t\tconst session = sessionRef.current;\n\t\tsessionRef.current = null;\n\t\tsetDragKey(null);\n\t\tif (!session) return;\n\n\t\tconst { table, from, to } = session;\n\n\t\tif (!commit || from === to) {\n\t\t\tclearTransforms();\n\t\t\treturn;\n\t\t}\n\n\t\t// Колонка доезжает до своего слота, и только потом порядок меняется в state:\n\t\t// иначе она прыгнула бы из-под курсора на новое место рывком.\n\t\tconst settleShift = offsetAfter(session, to) - session.offsets[from];\n\t\tsetColumnTransform(table, session.key, settleShift, false, session.borderColor);\n\n\t\tclearTimeout(settleTimer.current);\n\t\tsettleTimer.current = setTimeout(() => {\n\t\t\tclearTransforms();\n\t\t\tlatest.current.onReorder(orderAfter(session, to));\n\t\t}, TRANSITION_MS);\n\t};\n\n\tconst onPointerDown = (key: K) => (event: ReactPointerEvent) => {\n\t\tif (event.button !== 0 || lockedSet.has(key)) return;\n\t\tconst table = (event.currentTarget as HTMLElement).closest(\"table\");\n\t\tif (!table) return;\n\n\t\tevent.preventDefault();\n\n\t\tconst { columns: currentColumns, widths: currentWidths } = latest.current;\n\t\tconst offsets: number[] = [];\n\t\tcurrentColumns.reduce((sum, columnKey) => {\n\t\t\toffsets.push(sum);\n\t\t\treturn sum + currentWidths[columnKey];\n\t\t}, 0);\n\n\t\t// Цвет разделителя снимается с первой колонки, у которой правая граница есть:\n\t\t// у последней её нет (`last:border-r-0`), а цвет у всех один.\n\t\tconst borderColor = currentColumns\n\t\t\t.map((columnKey) => {\n\t\t\t\tconst head = table.querySelector<HTMLElement>(`thead [${COLUMN_KEY_ATTRIBUTE}=\"${columnKey}\"]`);\n\t\t\t\tif (!head) return undefined;\n\t\t\t\tconst style = window.getComputedStyle(head);\n\t\t\t\treturn parseFloat(style.borderRightWidth) > 0 ? style.borderRightColor : undefined;\n\t\t\t})\n\t\t\t.find(Boolean);\n\n\t\tconst from = currentColumns.indexOf(key);\n\t\tsessionRef.current = {\n\t\t\tborderColor,\n\t\t\tkey,\n\t\t\ttable,\n\t\t\tstartX: event.clientX,\n\t\t\tmovable: currentColumns.map((_, index) => index).filter((index) => !lockedSet.has(currentColumns[index])),\n\t\t\toffsets,\n\t\t\tfrom,\n\t\t\tto: from,\n\t\t\tstarted: false\n\t\t};\n\n\t\tconst onMove = (moveEvent: PointerEvent) => {\n\t\t\tconst session = sessionRef.current;\n\t\t\tif (!session) return;\n\n\t\t\tconst dx = moveEvent.clientX - session.startX;\n\t\t\t// Пока курсор не ушёл дальше порога, это ещё клик: нажатие на ручку не должно\n\t\t\t// дёргать колонку от дрожания руки.\n\t\t\tif (!session.started) {\n\t\t\t\tif (Math.abs(dx) < DRAG_THRESHOLD) return;\n\t\t\t\tsession.started = true;\n\t\t\t\tsetDragKey(session.key);\n\t\t\t\tcellsOf(session.table, session.key).forEach(markOpaque);\n\t\t\t}\n\n\t\t\tconst to = targetIndex(session, dx);\n\t\t\tsession.to = to;\n\n\t\t\t// Колонка, которая окажется справа от пустого слота: ей нужен левый край.\n\t\t\tconst order = orderAfter(session, to);\n\t\t\tconst afterSlot = order[order.indexOf(session.key) + 1];\n\n\t\t\tsetColumnTransform(session.table, session.key, dx, true, session.borderColor);\n\t\t\tlatest.current.columns.forEach((columnKey, index) => {\n\t\t\t\tif (index === session.from) return;\n\t\t\t\tconst shift = shiftOf(session, index, to);\n\t\t\t\tconst leftEdge = columnKey === afterSlot ? session.borderColor : undefined;\n\t\t\t\tsetColumnTransform(session.table, columnKey, shift, false, leftEdge);\n\t\t\t});\n\t\t};\n\n\t\tconst onUp = () => {\n\t\t\twindow.removeEventListener(\"pointermove\", onMove);\n\t\t\twindow.removeEventListener(\"pointerup\", onUp);\n\t\t\twindow.removeEventListener(\"pointercancel\", onCancel);\n\t\t\tfinish(sessionRef.current?.started ?? false);\n\t\t};\n\n\t\tconst onCancel = () => {\n\t\t\twindow.removeEventListener(\"pointermove\", onMove);\n\t\t\twindow.removeEventListener(\"pointerup\", onUp);\n\t\t\twindow.removeEventListener(\"pointercancel\", onCancel);\n\t\t\tfinish(false);\n\t\t};\n\n\t\twindow.addEventListener(\"pointermove\", onMove);\n\t\twindow.addEventListener(\"pointerup\", onUp);\n\t\twindow.addEventListener(\"pointercancel\", onCancel);\n\t};\n\n\treturn {\n\t\tdragKey,\n\t\tgetGripProps: (key: K) => ({\n\t\t\tonPointerDown: onPointerDown(key),\n\t\t\t// Без этого браузер на тач-устройстве начнёт прокрутку вместо перетаскивания.\n\t\t\tstyle: { touchAction: \"none\" as const }\n\t\t}),\n\t\tgetColumnProps: (key: K) => ({ [COLUMN_KEY_ATTRIBUTE]: key })\n\t};\n}\n"],"names":["COLUMN_KEY_ATTRIBUTE","TRANSITION_MS","DRAG_THRESHOLD","useColumnReorder","columns","widths","onReorder","locked","dragKey","setDragKey","useState","sessionRef","useRef","settleTimer","opaqueCells","touchedCells","lockedSet","useMemo","latest","useEffect","cellsOf","table","key","markOpaque","cell","classes","opaqueCellStyles","className","clearOpaque","rememberCell","transform","transition","position","zIndex","boxShadow","setColumnSeparator","leftEdge","setColumnTransform","shift","dragged","moving","clearTransforms","styles","targetIndex","session","dx","currentWidths","draggedCenter","best","bestDistance","index","center","distance","shiftOf","to","width","from","orderAfter","currentColumns","next","movableKeys","moved","slot","offsetAfter","sum","columnKey","finish","commit","settleShift","onPointerDown","event","offsets","borderColor","head","style","_","onMove","moveEvent","order","afterSlot","onUp","onCancel"],"mappings":"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"}
1
+ {"version":3,"file":"useColumnReorder-tE5pMONm.js","sources":["../src/components/table/column-reorder/useColumnReorder.ts"],"sourcesContent":["import { type PointerEvent as ReactPointerEvent, useEffect, useMemo, useRef, useState } from \"react\";\nimport { opaqueCellStyles } from \"../opaqueCell\";\n\n/** Атрибут, по которому хук находит в DOM все ячейки одной колонки. */\nexport const COLUMN_KEY_ATTRIBUTE = \"data-column-key\";\n\n/** Сколько миллисекунд колонки разъезжаются и укладываются на место. */\nconst TRANSITION_MS = 200;\n\n/** Порог в пикселях, до которого нажатие считается кликом, а не началом перетаскивания. */\nconst DRAG_THRESHOLD = 3;\n\n/** Инлайновые свойства, которые хук пишет ячейкам на время перетаскивания. */\ntype TouchedStyles = Pick<CSSStyleDeclaration, \"transform\" | \"transition\" | \"position\" | \"zIndex\" | \"boxShadow\">;\n\nexport interface UseColumnReorderOptions<K extends string> {\n\t/** Полный видимый порядок колонок — включая те, что двигать нельзя. */\n\tcolumns: K[];\n\t/** Ширины колонок: из них считаются границы слотов. Обычно это `widths` из `useColumnResize`. */\n\twidths: Record<K, number>;\n\t/** Новый порядок. Хук ничего не хранит — состояние остаётся у вызывающей стороны. */\n\tonReorder: (next: K[]) => void;\n\t/**\n\t * Колонки, которые нельзя ни таскать, ни занимать: например колонка иерархии,\n\t * которая обязана оставаться первой. Свой индекс они сохраняют при любой перестановке.\n\t */\n\tlocked?: K[];\n}\n\nexport interface UseColumnReorderResult<K extends string> {\n\t/** Колонка, которую тащат прямо сейчас. Годится для подсветки грипа. */\n\tdragKey: K | null;\n\t/** Пропы для ручки-грипа. Драг начинается только с неё. */\n\tgetGripProps: (key: K) => {\n\t\tonPointerDown: (event: ReactPointerEvent) => void;\n\t\tstyle: { touchAction: \"none\" };\n\t};\n\t/** Пропы для каждой ячейки колонки — и в шапке, и в теле. Без них колонка не поедет. */\n\tgetColumnProps: (key: K) => Record<string, string>;\n}\n\n/**\n * Перетаскивание колонок таблицы: колонка едет за курсором, соседи разъезжаются, отпускание\n * укладывает её в новый слот.\n *\n * **Почему не библиотека.** Универсальные DnD-библиотеки (dnd-kit и подобные) существуют ради\n * произвольной геометрии: они измеряют узлы, ищут коллизии, держат подписку на каждый\n * перетаскиваемый элемент. Здесь ничего этого не нужно — колонки лежат в один ряд, а их ширины\n * уже известны из `useColumnResize`, так что смещение слота это префиксная сумма, а выбор цели —\n * ближайший центр. Ровно то же самое делает `closestCenter`, только без обхода DOM.\n *\n * Вторая причина — цена на большой таблице. Библиотечный подход требует хука на **каждую**\n * ячейку, включая ячейки тела, иначе колонка не поедет целиком: на таблице 7×34 это больше\n * двухсот подписок и столько же ререндеров на каждое движение мыши. Здесь во время драга\n * React не участвует вовсе: трансформации пишутся прямо в DOM, а состояние меняется один раз,\n * когда кнопку отпустили. Тот же приём и по той же причине используется в `useColumnResize`.\n *\n * **Оговорка про инлайновые стили.** На время драга хук пишет ячейкам `transform`,\n * `transition`, `position`, `z-index` и `box-shadow` — последний рисует левый край, которого\n * у плывущей колонки нет (см. `setColumnSeparator`). Свои значения этих свойств ячейка\n * получает обратно после отпускания: хук снимает их при первом касании и возвращает\n * в конце. Классы при этом не трогаются вовсе, поэтому оформление классами живёт своей\n * жизнью, а тень от хука просто лежит поверх на время перетаскивания.\n *\n * **Оговорка про фон.** Плывущая колонка на время перетаскивания получает классы\n * `opaqueCellStyles`: строка прозрачна, и без непрозрачного фона колонка едет поверх соседей\n * вместе с их текстом, наложенным на свой. Тот же рецепт, что у закреплённой колонки, — и по\n * той же причине. Подсветку строки он сохраняет, поэтому наведение и `selected` под колонкой\n * не пропадают.\n *\n * **Чего нет.** Перетаскивания с клавиатуры: правильный клавиатурный аналог — пункты меню\n * «сдвинуть влево / вправо», а не имитация драга. Автопрокрутки контейнера у края тоже нет —\n * при перетаскивании за пределы видимой области колонка просто упрётся в край.\n *\n * **Как подключается.** `getGripProps` — на ручку, `getColumnProps` — на `TableHead`\n * и на каждую `TableCell` этой колонки. Драг начинается только с ручки: `pointerdown`\n * по всей ячейке конфликтовал бы с ресайзером, который начинается так же.\n *\n * @example\n * const [order, setOrder] = useState([\"tree\", \"client\", \"sum\"]);\n *\n * const { getGripProps, getColumnProps } = useColumnReorder({\n * columns: order,\n * widths, // из useColumnResize\n * onReorder: setOrder,\n * locked: [\"tree\"]\n * });\n *\n * <TableHead {...getColumnProps(key)}>\n * <span {...getGripProps(key)}>⠿</span>\n * </TableHead>\n * <TableCell {...getColumnProps(key)}>…</TableCell>\n */\nexport function useColumnReorder<K extends string>({\n\tcolumns,\n\twidths,\n\tonReorder,\n\tlocked\n}: UseColumnReorderOptions<K>): UseColumnReorderResult<K> {\n\tconst [dragKey, setDragKey] = useState<K | null>(null);\n\n\t/** Всё, что живёт только на время одного перетаскивания. */\n\tconst sessionRef = useRef<{\n\t\tkey: K;\n\t\ttable: HTMLElement;\n\t\tstartX: number;\n\t\t/** Индексы в `columns`, доступные для перестановки. */\n\t\tmovable: number[];\n\t\t/** Левая граница каждой колонки внутри таблицы. */\n\t\toffsets: number[];\n\t\t/**\n\t\t * Цвет разделителя колонок, снятый с живой ячейки, — им рисуется левый край плывущей\n\t\t * колонки. Читается один раз на старте: во время драга `getComputedStyle` на каждую\n\t\t * ячейку — это принудительный пересчёт раскладки в каждом кадре.\n\t\t */\n\t\tborderColor?: string;\n\t\tfrom: number;\n\t\tto: number;\n\t\tstarted: boolean;\n\t} | null>(null);\n\n\tconst settleTimer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n\t/** Ячейки, которым драг выдал непрозрачный фон, и ровно те классы, которые были выданы. */\n\tconst opaqueCells = useRef(new Map<HTMLElement, string[]>());\n\n\t/**\n\t * Инлайновые стили ячеек в том виде, в каком хук их застал.\n\t *\n\t * Снимаются один раз, при первом касании ячейки, и возвращаются на место после\n\t * перетаскивания. Инлайновый `box-shadow` или `transform` — законный инструмент\n\t * потребителя (рамка выделенного диапазона, своя анимация), и колонка, проехавшая\n\t * поверх такой ячейки, оставляет её ровно такой же, какой взяла.\n\t */\n\tconst touchedCells = useRef(new Map<HTMLElement, TouchedStyles>());\n\n\tconst lockedSet = useMemo(() => new Set(locked ?? []), [locked]);\n\n\t// Актуальные значения нужны обработчикам на `window`, которые подписываются один раз\n\t// за перетаскивание и иначе замкнулись бы на устаревшие пропы.\n\tconst latest = useRef({ columns, widths, onReorder, lockedSet });\n\tlatest.current = { columns, widths, onReorder, lockedSet };\n\n\tuseEffect(() => () => clearTimeout(settleTimer.current), []);\n\n\t/** Все ячейки колонки — заголовок и тело разом. */\n\tconst cellsOf = (table: HTMLElement, key: K) =>\n\t\tArray.from(table.querySelectorAll<HTMLElement>(`[${COLUMN_KEY_ATTRIBUTE}=\"${key}\"]`));\n\n\t/**\n\t * Непрозрачный фон плывущей колонке.\n\t *\n\t * Выданные классы запоминаются поштучно: те, что у ячейки уже были (закреплённая колонка\n\t * несёт тот же набор), не выдаются и не снимаются — иначе после перетаскивания она\n\t * осталась бы без фона.\n\t */\n\tconst markOpaque = (cell: HTMLElement) => {\n\t\tconst classes = opaqueCellStyles({ part: cell.closest(\"thead\") ? \"head\" : \"cell\" })\n\t\t\t.split(\" \")\n\t\t\t.filter((className) => className && !cell.classList.contains(className));\n\t\tcell.classList.add(...classes);\n\t\topaqueCells.current.set(cell, classes);\n\t};\n\n\tconst clearOpaque = () => {\n\t\topaqueCells.current.forEach((classes, cell) => cell.classList.remove(...classes));\n\t\topaqueCells.current.clear();\n\t};\n\n\t/** Снимок инлайновых стилей ячейки до того, как хук в них написал. */\n\tconst rememberCell = (cell: HTMLElement) => {\n\t\tif (touchedCells.current.has(cell)) return;\n\t\tconst { transform, transition, position, zIndex, boxShadow } = cell.style;\n\t\ttouchedCells.current.set(cell, { transform, transition, position, zIndex, boxShadow });\n\t};\n\n\t/**\n\t * Левый край перетаскиваемой колонки.\n\t *\n\t * Правый край едет с колонкой сам: разделители у кита лежат на ячейках (`border-r`),\n\t * а раздельная модель границ (`border-separate` у `Table`) включает границу в бокс ячейки.\n\t * Левый край принадлежит соседу слева и уезжает вместе с ним, поэтому его рисует тень —\n\t * и рисует всегда: у последней колонки своей правой границы нет (`last:border-r-0`),\n\t * и без тени она уплывала бы вовсе без краёв.\n\t *\n\t * По той же причине левый край нужен колонке справа от пустого слота: слева от неё стоит\n\t * не сосед, а дырка, в которую сядет плывущая колонка, и её правый борт рисовать некому.\n\t *\n\t * Тот же приём, что и в референсе на dnd-kit, где разделитель нарисован псевдоэлементом\n\t * `::before` — с той разницей, что здесь ничего не требуется от разметки потребителя.\n\t */\n\tconst setColumnSeparator = (cell: HTMLElement, leftEdge: string | undefined) => {\n\t\tcell.style.boxShadow = leftEdge ? `inset 1px 0 0 0 ${leftEdge}` : \"\";\n\t};\n\n\tconst setColumnTransform = (table: HTMLElement, key: K, shift: number, dragged: boolean, leftEdge?: string) => {\n\t\tconst moving = shift !== 0 || dragged;\n\t\tcellsOf(table, key).forEach((cell) => {\n\t\t\trememberCell(cell);\n\t\t\tcell.style.transform = shift ? `translateX(${shift}px)` : \"\";\n\t\t\t// Перетаскиваемая колонка идёт поверх соседей и следует за курсором без задержки;\n\t\t\t// разъезжающиеся соседи, наоборот, должны двигаться плавно.\n\t\t\tcell.style.transition = dragged ? \"none\" : `transform ${TRANSITION_MS}ms ease`;\n\t\t\tcell.style.position = moving ? \"relative\" : \"\";\n\t\t\tcell.style.zIndex = dragged ? \"20\" : \"\";\n\t\t\t// Край рисуется независимо от того, едет ли колонка: у соседа справа от пустого\n\t\t\t// слота сдвиг нулевой, а борт ему всё равно нужен.\n\t\t\tsetColumnSeparator(cell, leftEdge);\n\t\t});\n\t};\n\n\t/** Возврат ячеек в исходное состояние: ровно те стили и классы, что были до драга. */\n\tconst clearTransforms = () => {\n\t\ttouchedCells.current.forEach((styles, cell) => Object.assign(cell.style, styles));\n\t\ttouchedCells.current.clear();\n\t\tclearOpaque();\n\t};\n\n\t/**\n\t * Куда встанет колонка при текущем сдвиге: ближайший по центру доступный слот.\n\t *\n\t * Именно так выбирает цель и `closestCenter` в dnd-kit — с той разницей, что центры\n\t * слотов здесь известны заранее и обходить DOM не требуется.\n\t */\n\tconst targetIndex = (session: NonNullable<typeof sessionRef.current>, dx: number) => {\n\t\tconst { widths: currentWidths } = latest.current;\n\t\tconst draggedCenter = session.offsets[session.from] + currentWidths[session.key] / 2 + dx;\n\n\t\tlet best = session.from;\n\t\tlet bestDistance = Infinity;\n\t\tsession.movable.forEach((index) => {\n\t\t\tconst center = session.offsets[index] + currentWidths[latest.current.columns[index]] / 2;\n\t\t\tconst distance = Math.abs(center - draggedCenter);\n\t\t\tif (distance < bestDistance) {\n\t\t\t\tbestDistance = distance;\n\t\t\t\tbest = index;\n\t\t\t}\n\t\t});\n\t\treturn best;\n\t};\n\n\t/**\n\t * Сдвиг колонки при перестановке `from → to`.\n\t *\n\t * Двигаются только те, кто оказался между исходным и целевым слотом; закреплённые\n\t * не двигаются никогда, потому что в перестановке не участвуют.\n\t */\n\tconst shiftOf = (session: NonNullable<typeof sessionRef.current>, index: number, to: number) => {\n\t\tconst width = latest.current.widths[session.key];\n\t\tconst { from } = session;\n\t\tif (index === from || !session.movable.includes(index)) return 0;\n\t\tif (from < to && index > from && index <= to) return -width;\n\t\tif (from > to && index >= to && index < from) return width;\n\t\treturn 0;\n\t};\n\n\t/** Порядок колонок после перестановки `from → to`. Закреплённые сохраняют свои индексы. */\n\tconst orderAfter = (session: NonNullable<typeof sessionRef.current>, to: number) => {\n\t\tconst { columns: currentColumns } = latest.current;\n\t\tconst next = [...currentColumns];\n\t\tconst movableKeys = session.movable.map((index) => currentColumns[index]);\n\t\tconst [moved] = movableKeys.splice(session.movable.indexOf(session.from), 1);\n\t\tmovableKeys.splice(session.movable.indexOf(to), 0, moved);\n\t\tsession.movable.forEach((index, slot) => (next[index] = movableKeys[slot]));\n\t\treturn next;\n\t};\n\n\t/**\n\t * Левый край плывущей колонки в раскладке, которая получится после перестановки.\n\t *\n\t * Считается по будущему порядку, а не как `offsets[to]`. При движении вправо соседи между\n\t * слотами уезжают влево, и колонка встаёт не на левый край целевого слота, а на его правый\n\t * край минус собственная ширина; `offsets[to]` промахивается ровно на разницу ширин целевой\n\t * и перетаскиваемой колонок. На колонках равной ширины это ноль, на разных — заметный\n\t * скачок в момент, когда анимация закончилась и трансформации сняты.\n\t */\n\tconst offsetAfter = (session: NonNullable<typeof sessionRef.current>, to: number) => {\n\t\tconst { widths: currentWidths } = latest.current;\n\t\tconst next = orderAfter(session, to);\n\t\treturn next.slice(0, next.indexOf(session.key)).reduce((sum, columnKey) => sum + currentWidths[columnKey], 0);\n\t};\n\n\tconst finish = (commit: boolean) => {\n\t\tconst session = sessionRef.current;\n\t\tsessionRef.current = null;\n\t\tsetDragKey(null);\n\t\tif (!session) return;\n\n\t\tconst { table, from, to } = session;\n\n\t\tif (!commit || from === to) {\n\t\t\tclearTransforms();\n\t\t\treturn;\n\t\t}\n\n\t\t// Колонка доезжает до своего слота, и только потом порядок меняется в state:\n\t\t// иначе она прыгнула бы из-под курсора на новое место рывком.\n\t\tconst settleShift = offsetAfter(session, to) - session.offsets[from];\n\t\tsetColumnTransform(table, session.key, settleShift, false, session.borderColor);\n\n\t\tclearTimeout(settleTimer.current);\n\t\tsettleTimer.current = setTimeout(() => {\n\t\t\tclearTransforms();\n\t\t\tlatest.current.onReorder(orderAfter(session, to));\n\t\t}, TRANSITION_MS);\n\t};\n\n\tconst onPointerDown = (key: K) => (event: ReactPointerEvent) => {\n\t\tif (event.button !== 0 || lockedSet.has(key)) return;\n\t\tconst table = (event.currentTarget as HTMLElement).closest(\"table\");\n\t\tif (!table) return;\n\n\t\tevent.preventDefault();\n\n\t\tconst { columns: currentColumns, widths: currentWidths } = latest.current;\n\t\tconst offsets: number[] = [];\n\t\tcurrentColumns.reduce((sum, columnKey) => {\n\t\t\toffsets.push(sum);\n\t\t\treturn sum + currentWidths[columnKey];\n\t\t}, 0);\n\n\t\t// Цвет разделителя снимается с первой колонки, у которой правая граница есть:\n\t\t// у последней её нет (`last:border-r-0`), а цвет у всех один.\n\t\tconst borderColor = currentColumns\n\t\t\t.map((columnKey) => {\n\t\t\t\tconst head = table.querySelector<HTMLElement>(`thead [${COLUMN_KEY_ATTRIBUTE}=\"${columnKey}\"]`);\n\t\t\t\tif (!head) return undefined;\n\t\t\t\tconst style = window.getComputedStyle(head);\n\t\t\t\treturn parseFloat(style.borderRightWidth) > 0 ? style.borderRightColor : undefined;\n\t\t\t})\n\t\t\t.find(Boolean);\n\n\t\tconst from = currentColumns.indexOf(key);\n\t\tsessionRef.current = {\n\t\t\tborderColor,\n\t\t\tkey,\n\t\t\ttable,\n\t\t\tstartX: event.clientX,\n\t\t\tmovable: currentColumns.map((_, index) => index).filter((index) => !lockedSet.has(currentColumns[index])),\n\t\t\toffsets,\n\t\t\tfrom,\n\t\t\tto: from,\n\t\t\tstarted: false\n\t\t};\n\n\t\tconst onMove = (moveEvent: PointerEvent) => {\n\t\t\tconst session = sessionRef.current;\n\t\t\tif (!session) return;\n\n\t\t\tconst dx = moveEvent.clientX - session.startX;\n\t\t\t// Пока курсор не ушёл дальше порога, это ещё клик: нажатие на ручку не должно\n\t\t\t// дёргать колонку от дрожания руки.\n\t\t\tif (!session.started) {\n\t\t\t\tif (Math.abs(dx) < DRAG_THRESHOLD) return;\n\t\t\t\tsession.started = true;\n\t\t\t\tsetDragKey(session.key);\n\t\t\t\tcellsOf(session.table, session.key).forEach(markOpaque);\n\t\t\t}\n\n\t\t\tconst to = targetIndex(session, dx);\n\t\t\tsession.to = to;\n\n\t\t\t// Колонка, которая окажется справа от пустого слота: ей нужен левый край.\n\t\t\tconst order = orderAfter(session, to);\n\t\t\tconst afterSlot = order[order.indexOf(session.key) + 1];\n\n\t\t\tsetColumnTransform(session.table, session.key, dx, true, session.borderColor);\n\t\t\tlatest.current.columns.forEach((columnKey, index) => {\n\t\t\t\tif (index === session.from) return;\n\t\t\t\tconst shift = shiftOf(session, index, to);\n\t\t\t\tconst leftEdge = columnKey === afterSlot ? session.borderColor : undefined;\n\t\t\t\tsetColumnTransform(session.table, columnKey, shift, false, leftEdge);\n\t\t\t});\n\t\t};\n\n\t\tconst onUp = () => {\n\t\t\twindow.removeEventListener(\"pointermove\", onMove);\n\t\t\twindow.removeEventListener(\"pointerup\", onUp);\n\t\t\twindow.removeEventListener(\"pointercancel\", onCancel);\n\t\t\tfinish(sessionRef.current?.started ?? false);\n\t\t};\n\n\t\tconst onCancel = () => {\n\t\t\twindow.removeEventListener(\"pointermove\", onMove);\n\t\t\twindow.removeEventListener(\"pointerup\", onUp);\n\t\t\twindow.removeEventListener(\"pointercancel\", onCancel);\n\t\t\tfinish(false);\n\t\t};\n\n\t\twindow.addEventListener(\"pointermove\", onMove);\n\t\twindow.addEventListener(\"pointerup\", onUp);\n\t\twindow.addEventListener(\"pointercancel\", onCancel);\n\t};\n\n\treturn {\n\t\tdragKey,\n\t\tgetGripProps: (key: K) => ({\n\t\t\tonPointerDown: onPointerDown(key),\n\t\t\t// Без этого браузер на тач-устройстве начнёт прокрутку вместо перетаскивания.\n\t\t\tstyle: { touchAction: \"none\" as const }\n\t\t}),\n\t\tgetColumnProps: (key: K) => ({ [COLUMN_KEY_ATTRIBUTE]: key })\n\t};\n}\n"],"names":["COLUMN_KEY_ATTRIBUTE","TRANSITION_MS","DRAG_THRESHOLD","useColumnReorder","columns","widths","onReorder","locked","dragKey","setDragKey","useState","sessionRef","useRef","settleTimer","opaqueCells","touchedCells","lockedSet","useMemo","latest","useEffect","cellsOf","table","key","markOpaque","cell","classes","opaqueCellStyles","className","clearOpaque","rememberCell","transform","transition","position","zIndex","boxShadow","setColumnSeparator","leftEdge","setColumnTransform","shift","dragged","moving","clearTransforms","styles","targetIndex","session","dx","currentWidths","draggedCenter","best","bestDistance","index","center","distance","shiftOf","to","width","from","orderAfter","currentColumns","next","movableKeys","moved","slot","offsetAfter","sum","columnKey","finish","commit","settleShift","onPointerDown","event","offsets","borderColor","head","style","_","onMove","moveEvent","order","afterSlot","onUp","onCancel"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ics-ui-kit",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "packageManager": "pnpm@10.17.1",
5
5
  "repository": {
6
6
  "type": "git",