ics-ui-kit 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (175) hide show
  1. package/README.md +73 -73
  2. package/dist/AlertContext-CxjW1LVL.js.map +1 -1
  3. package/dist/AlertIcon-BphnEYvV.js.map +1 -1
  4. package/dist/Button-_qdP4hSf.js.map +1 -1
  5. package/dist/ButtonBase-CbWrYcx-.js.map +1 -1
  6. package/dist/CalendarPreviousMonthButton-CHMp8bkd.js.map +1 -1
  7. package/dist/CheckboxField-xDqHgXHh.js.map +1 -1
  8. package/dist/Combination-DeIugdgY.js.map +1 -1
  9. package/dist/{Command-WsAKNQrY.js → Command-hVL9sUnd.js} +3 -3
  10. package/dist/Command-hVL9sUnd.js.map +1 -0
  11. package/dist/ComponentVariantProvider-brk0g-hm.js.map +1 -1
  12. package/dist/Description-BTPMlTT-.js.map +1 -1
  13. package/dist/{Dialog-i_Y-phdM.js → Dialog-BKCZO7T_.js} +2 -2
  14. package/dist/Dialog-BKCZO7T_.js.map +1 -0
  15. package/dist/Divider-DPW5ZhZ8.js.map +1 -1
  16. package/dist/EmptyState-DRKjscH-.js.map +1 -1
  17. package/dist/ErrorState-B26k67-z.js.map +1 -1
  18. package/dist/FeatureIcon-BGE0Orkc.js.map +1 -1
  19. package/dist/Field-BcwUtgGr.js.map +1 -1
  20. package/dist/FieldLabel-DYu1AcGH.js.map +1 -1
  21. package/dist/FolderSvg-cw0DxNVy.js.map +1 -1
  22. package/dist/{FormFooterTemplate-CHlas_Pp.js → FormFooterTemplate-CRkxi-Mh.js} +2 -2
  23. package/dist/FormFooterTemplate-CRkxi-Mh.js.map +1 -0
  24. package/dist/{FormHeader-PE63OqG9.js → FormHeader-CX2jsIcI.js} +2 -2
  25. package/dist/FormHeader-CX2jsIcI.js.map +1 -0
  26. package/dist/FormStack-DfoaOry7.js.map +1 -1
  27. package/dist/HintState-BxrCAWqq.js.map +1 -1
  28. package/dist/Icon-DH3ev9GK.js.map +1 -1
  29. package/dist/IconButton-DAg1oMwz.js.map +1 -1
  30. package/dist/IconTooltip-R6_6_f40.js.map +1 -1
  31. package/dist/Indicator-AqxHWPA9.js.map +1 -1
  32. package/dist/InputGroup-CW55G5nE.js.map +1 -1
  33. package/dist/InputOTP-DkVh6bBz.js.map +1 -1
  34. package/dist/Loader-BpHiL6W-.js.map +1 -1
  35. package/dist/MenuItem-C51uFz3V.js.map +1 -1
  36. package/dist/MenuItemShortcut-D1faeIXp.js.map +1 -1
  37. package/dist/MenuItemText-CRpaPbvg.js.map +1 -1
  38. package/dist/Overlay-E0UvxzIc.js.map +1 -1
  39. package/dist/Popover-XrJa7lyb.js.map +1 -1
  40. package/dist/RichButton-Bt0yUShU.js.map +1 -1
  41. package/dist/ScrollArea-CuuTeDn3.js.map +1 -1
  42. package/dist/{ScrollShadowContainer-DdrnF8qU.js → ScrollShadowContainer-KUmqA25a.js} +11 -11
  43. package/dist/ScrollShadowContainer-KUmqA25a.js.map +1 -0
  44. package/dist/SearchSelectTag-Dp5_OvZp.js.map +1 -1
  45. package/dist/Select-DO02vXt3.js.map +1 -1
  46. package/dist/Sheet-C2UoHLL0.js.map +1 -1
  47. package/dist/Shortcut-D8L15_ed.js.map +1 -1
  48. package/dist/Skeleton-y6I-i9q5.js.map +1 -1
  49. package/dist/TableFillHandle-CHHoUi6s.js.map +1 -1
  50. package/dist/Tag-Cf6HftP-.js.map +1 -1
  51. package/dist/Text-DeBE8AKl.js.map +1 -1
  52. package/dist/TextInput-CoL8nOyt.js.map +1 -1
  53. package/dist/TextOverflowTooltip-XPDdO9Dz.js.map +1 -1
  54. package/dist/Toggle-CmalMf4O.js.map +1 -1
  55. package/dist/Tooltip-D2XvRS0c.js.map +1 -1
  56. package/dist/TriggerButton-CoAgB4lx.js.map +1 -1
  57. package/dist/blocks/auth/otp-form.js.map +1 -1
  58. package/dist/cn-dsXlqdJg.js.map +1 -1
  59. package/dist/components/alert-dialog.js.map +1 -1
  60. package/dist/components/alert.js.map +1 -1
  61. package/dist/components/avatar.js.map +1 -1
  62. package/dist/components/background-pattern.js.map +1 -1
  63. package/dist/components/badge.js.map +1 -1
  64. package/dist/components/banner.js.map +1 -1
  65. package/dist/components/breadcrumb.js.map +1 -1
  66. package/dist/components/button.js.map +1 -1
  67. package/dist/components/calendar-scroll.js +28 -27
  68. package/dist/components/calendar-scroll.js.map +1 -1
  69. package/dist/components/calendar.js.map +1 -1
  70. package/dist/components/card.js.map +1 -1
  71. package/dist/components/carousel.js.map +1 -1
  72. package/dist/components/collapsible.js.map +1 -1
  73. package/dist/components/color-tile.js.map +1 -1
  74. package/dist/components/command.js +1 -1
  75. package/dist/components/container.js.map +1 -1
  76. package/dist/components/context-menu.js.map +1 -1
  77. package/dist/components/counter.js.map +1 -1
  78. package/dist/components/dialog.js +3 -3
  79. package/dist/components/dialog.js.map +1 -1
  80. package/dist/components/divider.js.map +1 -1
  81. package/dist/components/drawer.js +1 -1
  82. package/dist/components/drawer.js.map +1 -1
  83. package/dist/components/dropdown.js.map +1 -1
  84. package/dist/components/error-state.js.map +1 -1
  85. package/dist/components/file-upload.js.map +1 -1
  86. package/dist/components/form.js +2 -2
  87. package/dist/components/form.js.map +1 -1
  88. package/dist/components/glass-toolbar.js.map +1 -1
  89. package/dist/components/image-placeholder.js.map +1 -1
  90. package/dist/components/image-preview.js.map +1 -1
  91. package/dist/components/image-uploader.js.map +1 -1
  92. package/dist/components/input.js.map +1 -1
  93. package/dist/components/menu-item.js.map +1 -1
  94. package/dist/components/page-state.js.map +1 -1
  95. package/dist/components/progress-circle.js.map +1 -1
  96. package/dist/components/progress.js.map +1 -1
  97. package/dist/components/prose.js.map +1 -1
  98. package/dist/components/radio-group.js.map +1 -1
  99. package/dist/components/resizable.js +26 -1530
  100. package/dist/components/resizable.js.map +1 -1
  101. package/dist/components/scheduler/components/hour-rows/HourRows.stories.d.ts +1 -1
  102. package/dist/components/scheduler/components/week-days/WeekDays.stories.d.ts +1 -0
  103. package/dist/components/scheduler.js.map +1 -1
  104. package/dist/components/scroll-shadow-container.js +1 -1
  105. package/dist/components/search-select.js +1 -1
  106. package/dist/components/search-select.js.map +1 -1
  107. package/dist/components/sidebar.js +142 -141
  108. package/dist/components/sidebar.js.map +1 -1
  109. package/dist/components/slider.js.map +1 -1
  110. package/dist/components/stepper.js.map +1 -1
  111. package/dist/components/switch.js.map +1 -1
  112. package/dist/components/system-state.js.map +1 -1
  113. package/dist/components/table/tree.js +1 -1
  114. package/dist/components/table.js +1 -1
  115. package/dist/components/tabs.js.map +1 -1
  116. package/dist/components/tag-input.js.map +1 -1
  117. package/dist/components/textarea.js +30 -189
  118. package/dist/components/textarea.js.map +1 -1
  119. package/dist/components/timer.js.map +1 -1
  120. package/dist/components/toast.js.map +1 -1
  121. package/dist/components/toggle-group.js.map +1 -1
  122. package/dist/components/toolbar.js.map +1 -1
  123. package/dist/docs/tailwind-utilities/ScrollFade.stories.d.ts +1 -0
  124. package/dist/floating-ui.react-dom-BwDfy92G.js.map +1 -1
  125. package/dist/font-smoothing.css +4 -4
  126. package/dist/formatBytes-C4QXq5lC.js.map +1 -1
  127. package/dist/index-0ioNhtNM.js.map +1 -1
  128. package/dist/index-1SnkxfPR.js.map +1 -1
  129. package/dist/index-437EL2iq.js.map +1 -1
  130. package/dist/index-BDrapWDv.js.map +1 -1
  131. package/dist/index-BGQepRFJ.js.map +1 -1
  132. package/dist/index-BVqs-uqP.js.map +1 -1
  133. package/dist/index-BZPx6jYI.js.map +1 -1
  134. package/dist/index-Bb23HztA.js.map +1 -1
  135. package/dist/index-BjtNfqNq.js.map +1 -1
  136. package/dist/index-BpWB3aFK.js.map +1 -1
  137. package/dist/index-ByaXH_ih.js.map +1 -1
  138. package/dist/index-CCKe-Mpx.js.map +1 -1
  139. package/dist/index-CFaU3UXv.js.map +1 -1
  140. package/dist/index-CLuiUUQ8.js.map +1 -1
  141. package/dist/index-CMxHunQ4.js.map +1 -1
  142. package/dist/index-CmBeyp2d.js.map +1 -1
  143. package/dist/index-DFZozV_h.js.map +1 -1
  144. package/dist/index-DHsfW5Rj.js.map +1 -1
  145. package/dist/index-DHyZ_0Ut.js.map +1 -1
  146. package/dist/index-DLcqcWxM.js.map +1 -1
  147. package/dist/index-DnnQs07z.js.map +1 -1
  148. package/dist/index-Uiy0Xwy2.js.map +1 -1
  149. package/dist/index-_ITz1IyW.js.map +1 -1
  150. package/dist/index.js.map +1 -1
  151. package/dist/inputBaseStyles-CZwQWSub.js.map +1 -1
  152. package/dist/lib/utils.js.map +1 -1
  153. package/dist/opaqueCell-D95h1mFM.js.map +1 -1
  154. package/dist/scroll-fade-fix.css +120 -0
  155. package/dist/ssr.test.d.ts +1 -0
  156. package/dist/tailwind.css +408 -407
  157. package/dist/theme.css +360 -360
  158. package/dist/{treeModel-CUO1A5s7.js → treeModel-BH6Jg8rm.js} +2 -2
  159. package/dist/treeModel-BH6Jg8rm.js.map +1 -0
  160. package/dist/types/css.d.ts +4 -4
  161. package/dist/useBreakpoints-DHvp74UL.js.map +1 -1
  162. package/dist/useDebounce-BRah78CF.js.map +1 -1
  163. package/dist/useFileUpload-Bnl3P8mP.js.map +1 -1
  164. package/dist/useIsomorphicLayoutEffect-MNxJD61V.js +6 -0
  165. package/dist/useIsomorphicLayoutEffect-MNxJD61V.js.map +1 -0
  166. package/dist/useItemsKeyboardNavigation-CmeOR30y.js.map +1 -1
  167. package/dist/useMergeRefs-qoKniYqT.js.map +1 -1
  168. package/package.json +213 -210
  169. package/dist/Command-WsAKNQrY.js.map +0 -1
  170. package/dist/Dialog-i_Y-phdM.js.map +0 -1
  171. package/dist/FormFooterTemplate-CHlas_Pp.js.map +0 -1
  172. package/dist/FormHeader-PE63OqG9.js.map +0 -1
  173. package/dist/ScrollShadowContainer-DdrnF8qU.js.map +0 -1
  174. package/dist/design-tokens.source.json +0 -1
  175. package/dist/treeModel-CUO1A5s7.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"TableFillHandle-CHHoUi6s.js","sources":["../src/components/table/editable/editableCell.ts","../src/components/table/editable/cellRange.ts","../src/components/table/editable/TableFillHandle.tsx"],"sourcesContent":["import { tv, type VariantProps } from \"tailwind-variants\";\r\n\r\n/**\r\n * Ячейка редактируемой таблицы: скелет сетки и заливка по состоянию.\r\n *\r\n * Скелет один на все состояния. `relative` — контекст позиционирования для ручки\r\n * автозаполнения (`TableFillHandle`), `cursor-cell` — курсор сетки вместо стрелки,\r\n * `select-none` — чтобы протягивание выделения мышью не выделяло текст.\r\n *\r\n * **Состояние — одна ось, а не набор флагов.** Все состояния красят одно и то же —\r\n * `background-color`, поэтому одновременно видно ровно одно. Будь это булевы пропы,\r\n * у ячейки «изменена и нередактируема» победил бы не тот класс, который передали последним,\r\n * а тот, что стоит ниже в стилях: порядок в атрибуте `class` браузер не учитывает.\r\n * С одним `state` выбор делается явно — и делает его прикладной код, потому что приоритет\r\n * состояний зависит от задачи: где-то важнее показать правку, где-то — запрет на неё.\r\n *\r\n * Что означают состояния и когда их включать, кит не знает: «изменена» — это правка,\r\n * не отправленная на сервер, или отличие от прошлой версии? Ячейка только красится.\r\n *\r\n * | Состояние | Смысл |\r\n * | ------------ | ------------------------------------------------------------ |\r\n * | `readonly` | правка запрещена — приглушённый текст на серой заливке |\r\n * | `modified` | значение изменено |\r\n * | `editing` | открыт редактор — та же заливка плюс кольцо фокуса |\r\n * | `fillSource` | ячейка, из которой тянут значения |\r\n *\r\n * @example\r\n * <TableCell\r\n * className={cellStateStyles({\r\n * state: isEditing ? \"editing\" : isModified ? \"modified\" : readonly ? \"readonly\" : undefined,\r\n * className: column.numeric ? \"text-right tabular-nums\" : undefined\r\n * })}\r\n * >\r\n */\r\nexport const cellStateStyles = tv({\r\n\tbase: \"relative cursor-cell select-none\",\r\n\tvariants: {\r\n\t\tstate: {\r\n\t\t\treadonly: \"bg-secondary-bg-hover text-muted\",\r\n\t\t\tfillSource: \"bg-primary-bg-hover\",\r\n\t\t\tmodified: \"bg-status-warning-bg-hover\",\r\n\t\t\tediting: \"bg-status-warning-bg-hover shadow-focus\"\r\n\t\t}\r\n\t}\r\n});\r\n\r\n/**\r\n * Поле правки внутри ячейки — `input`, `textarea` или редактируемый `div`.\r\n *\r\n * Прозрачный фон обязателен: заливку ячейка уже нарисовала своим состоянием, и собственный\r\n * фон поля закрыл бы её. Снятый `outline` — по той же причине: рамку правки рисует ячейка\r\n * (`state: \"editing\"`), а вторая обводка внутри первой выглядит браком.\r\n *\r\n * `multiline` возвращает выделение текста, снятое у ячейки ради протягивания мышью, и учит\r\n * поле переносам: без `whitespace-pre-wrap` переносы в значении схлопнутся в пробелы,\r\n * без `break-words` длинное слово растянет колонку.\r\n *\r\n * @example\r\n * <input className={cellEditorStyles({ className: column.numeric ? \"text-right\" : undefined })} />\r\n * <div contentEditable className={cellEditorStyles({ multiline: true })} />\r\n */\r\nexport const cellEditorStyles = tv({\r\n\tbase: \"w-full bg-transparent outline-hidden\",\r\n\tvariants: {\r\n\t\tmultiline: {\r\n\t\t\ttrue: \"select-text whitespace-pre-wrap break-words\"\r\n\t\t}\r\n\t}\r\n});\r\n\r\n/**\r\n * Состояние ячейки — то, что она означает прямо сейчас.\r\n *\r\n * Выведено из самого `cellStateStyles`, поэтому список состояний в типе и в стилях\r\n * не разъезжается.\r\n */\r\nexport type CellState = NonNullable<VariantProps<typeof cellStateStyles>[\"state\"]>;\r\n","import type { CSSProperties } from \"react\";\n\n/** Адрес ячейки в сетке: индекс видимой строки и индекс видимой колонки. */\nexport type CellRef = { row: number; col: number };\n\n/** Прямоугольный диапазон ячеек. Границы включительно, поэтому одна ячейка — тоже диапазон. */\nexport type CellRange = { top: number; bottom: number; left: number; right: number };\n\n/**\n * Диапазон по двум углам — якорю выделения и текущей ячейке.\n *\n * Порядок углов не важен: тянут выделение в любую сторону, поэтому границы нормализуются.\n * Это геометрия, а не поведение: где стоит якорь, когда он переставляется и что вообще\n * считается выделением — знание прикладного кода.\n *\n * @example\n * cellRange({ row: 4, col: 1 }, { row: 2, col: 3 }); // { top: 2, bottom: 4, left: 1, right: 3 }\n */\nexport const cellRange = (anchor: CellRef, focus: CellRef): CellRange => ({\n\ttop: Math.min(anchor.row, focus.row),\n\tbottom: Math.max(anchor.row, focus.row),\n\tleft: Math.min(anchor.col, focus.col),\n\tright: Math.max(anchor.col, focus.col)\n});\n\n/** Попадает ли ячейка в диапазон. Отсутствие диапазона — не попадает, проверять отдельно не нужно. */\nexport const inCellRange = (range: CellRange | null | undefined, cell: CellRef): boolean =>\n\tBoolean(range) &&\n\tcell.row >= range!.top &&\n\tcell.row <= range!.bottom &&\n\tcell.col >= range!.left &&\n\tcell.col <= range!.right;\n\n/** Как выглядит грань диапазона: цвет и толщина линии. */\nexport type CellRangeEdge = { color: string; width: number };\n\n/**\n * Готовые рамки диапазонов: `selection` — то, что выделено, `preview` — то, что получится,\n * если отпустить сейчас (протягивание значений, перенос).\n *\n * Предпросмотр намеренно тоньше и бледнее выделения: две одинаковые рамки на экране\n * невозможно различить, а они означают разное — состоявшееся и предполагаемое.\n *\n * Список открытый: своя рамка — это `{ color, width }` с любым CSS-цветом.\n */\nexport const CELL_RANGE_EDGE = {\n\tselection: { color: \"hsl(var(--primary-accent))\", width: 2 },\n\tpreview: { color: \"hsl(var(--primary-border) / 0.75)\", width: 1 }\n} as const satisfies Record<string, CellRangeEdge>;\n\n/**\n * Грани диапазона, проходящие через эту ячейку, — готовая строка для `box-shadow`.\n *\n * Рамка обводит диапазон целиком, а не каждую его ячейку: грань достаётся только тем ячейкам,\n * что стоят по краю, поэтому внутри диапазона линий нет. Ячейка вне диапазона (и отсутствие\n * диапазона) даёт пустую строку — проверять попадание перед вызовом не нужно.\n *\n * **Почему тень, а не рамка.** `border` входит в бокс ячейки и раздвинул бы колонки на\n * ширину линии, `outline` обвёл бы каждую ячейку целиком. `inset`-тень рисуется внутри\n * ячейки и ничего не двигает.\n *\n * Значения считаются на ходу и потому уезжают в инлайновый стиль, но цвет всё равно берётся\n * из токена, а не хардкодом.\n *\n * @example\n * cellRangeEdges(selection, { row: 2, col: 0 }); // \"inset 0 2px 0 0 …, inset 2px 0 0 0 …\"\n */\nexport const cellRangeEdges = (\n\trange: CellRange | null | undefined,\n\tcell: CellRef,\n\tedge: CellRangeEdge = CELL_RANGE_EDGE.selection\n): string => {\n\tif (!range || !inCellRange(range, cell)) return \"\";\n\n\tconst { color, width } = edge;\n\tconst edges: string[] = [];\n\n\tif (cell.row === range.top) edges.push(`inset 0 ${width}px 0 0 ${color}`);\n\tif (cell.row === range.bottom) edges.push(`inset 0 -${width}px 0 0 ${color}`);\n\tif (cell.col === range.left) edges.push(`inset ${width}px 0 0 0 ${color}`);\n\tif (cell.col === range.right) edges.push(`inset -${width}px 0 0 0 ${color}`);\n\n\treturn edges.join(\", \");\n};\n\n/**\n * Рамки нескольких диапазонов в одном `style` ячейки. Первый аргумент — верхняя тень.\n *\n * Ложные и пустые значения отбрасываются, поэтому условия пишутся прямо в аргументах,\n * а ячейка без единой грани не получает инлайнового стиля вовсе.\n *\n * @example\n * <TableCell\n * style={cellRangeStyle(\n * cellRangeEdges(selection, cell),\n * cellRangeEdges(fillPreview, cell, CELL_RANGE_EDGE.preview)\n * )}\n * >\n */\nexport const cellRangeStyle = (...shadows: (string | false | null | undefined)[]): CSSProperties => {\n\tconst layers = shadows.filter(Boolean);\n\n\treturn layers.length ? { boxShadow: layers.join(\", \") } : {};\n};\n","import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nconst tableFillHandleStyles = tv({\n\t// Смещение в половину размера: ручка садится ровно на угол ячейки, а не рядом с ним.\n\tbase: [\n\t\t\"absolute -bottom-[5px] -right-[5px] z-10 size-2.5 cursor-crosshair rounded-full\",\n\t\t\"border border-secondary-bg bg-primary-accent\"\n\t]\n});\n\nexport type TableFillHandleProps = React.HTMLAttributes<HTMLSpanElement>;\n\n/**\n * Ручка автозаполнения — точка на нижнем правом углу выделения, за которую тянут значения.\n *\n * Рисуется внутри угловой ячейки диапазона и позиционируется от неё, поэтому ячейке нужен\n * `position: relative` — он уже есть в `cellStateStyles`.\n *\n * По макету ручка круглая (`border radius/full`, 10px), хотя в Excel это квадрат — оставлено\n * как в макете.\n *\n * Кит даёт только вид и попадание курсором: что протянется, куда и как далеко — решает\n * прикладной код по `onMouseDown` и движению мыши.\n *\n * **Почему `span`, а не `button`.** Ручка работает только протягиванием мыши, клавиатурного\n * аналога у неё нет. Настоящая кнопка встала бы в порядок обхода табом и по Enter не делала\n * бы ничего — остановка фокуса, которая ничем не отвечает, хуже её отсутствия. Роль и подпись\n * при этом остаются: скринридер ручку видит и называет.\n *\n * @example\n * {isCorner && <TableFillHandle onMouseDown={() => setFillFrom(rowIndex)} />}\n */\nexport const TableFillHandle = React.forwardRef<HTMLSpanElement, TableFillHandleProps>(\n\t({ className, ...props }, ref) => (\n\t\t<span\n\t\t\tref={ref}\n\t\t\trole=\"button\"\n\t\t\taria-label=\"Протянуть значения\"\n\t\t\tclassName={tableFillHandleStyles({ className })}\n\t\t\t{...props}\n\t\t/>\n\t)\n);\n\nTableFillHandle.displayName = \"TableFillHandle\";\n"],"names":["cellStateStyles","tv","cellEditorStyles","cellRange","anchor","focus","inCellRange","range","cell","CELL_RANGE_EDGE","cellRangeEdges","edge","color","width","edges","cellRangeStyle","shadows","layers","tableFillHandleStyles","TableFillHandle","React","className","props","ref","jsx"],"mappings":";;;AAkCO,MAAMA,IAAkBC,EAAG;AAAA,EACjC,MAAM;AAAA,EACN,UAAU;AAAA,IACT,OAAO;AAAA,MACN,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,SAAS;AAAA,IAAA;AAAA,EACV;AAEF,CAAC,GAiBYC,IAAmBD,EAAG;AAAA,EAClC,MAAM;AAAA,EACN,UAAU;AAAA,IACT,WAAW;AAAA,MACV,MAAM;AAAA,IAAA;AAAA,EACP;AAEF,CAAC,GClDYE,IAAY,CAACC,GAAiBC,OAA+B;AAAA,EACzE,KAAK,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AAAA,EACnC,QAAQ,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AAAA,EACtC,MAAM,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AAAA,EACpC,OAAO,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AACtC,IAGaC,IAAc,CAACC,GAAqCC,MAChE,EAAQD,KACRC,EAAK,OAAOD,EAAO,OACnBC,EAAK,OAAOD,EAAO,UACnBC,EAAK,OAAOD,EAAO,QACnBC,EAAK,OAAOD,EAAO,OAcPE,IAAkB;AAAA,EAC9B,WAAW,EAAE,OAAO,8BAA8B,OAAO,EAAE;AAAA,EAC3D,SAAS,EAAE,OAAO,qCAAqC,OAAO,EAAE;AACjE,GAmBaC,IAAiB,CAC7BH,GACAC,GACAG,IAAsBF,EAAgB,cAC1B;AACZ,MAAI,CAACF,KAAS,CAACD,EAAYC,GAAOC,CAAI,EAAU,QAAA;AAE1C,QAAA,EAAE,OAAAI,GAAO,OAAAC,EAAA,IAAUF,GACnBG,IAAkB,CAAC;AAErB,SAAAN,EAAK,QAAQD,EAAM,OAAKO,EAAM,KAAK,WAAWD,CAAK,UAAUD,CAAK,EAAE,GACpEJ,EAAK,QAAQD,EAAM,UAAQO,EAAM,KAAK,YAAYD,CAAK,UAAUD,CAAK,EAAE,GACxEJ,EAAK,QAAQD,EAAM,QAAMO,EAAM,KAAK,SAASD,CAAK,YAAYD,CAAK,EAAE,GACrEJ,EAAK,QAAQD,EAAM,SAAOO,EAAM,KAAK,UAAUD,CAAK,YAAYD,CAAK,EAAE,GAEpEE,EAAM,KAAK,IAAI;AACvB,GAgBaC,IAAiB,IAAIC,MAAkE;AAC7F,QAAAC,IAASD,EAAQ,OAAO,OAAO;AAE9B,SAAAC,EAAO,SAAS,EAAE,WAAWA,EAAO,KAAK,IAAI,EAAE,IAAI,CAAC;AAC5D,GCpGMC,IAAwBjB,EAAG;AAAA;AAAA,EAEhC,MAAM;AAAA,IACL;AAAA,IACA;AAAA,EAAA;AAEF,CAAC,GAwBYkB,IAAkBC,EAAM;AAAA,EACpC,CAAC,EAAE,WAAAC,GAAW,GAAGC,KAASC,MACzB,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACA,KAAAD;AAAA,MACA,MAAK;AAAA,MACL,cAAW;AAAA,MACX,WAAWL,EAAsB,EAAE,WAAAG,GAAW;AAAA,MAC7C,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGP;AAEAH,EAAgB,cAAc;"}
1
+ {"version":3,"file":"TableFillHandle-CHHoUi6s.js","sources":["../src/components/table/editable/editableCell.ts","../src/components/table/editable/cellRange.ts","../src/components/table/editable/TableFillHandle.tsx"],"sourcesContent":["import { tv, type VariantProps } from \"tailwind-variants\";\n\n/**\n * Ячейка редактируемой таблицы: скелет сетки и заливка по состоянию.\n *\n * Скелет один на все состояния. `relative` — контекст позиционирования для ручки\n * автозаполнения (`TableFillHandle`), `cursor-cell` — курсор сетки вместо стрелки,\n * `select-none` — чтобы протягивание выделения мышью не выделяло текст.\n *\n * **Состояние — одна ось, а не набор флагов.** Все состояния красят одно и то же —\n * `background-color`, поэтому одновременно видно ровно одно. Будь это булевы пропы,\n * у ячейки «изменена и нередактируема» победил бы не тот класс, который передали последним,\n * а тот, что стоит ниже в стилях: порядок в атрибуте `class` браузер не учитывает.\n * С одним `state` выбор делается явно — и делает его прикладной код, потому что приоритет\n * состояний зависит от задачи: где-то важнее показать правку, где-то — запрет на неё.\n *\n * Что означают состояния и когда их включать, кит не знает: «изменена» — это правка,\n * не отправленная на сервер, или отличие от прошлой версии? Ячейка только красится.\n *\n * | Состояние | Смысл |\n * | ------------ | ------------------------------------------------------------ |\n * | `readonly` | правка запрещена — приглушённый текст на серой заливке |\n * | `modified` | значение изменено |\n * | `editing` | открыт редактор — та же заливка плюс кольцо фокуса |\n * | `fillSource` | ячейка, из которой тянут значения |\n *\n * @example\n * <TableCell\n * className={cellStateStyles({\n * state: isEditing ? \"editing\" : isModified ? \"modified\" : readonly ? \"readonly\" : undefined,\n * className: column.numeric ? \"text-right tabular-nums\" : undefined\n * })}\n * >\n */\nexport const cellStateStyles = tv({\n\tbase: \"relative cursor-cell select-none\",\n\tvariants: {\n\t\tstate: {\n\t\t\treadonly: \"bg-secondary-bg-hover text-muted\",\n\t\t\tfillSource: \"bg-primary-bg-hover\",\n\t\t\tmodified: \"bg-status-warning-bg-hover\",\n\t\t\tediting: \"bg-status-warning-bg-hover shadow-focus\"\n\t\t}\n\t}\n});\n\n/**\n * Поле правки внутри ячейки — `input`, `textarea` или редактируемый `div`.\n *\n * Прозрачный фон обязателен: заливку ячейка уже нарисовала своим состоянием, и собственный\n * фон поля закрыл бы её. Снятый `outline` — по той же причине: рамку правки рисует ячейка\n * (`state: \"editing\"`), а вторая обводка внутри первой выглядит браком.\n *\n * `multiline` возвращает выделение текста, снятое у ячейки ради протягивания мышью, и учит\n * поле переносам: без `whitespace-pre-wrap` переносы в значении схлопнутся в пробелы,\n * без `break-words` длинное слово растянет колонку.\n *\n * @example\n * <input className={cellEditorStyles({ className: column.numeric ? \"text-right\" : undefined })} />\n * <div contentEditable className={cellEditorStyles({ multiline: true })} />\n */\nexport const cellEditorStyles = tv({\n\tbase: \"w-full bg-transparent outline-hidden\",\n\tvariants: {\n\t\tmultiline: {\n\t\t\ttrue: \"select-text whitespace-pre-wrap break-words\"\n\t\t}\n\t}\n});\n\n/**\n * Состояние ячейки — то, что она означает прямо сейчас.\n *\n * Выведено из самого `cellStateStyles`, поэтому список состояний в типе и в стилях\n * не разъезжается.\n */\nexport type CellState = NonNullable<VariantProps<typeof cellStateStyles>[\"state\"]>;\n","import type { CSSProperties } from \"react\";\n\n/** Адрес ячейки в сетке: индекс видимой строки и индекс видимой колонки. */\nexport type CellRef = { row: number; col: number };\n\n/** Прямоугольный диапазон ячеек. Границы включительно, поэтому одна ячейка — тоже диапазон. */\nexport type CellRange = { top: number; bottom: number; left: number; right: number };\n\n/**\n * Диапазон по двум углам — якорю выделения и текущей ячейке.\n *\n * Порядок углов не важен: тянут выделение в любую сторону, поэтому границы нормализуются.\n * Это геометрия, а не поведение: где стоит якорь, когда он переставляется и что вообще\n * считается выделением — знание прикладного кода.\n *\n * @example\n * cellRange({ row: 4, col: 1 }, { row: 2, col: 3 }); // { top: 2, bottom: 4, left: 1, right: 3 }\n */\nexport const cellRange = (anchor: CellRef, focus: CellRef): CellRange => ({\n\ttop: Math.min(anchor.row, focus.row),\n\tbottom: Math.max(anchor.row, focus.row),\n\tleft: Math.min(anchor.col, focus.col),\n\tright: Math.max(anchor.col, focus.col)\n});\n\n/** Попадает ли ячейка в диапазон. Отсутствие диапазона — не попадает, проверять отдельно не нужно. */\nexport const inCellRange = (range: CellRange | null | undefined, cell: CellRef): boolean =>\n\tBoolean(range) &&\n\tcell.row >= range!.top &&\n\tcell.row <= range!.bottom &&\n\tcell.col >= range!.left &&\n\tcell.col <= range!.right;\n\n/** Как выглядит грань диапазона: цвет и толщина линии. */\nexport type CellRangeEdge = { color: string; width: number };\n\n/**\n * Готовые рамки диапазонов: `selection` — то, что выделено, `preview` — то, что получится,\n * если отпустить сейчас (протягивание значений, перенос).\n *\n * Предпросмотр намеренно тоньше и бледнее выделения: две одинаковые рамки на экране\n * невозможно различить, а они означают разное — состоявшееся и предполагаемое.\n *\n * Список открытый: своя рамка — это `{ color, width }` с любым CSS-цветом.\n */\nexport const CELL_RANGE_EDGE = {\n\tselection: { color: \"hsl(var(--primary-accent))\", width: 2 },\n\tpreview: { color: \"hsl(var(--primary-border) / 0.75)\", width: 1 }\n} as const satisfies Record<string, CellRangeEdge>;\n\n/**\n * Грани диапазона, проходящие через эту ячейку, — готовая строка для `box-shadow`.\n *\n * Рамка обводит диапазон целиком, а не каждую его ячейку: грань достаётся только тем ячейкам,\n * что стоят по краю, поэтому внутри диапазона линий нет. Ячейка вне диапазона (и отсутствие\n * диапазона) даёт пустую строку — проверять попадание перед вызовом не нужно.\n *\n * **Почему тень, а не рамка.** `border` входит в бокс ячейки и раздвинул бы колонки на\n * ширину линии, `outline` обвёл бы каждую ячейку целиком. `inset`-тень рисуется внутри\n * ячейки и ничего не двигает.\n *\n * Значения считаются на ходу и потому уезжают в инлайновый стиль, но цвет всё равно берётся\n * из токена, а не хардкодом.\n *\n * @example\n * cellRangeEdges(selection, { row: 2, col: 0 }); // \"inset 0 2px 0 0 …, inset 2px 0 0 0 …\"\n */\nexport const cellRangeEdges = (\n\trange: CellRange | null | undefined,\n\tcell: CellRef,\n\tedge: CellRangeEdge = CELL_RANGE_EDGE.selection\n): string => {\n\tif (!range || !inCellRange(range, cell)) return \"\";\n\n\tconst { color, width } = edge;\n\tconst edges: string[] = [];\n\n\tif (cell.row === range.top) edges.push(`inset 0 ${width}px 0 0 ${color}`);\n\tif (cell.row === range.bottom) edges.push(`inset 0 -${width}px 0 0 ${color}`);\n\tif (cell.col === range.left) edges.push(`inset ${width}px 0 0 0 ${color}`);\n\tif (cell.col === range.right) edges.push(`inset -${width}px 0 0 0 ${color}`);\n\n\treturn edges.join(\", \");\n};\n\n/**\n * Рамки нескольких диапазонов в одном `style` ячейки. Первый аргумент — верхняя тень.\n *\n * Ложные и пустые значения отбрасываются, поэтому условия пишутся прямо в аргументах,\n * а ячейка без единой грани не получает инлайнового стиля вовсе.\n *\n * @example\n * <TableCell\n * style={cellRangeStyle(\n * cellRangeEdges(selection, cell),\n * cellRangeEdges(fillPreview, cell, CELL_RANGE_EDGE.preview)\n * )}\n * >\n */\nexport const cellRangeStyle = (...shadows: (string | false | null | undefined)[]): CSSProperties => {\n\tconst layers = shadows.filter(Boolean);\n\n\treturn layers.length ? { boxShadow: layers.join(\", \") } : {};\n};\n","import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nconst tableFillHandleStyles = tv({\n\t// Смещение в половину размера: ручка садится ровно на угол ячейки, а не рядом с ним.\n\tbase: [\n\t\t\"absolute -bottom-[5px] -right-[5px] z-10 size-2.5 cursor-crosshair rounded-full\",\n\t\t\"border border-secondary-bg bg-primary-accent\"\n\t]\n});\n\nexport type TableFillHandleProps = React.HTMLAttributes<HTMLSpanElement>;\n\n/**\n * Ручка автозаполнения — точка на нижнем правом углу выделения, за которую тянут значения.\n *\n * Рисуется внутри угловой ячейки диапазона и позиционируется от неё, поэтому ячейке нужен\n * `position: relative` — он уже есть в `cellStateStyles`.\n *\n * По макету ручка круглая (`border radius/full`, 10px), хотя в Excel это квадрат — оставлено\n * как в макете.\n *\n * Кит даёт только вид и попадание курсором: что протянется, куда и как далеко — решает\n * прикладной код по `onMouseDown` и движению мыши.\n *\n * **Почему `span`, а не `button`.** Ручка работает только протягиванием мыши, клавиатурного\n * аналога у неё нет. Настоящая кнопка встала бы в порядок обхода табом и по Enter не делала\n * бы ничего — остановка фокуса, которая ничем не отвечает, хуже её отсутствия. Роль и подпись\n * при этом остаются: скринридер ручку видит и называет.\n *\n * @example\n * {isCorner && <TableFillHandle onMouseDown={() => setFillFrom(rowIndex)} />}\n */\nexport const TableFillHandle = React.forwardRef<HTMLSpanElement, TableFillHandleProps>(\n\t({ className, ...props }, ref) => (\n\t\t<span\n\t\t\tref={ref}\n\t\t\trole=\"button\"\n\t\t\taria-label=\"Протянуть значения\"\n\t\t\tclassName={tableFillHandleStyles({ className })}\n\t\t\t{...props}\n\t\t/>\n\t)\n);\n\nTableFillHandle.displayName = \"TableFillHandle\";\n"],"names":["cellStateStyles","tv","cellEditorStyles","cellRange","anchor","focus","inCellRange","range","cell","CELL_RANGE_EDGE","cellRangeEdges","edge","color","width","edges","cellRangeStyle","shadows","layers","tableFillHandleStyles","TableFillHandle","React","className","props","ref","jsx"],"mappings":";;;AAkCO,MAAMA,IAAkBC,EAAG;AAAA,EACjC,MAAM;AAAA,EACN,UAAU;AAAA,IACT,OAAO;AAAA,MACN,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,SAAS;AAAA,IAAA;AAAA,EACV;AAEF,CAAC,GAiBYC,IAAmBD,EAAG;AAAA,EAClC,MAAM;AAAA,EACN,UAAU;AAAA,IACT,WAAW;AAAA,MACV,MAAM;AAAA,IAAA;AAAA,EACP;AAEF,CAAC,GClDYE,IAAY,CAACC,GAAiBC,OAA+B;AAAA,EACzE,KAAK,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AAAA,EACnC,QAAQ,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AAAA,EACtC,MAAM,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AAAA,EACpC,OAAO,KAAK,IAAID,EAAO,KAAKC,EAAM,GAAG;AACtC,IAGaC,IAAc,CAACC,GAAqCC,MAChE,EAAQD,KACRC,EAAK,OAAOD,EAAO,OACnBC,EAAK,OAAOD,EAAO,UACnBC,EAAK,OAAOD,EAAO,QACnBC,EAAK,OAAOD,EAAO,OAcPE,IAAkB;AAAA,EAC9B,WAAW,EAAE,OAAO,8BAA8B,OAAO,EAAE;AAAA,EAC3D,SAAS,EAAE,OAAO,qCAAqC,OAAO,EAAE;AACjE,GAmBaC,IAAiB,CAC7BH,GACAC,GACAG,IAAsBF,EAAgB,cAC1B;AACZ,MAAI,CAACF,KAAS,CAACD,EAAYC,GAAOC,CAAI,EAAU,QAAA;AAE1C,QAAA,EAAE,OAAAI,GAAO,OAAAC,EAAA,IAAUF,GACnBG,IAAkB,CAAC;AAErB,SAAAN,EAAK,QAAQD,EAAM,OAAKO,EAAM,KAAK,WAAWD,CAAK,UAAUD,CAAK,EAAE,GACpEJ,EAAK,QAAQD,EAAM,UAAQO,EAAM,KAAK,YAAYD,CAAK,UAAUD,CAAK,EAAE,GACxEJ,EAAK,QAAQD,EAAM,QAAMO,EAAM,KAAK,SAASD,CAAK,YAAYD,CAAK,EAAE,GACrEJ,EAAK,QAAQD,EAAM,SAAOO,EAAM,KAAK,UAAUD,CAAK,YAAYD,CAAK,EAAE,GAEpEE,EAAM,KAAK,IAAI;AACvB,GAgBaC,IAAiB,IAAIC,MAAkE;AAC7F,QAAAC,IAASD,EAAQ,OAAO,OAAO;AAE9B,SAAAC,EAAO,SAAS,EAAE,WAAWA,EAAO,KAAK,IAAI,EAAE,IAAI,CAAC;AAC5D,GCpGMC,IAAwBjB,EAAG;AAAA;AAAA,EAEhC,MAAM;AAAA,IACL;AAAA,IACA;AAAA,EAAA;AAEF,CAAC,GAwBYkB,IAAkBC,EAAM;AAAA,EACpC,CAAC,EAAE,WAAAC,GAAW,GAAGC,KAASC,MACzB,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACA,KAAAD;AAAA,MACA,MAAK;AAAA,MACL,cAAW;AAAA,MACX,WAAWL,EAAsB,EAAE,WAAAG,GAAW;AAAA,MAC7C,GAAGC;AAAA,IAAA;AAAA,EAAA;AAGP;AAEAH,EAAgB,cAAc;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tag-Cf6HftP-.js","sources":["../src/components/tag/Tag.tsx"],"sourcesContent":["import React, { PropsWithChildren } from \"react\";\r\nimport { tv } from \"tailwind-variants\";\r\nimport { Slot } from \"@radix-ui/react-slot\";\r\nimport { LucideIcon, X } from \"lucide-react\";\r\nimport { Icon } from \"../icon\";\r\nimport { ButtonProps } from \"../button/button/Button\";\r\nimport { VariantsConfig } from \"@/lib/utils/variants\";\r\n\r\nexport interface TagBaseVariants {\r\n\tstatus?: \"default\" | \"info\" | \"success\" | \"warning\" | \"error\";\r\n\tfocus?: \"low\" | \"high\";\r\n\tsize?: \"sm\" | \"md\" | \"lg\";\r\n}\r\n\r\nconst tagBaseStyles = tv({\r\n\tbase: \"inline-flex items-center justify-center overflow-hidden font-medium transition-colors\",\r\n\tvariants: {\r\n\t\tstatus: {\r\n\t\t\tdefault: \"border-primary-border bg-status-neutral-bg text-primary-fg hover:bg-status-neutral-bg-hover\",\r\n\t\t\tinfo: \"border-status-info-primary-border bg-status-info-bg text-status-info-fg hover:bg-status-info-bg-hover\",\r\n\t\t\tsuccess:\r\n\t\t\t\t\"border-status-success-primary-border bg-status-success-bg text-status-success-fg hover:bg-status-success-bg-hover\",\r\n\t\t\twarning:\r\n\t\t\t\t\"border-status-warning-primary-border bg-status-warning-bg text-status-warning-fg hover:bg-status-warning-bg-hover\",\r\n\t\t\terror: \"border-status-error-primary-border bg-status-error-bg text-status-error-fg hover:bg-status-error-bg-hover\"\r\n\t\t},\r\n\t\tfocus: {\r\n\t\t\tlow: \"\",\r\n\t\t\thigh: \"\"\r\n\t\t},\r\n\t\tsize: {\r\n\t\t\tsm: \"h-5 px-1.5 py-1 text-xs leading-none\",\r\n\t\t\tmd: \"h-6 px-1.5 py-1 text-sm leading-none\",\r\n\t\t\tlg: \"h-7 px-2 py-1 text-base leading-none\"\r\n\t\t}\r\n\t} satisfies VariantsConfig<TagBaseVariants>,\r\n\tdefaultVariants: {\r\n\t\tstatus: \"default\",\r\n\t\tfocus: \"low\",\r\n\t\tsize: \"md\"\r\n\t},\r\n\tcompoundVariants: [\r\n\t\t{\r\n\t\t\tstatus: [\"info\", \"success\", \"warning\", \"error\"],\r\n\t\t\tfocus: \"high\",\r\n\t\t\tclass: \"text-white\"\r\n\t\t},\r\n\t\t{\r\n\t\t\tstatus: \"default\",\r\n\t\t\tfocus: \"high\",\r\n\t\t\tclass: \"border-transparent bg-status-neutral text-primary-bg hover:bg-status-neutral-hover\"\r\n\t\t},\r\n\t\t{\r\n\t\t\tstatus: \"info\",\r\n\t\t\tfocus: \"high\",\r\n\t\t\tclass: \"border-transparent bg-status-info hover:bg-status-info-hover\"\r\n\t\t},\r\n\t\t{\r\n\t\t\tstatus: \"success\",\r\n\t\t\tfocus: \"high\",\r\n\t\t\tclass: \"border-transparent bg-status-success hover:bg-status-success-hover\"\r\n\t\t},\r\n\t\t{\r\n\t\t\tstatus: \"warning\",\r\n\t\t\tfocus: \"high\",\r\n\t\t\tclass: \"border-transparent bg-status-warning hover:bg-status-warning-hover\"\r\n\t\t},\r\n\t\t{\r\n\t\t\tstatus: \"error\",\r\n\t\t\tfocus: \"high\",\r\n\t\t\tclass: \"border-transparent bg-status-error hover:bg-status-error-hover\"\r\n\t\t}\r\n\t]\r\n});\r\n\r\nexport type TagBaseProps = React.HTMLAttributes<HTMLElement> &\r\n\tTagBaseVariants & {\r\n\t\tasChild?: boolean;\r\n\t};\r\n\r\nexport const TagBase = ({ asChild = false, children, ...props }: PropsWithChildren<TagBaseProps>) => {\r\n\tconst Comp = asChild ? Slot : \"span\";\r\n\treturn (\r\n\t\t<Comp className={tagBaseStyles(props)} {...props}>\r\n\t\t\t{children}\r\n\t\t</Comp>\r\n\t);\r\n};\r\n\r\nTagBase.displayName = \"TagBase\";\r\n\r\nexport interface TagButtonVariants {\r\n\tsize?: \"sm\" | \"md\" | \"lg\";\r\n\tclickable?: boolean;\r\n\tposition?: \"standalone\" | \"left\" | \"right\" | \"middle\";\r\n}\r\n\r\nconst tagButtonStyles = tv({\r\n\textend: tagBaseStyles,\r\n\tbase: \"z-10 flex cursor-pointer items-center justify-center whitespace-nowrap rounded-sm border focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-primary\",\r\n\tvariants: {\r\n\t\tsize: {\r\n\t\t\tsm: \"gap-1\",\r\n\t\t\tmd: \"gap-1\",\r\n\t\t\tlg: \"gap-1.5\"\r\n\t\t},\r\n\t\tclickable: {\r\n\t\t\tfalse: \"cursor-default\"\r\n\t\t},\r\n\t\tposition: {\r\n\t\t\tstandalone: \"\",\r\n\t\t\tleft: \"rounded-r-none border-r-0\",\r\n\t\t\tright: \"rounded-l-none border-l-0\",\r\n\t\t\tmiddle: \"rounded-none border-l-0 border-r-0\"\r\n\t\t}\r\n\t} satisfies VariantsConfig<TagButtonVariants>,\r\n\tdefaultVariants: {\r\n\t\tclickable: true,\r\n\t\tposition: \"standalone\"\r\n\t}\r\n});\r\n\r\nexport type TagButtonProps = React.HTMLAttributes<HTMLElement> &\r\n\tTagButtonVariants &\r\n\tOmit<TagBaseVariants, \"size\"> & {\r\n\t\tasChild?: boolean;\r\n\t};\r\n\r\nexport const TagButton = (props: PropsWithChildren<TagButtonProps>) => {\r\n\tconst { asChild = false, children, className, ...rest } = props;\r\n\tconst Comp = asChild ? Slot : \"button\";\r\n\tconst styles = tagButtonStyles({ className, ...rest });\r\n\treturn (\r\n\t\t<Comp className={styles} {...rest}>\r\n\t\t\t{children}\r\n\t\t</Comp>\r\n\t);\r\n};\r\n\r\nTagButton.displayName = \"TagButton\";\r\n\r\nexport interface TagCloseVariants {\r\n\tsize?: \"sm\" | \"md\" | \"lg\";\r\n\tfocus?: \"low\" | \"high\";\r\n}\r\n\r\nconst tagCloseStyles = tv({\r\n\textend: tagBaseStyles,\r\n\tbase: \"aspect-square cursor-pointer rounded-l-none rounded-r-sm border border-l-0 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-primary\",\r\n\tvariants: {\r\n\t\tsize: {\r\n\t\t\tsm: \"h-5 p-1 text-xs\",\r\n\t\t\tmd: \"h-6 p-1 text-sm\",\r\n\t\t\tlg: \"h-7 p-1.5 text-base\"\r\n\t\t},\r\n\t\tfocus: {\r\n\t\t\tlow: \"\",\r\n\t\t\thigh: \"\"\r\n\t\t}\r\n\t} satisfies VariantsConfig<TagCloseVariants>\r\n});\r\n\r\nconst tagIconStyles = tv({\r\n\tbase: \"aspect-square shrink-0\",\r\n\tvariants: {\r\n\t\tsize: {\r\n\t\t\tsm: \"h-3 w-3\",\r\n\t\t\tmd: \"h-3.5 w-3.5\",\r\n\t\t\tlg: \"h-4 w-4\"\r\n\t\t}\r\n\t}\r\n});\r\n\r\nexport type TagCloseProps = React.ButtonHTMLAttributes<HTMLButtonElement> &\r\n\tTagCloseVariants &\r\n\tOmit<TagBaseVariants, \"size\"> & {\r\n\t\ticon?: LucideIcon;\r\n\t\ttag?: React.ElementType;\r\n\t};\r\n\r\nexport const TagClose = (props: TagCloseProps) => {\r\n\tconst { icon = X, size, tag: Tag = \"button\", className, ...rest } = props;\r\n\tconst styles = tagCloseStyles({ className, size, ...rest });\r\n\treturn (\r\n\t\t<Tag type=\"button\" className={styles} aria-label=\"Удалить\" size={size} {...rest}>\r\n\t\t\t<Icon icon={icon} className={tagIconStyles({ size })} />\r\n\t\t</Tag>\r\n\t);\r\n};\r\n\r\nTagClose.displayName = \"TagClose\";\r\n\r\nexport interface TagDividerVariants {\r\n\tstatus?: \"default\" | \"info\" | \"success\" | \"warning\" | \"error\";\r\n}\r\n\r\nconst tagDividerStyles = tv({\r\n\tbase: \"self-stretch border-l border-primary-border\",\r\n\tvariants: {\r\n\t\tstatus: {\r\n\t\t\tdefault: \"\",\r\n\t\t\tinfo: \"border-status-info-primary-border\",\r\n\t\t\tsuccess: \"border-status-success-primary-border\",\r\n\t\t\twarning: \"border-status-warning-primary-border\",\r\n\t\t\terror: \"border-status-error-primary-border\"\r\n\t\t}\r\n\t} satisfies VariantsConfig<TagDividerVariants>,\r\n\tdefaultVariants: {\r\n\t\tstatus: \"default\"\r\n\t}\r\n});\r\n\r\nexport type TagDividerProps = React.HTMLAttributes<HTMLDivElement> & TagDividerVariants;\r\n\r\nexport const TagDivider = (props: TagDividerProps) => {\r\n\tconst { status, className, ...rest } = props;\r\n\treturn <div className={tagDividerStyles({ status, className })} {...rest} />;\r\n};\r\n\r\nTagDivider.displayName = \"TagDivider\";\r\n\r\nexport interface TagWrapperVariants {\r\n\tsize?: \"sm\" | \"md\" | \"lg\";\r\n}\r\n\r\nconst tagWrapperStyles = tv({\r\n\tbase: \"inline-flex items-center rounded-sm\",\r\n\tvariants: {\r\n\t\tsize: {\r\n\t\t\tsm: \"h-5\",\r\n\t\t\tmd: \"h-6\",\r\n\t\t\tlg: \"h-7\"\r\n\t\t}\r\n\t} satisfies VariantsConfig<TagWrapperVariants>\r\n});\r\n\r\nexport type TagWrapperProps = React.HTMLAttributes<HTMLDivElement> & TagWrapperVariants;\r\n\r\nexport const TagWrapper = (props: TagWrapperProps) => {\r\n\tconst { children, className, size, ...rest } = props;\r\n\tconst styles = tagWrapperStyles({ className, size });\r\n\treturn (\r\n\t\t<div className={styles} {...rest}>\r\n\t\t\t{children}\r\n\t\t</div>\r\n\t);\r\n};\r\n\r\nexport type TagProps = PropsWithChildren<\r\n\tPick<TagBaseVariants, \"focus\" | \"size\"> &\r\n\t\tButtonProps & {\r\n\t\t\tonLabelClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;\r\n\t\t\tonClose?: (e: React.MouseEvent<HTMLButtonElement>) => void;\r\n\t\t\tclassName?: string;\r\n\t\t\tbuttonClassName?: string;\r\n\t\t}\r\n>;\r\n\r\nexport const Tag = (props: TagProps) => {\r\n\tconst {\r\n\t\tstartIcon: StartIcon,\r\n\t\tendIcon: EndIcon,\r\n\t\tchildren,\r\n\t\tonLabelClick,\r\n\t\tonClose,\r\n\t\tstatus,\r\n\t\tfocus,\r\n\t\tsize = \"md\",\r\n\t\tclassName,\r\n\t\tbuttonClassName,\r\n\t\t...rest\r\n\t} = props;\r\n\tconst hasClose = Boolean(onClose);\r\n\r\n\tconst startIconEl = StartIcon && <StartIcon className={tagIconStyles({ size })} />;\r\n\tconst endIconEl = EndIcon && <EndIcon className={tagIconStyles({ size })} />;\r\n\r\n\treturn (\r\n\t\t<TagWrapper size={size} className={className}>\r\n\t\t\t<TagButton\r\n\t\t\t\tposition={hasClose ? \"left\" : undefined}\r\n\t\t\t\tstatus={status}\r\n\t\t\t\tfocus={focus}\r\n\t\t\t\tsize={size}\r\n\t\t\t\tonClick={onLabelClick}\r\n\t\t\t\tclassName={buttonClassName}\r\n\t\t\t\t{...rest}\r\n\t\t\t>\r\n\t\t\t\t{startIconEl}\r\n\t\t\t\t{children}\r\n\t\t\t\t{endIconEl}\r\n\t\t\t</TagButton>\r\n\r\n\t\t\t{hasClose && (\r\n\t\t\t\t<>\r\n\t\t\t\t\t<TagDivider status={status} />\r\n\t\t\t\t\t<TagClose status={status} focus={focus} size={size} onClick={onClose} />\r\n\t\t\t\t</>\r\n\t\t\t)}\r\n\t\t</TagWrapper>\r\n\t);\r\n};\r\n\r\nTag.displayName = \"Tag\";\r\n"],"names":["tagBaseStyles","tv","TagBase","asChild","children","props","jsx","Slot","tagButtonStyles","TagButton","className","rest","Comp","styles","tagCloseStyles","tagIconStyles","TagClose","icon","X","size","Tag","Icon","tagDividerStyles","TagDivider","status","tagWrapperStyles","TagWrapper","StartIcon","EndIcon","onLabelClick","onClose","focus","buttonClassName","hasClose","startIconEl","endIconEl","jsxs","Fragment"],"mappings":"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"}
1
+ {"version":3,"file":"Tag-Cf6HftP-.js","sources":["../src/components/tag/Tag.tsx"],"sourcesContent":["import React, { PropsWithChildren } from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport { LucideIcon, X } from \"lucide-react\";\nimport { Icon } from \"../icon\";\nimport { ButtonProps } from \"../button/button/Button\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\n\nexport interface TagBaseVariants {\n\tstatus?: \"default\" | \"info\" | \"success\" | \"warning\" | \"error\";\n\tfocus?: \"low\" | \"high\";\n\tsize?: \"sm\" | \"md\" | \"lg\";\n}\n\nconst tagBaseStyles = tv({\n\tbase: \"inline-flex items-center justify-center overflow-hidden font-medium transition-colors\",\n\tvariants: {\n\t\tstatus: {\n\t\t\tdefault: \"border-primary-border bg-status-neutral-bg text-primary-fg hover:bg-status-neutral-bg-hover\",\n\t\t\tinfo: \"border-status-info-primary-border bg-status-info-bg text-status-info-fg hover:bg-status-info-bg-hover\",\n\t\t\tsuccess:\n\t\t\t\t\"border-status-success-primary-border bg-status-success-bg text-status-success-fg hover:bg-status-success-bg-hover\",\n\t\t\twarning:\n\t\t\t\t\"border-status-warning-primary-border bg-status-warning-bg text-status-warning-fg hover:bg-status-warning-bg-hover\",\n\t\t\terror: \"border-status-error-primary-border bg-status-error-bg text-status-error-fg hover:bg-status-error-bg-hover\"\n\t\t},\n\t\tfocus: {\n\t\t\tlow: \"\",\n\t\t\thigh: \"\"\n\t\t},\n\t\tsize: {\n\t\t\tsm: \"h-5 px-1.5 py-1 text-xs leading-none\",\n\t\t\tmd: \"h-6 px-1.5 py-1 text-sm leading-none\",\n\t\t\tlg: \"h-7 px-2 py-1 text-base leading-none\"\n\t\t}\n\t} satisfies VariantsConfig<TagBaseVariants>,\n\tdefaultVariants: {\n\t\tstatus: \"default\",\n\t\tfocus: \"low\",\n\t\tsize: \"md\"\n\t},\n\tcompoundVariants: [\n\t\t{\n\t\t\tstatus: [\"info\", \"success\", \"warning\", \"error\"],\n\t\t\tfocus: \"high\",\n\t\t\tclass: \"text-white\"\n\t\t},\n\t\t{\n\t\t\tstatus: \"default\",\n\t\t\tfocus: \"high\",\n\t\t\tclass: \"border-transparent bg-status-neutral text-primary-bg hover:bg-status-neutral-hover\"\n\t\t},\n\t\t{\n\t\t\tstatus: \"info\",\n\t\t\tfocus: \"high\",\n\t\t\tclass: \"border-transparent bg-status-info hover:bg-status-info-hover\"\n\t\t},\n\t\t{\n\t\t\tstatus: \"success\",\n\t\t\tfocus: \"high\",\n\t\t\tclass: \"border-transparent bg-status-success hover:bg-status-success-hover\"\n\t\t},\n\t\t{\n\t\t\tstatus: \"warning\",\n\t\t\tfocus: \"high\",\n\t\t\tclass: \"border-transparent bg-status-warning hover:bg-status-warning-hover\"\n\t\t},\n\t\t{\n\t\t\tstatus: \"error\",\n\t\t\tfocus: \"high\",\n\t\t\tclass: \"border-transparent bg-status-error hover:bg-status-error-hover\"\n\t\t}\n\t]\n});\n\nexport type TagBaseProps = React.HTMLAttributes<HTMLElement> &\n\tTagBaseVariants & {\n\t\tasChild?: boolean;\n\t};\n\nexport const TagBase = ({ asChild = false, children, ...props }: PropsWithChildren<TagBaseProps>) => {\n\tconst Comp = asChild ? Slot : \"span\";\n\treturn (\n\t\t<Comp className={tagBaseStyles(props)} {...props}>\n\t\t\t{children}\n\t\t</Comp>\n\t);\n};\n\nTagBase.displayName = \"TagBase\";\n\nexport interface TagButtonVariants {\n\tsize?: \"sm\" | \"md\" | \"lg\";\n\tclickable?: boolean;\n\tposition?: \"standalone\" | \"left\" | \"right\" | \"middle\";\n}\n\nconst tagButtonStyles = tv({\n\textend: tagBaseStyles,\n\tbase: \"z-10 flex cursor-pointer items-center justify-center whitespace-nowrap rounded-sm border focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-primary\",\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"gap-1\",\n\t\t\tmd: \"gap-1\",\n\t\t\tlg: \"gap-1.5\"\n\t\t},\n\t\tclickable: {\n\t\t\tfalse: \"cursor-default\"\n\t\t},\n\t\tposition: {\n\t\t\tstandalone: \"\",\n\t\t\tleft: \"rounded-r-none border-r-0\",\n\t\t\tright: \"rounded-l-none border-l-0\",\n\t\t\tmiddle: \"rounded-none border-l-0 border-r-0\"\n\t\t}\n\t} satisfies VariantsConfig<TagButtonVariants>,\n\tdefaultVariants: {\n\t\tclickable: true,\n\t\tposition: \"standalone\"\n\t}\n});\n\nexport type TagButtonProps = React.HTMLAttributes<HTMLElement> &\n\tTagButtonVariants &\n\tOmit<TagBaseVariants, \"size\"> & {\n\t\tasChild?: boolean;\n\t};\n\nexport const TagButton = (props: PropsWithChildren<TagButtonProps>) => {\n\tconst { asChild = false, children, className, ...rest } = props;\n\tconst Comp = asChild ? Slot : \"button\";\n\tconst styles = tagButtonStyles({ className, ...rest });\n\treturn (\n\t\t<Comp className={styles} {...rest}>\n\t\t\t{children}\n\t\t</Comp>\n\t);\n};\n\nTagButton.displayName = \"TagButton\";\n\nexport interface TagCloseVariants {\n\tsize?: \"sm\" | \"md\" | \"lg\";\n\tfocus?: \"low\" | \"high\";\n}\n\nconst tagCloseStyles = tv({\n\textend: tagBaseStyles,\n\tbase: \"aspect-square cursor-pointer rounded-l-none rounded-r-sm border border-l-0 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-primary\",\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"h-5 p-1 text-xs\",\n\t\t\tmd: \"h-6 p-1 text-sm\",\n\t\t\tlg: \"h-7 p-1.5 text-base\"\n\t\t},\n\t\tfocus: {\n\t\t\tlow: \"\",\n\t\t\thigh: \"\"\n\t\t}\n\t} satisfies VariantsConfig<TagCloseVariants>\n});\n\nconst tagIconStyles = tv({\n\tbase: \"aspect-square shrink-0\",\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"h-3 w-3\",\n\t\t\tmd: \"h-3.5 w-3.5\",\n\t\t\tlg: \"h-4 w-4\"\n\t\t}\n\t}\n});\n\nexport type TagCloseProps = React.ButtonHTMLAttributes<HTMLButtonElement> &\n\tTagCloseVariants &\n\tOmit<TagBaseVariants, \"size\"> & {\n\t\ticon?: LucideIcon;\n\t\ttag?: React.ElementType;\n\t};\n\nexport const TagClose = (props: TagCloseProps) => {\n\tconst { icon = X, size, tag: Tag = \"button\", className, ...rest } = props;\n\tconst styles = tagCloseStyles({ className, size, ...rest });\n\treturn (\n\t\t<Tag type=\"button\" className={styles} aria-label=\"Удалить\" size={size} {...rest}>\n\t\t\t<Icon icon={icon} className={tagIconStyles({ size })} />\n\t\t</Tag>\n\t);\n};\n\nTagClose.displayName = \"TagClose\";\n\nexport interface TagDividerVariants {\n\tstatus?: \"default\" | \"info\" | \"success\" | \"warning\" | \"error\";\n}\n\nconst tagDividerStyles = tv({\n\tbase: \"self-stretch border-l border-primary-border\",\n\tvariants: {\n\t\tstatus: {\n\t\t\tdefault: \"\",\n\t\t\tinfo: \"border-status-info-primary-border\",\n\t\t\tsuccess: \"border-status-success-primary-border\",\n\t\t\twarning: \"border-status-warning-primary-border\",\n\t\t\terror: \"border-status-error-primary-border\"\n\t\t}\n\t} satisfies VariantsConfig<TagDividerVariants>,\n\tdefaultVariants: {\n\t\tstatus: \"default\"\n\t}\n});\n\nexport type TagDividerProps = React.HTMLAttributes<HTMLDivElement> & TagDividerVariants;\n\nexport const TagDivider = (props: TagDividerProps) => {\n\tconst { status, className, ...rest } = props;\n\treturn <div className={tagDividerStyles({ status, className })} {...rest} />;\n};\n\nTagDivider.displayName = \"TagDivider\";\n\nexport interface TagWrapperVariants {\n\tsize?: \"sm\" | \"md\" | \"lg\";\n}\n\nconst tagWrapperStyles = tv({\n\tbase: \"inline-flex items-center rounded-sm\",\n\tvariants: {\n\t\tsize: {\n\t\t\tsm: \"h-5\",\n\t\t\tmd: \"h-6\",\n\t\t\tlg: \"h-7\"\n\t\t}\n\t} satisfies VariantsConfig<TagWrapperVariants>\n});\n\nexport type TagWrapperProps = React.HTMLAttributes<HTMLDivElement> & TagWrapperVariants;\n\nexport const TagWrapper = (props: TagWrapperProps) => {\n\tconst { children, className, size, ...rest } = props;\n\tconst styles = tagWrapperStyles({ className, size });\n\treturn (\n\t\t<div className={styles} {...rest}>\n\t\t\t{children}\n\t\t</div>\n\t);\n};\n\nexport type TagProps = PropsWithChildren<\n\tPick<TagBaseVariants, \"focus\" | \"size\"> &\n\t\tButtonProps & {\n\t\t\tonLabelClick?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n\t\t\tonClose?: (e: React.MouseEvent<HTMLButtonElement>) => void;\n\t\t\tclassName?: string;\n\t\t\tbuttonClassName?: string;\n\t\t}\n>;\n\nexport const Tag = (props: TagProps) => {\n\tconst {\n\t\tstartIcon: StartIcon,\n\t\tendIcon: EndIcon,\n\t\tchildren,\n\t\tonLabelClick,\n\t\tonClose,\n\t\tstatus,\n\t\tfocus,\n\t\tsize = \"md\",\n\t\tclassName,\n\t\tbuttonClassName,\n\t\t...rest\n\t} = props;\n\tconst hasClose = Boolean(onClose);\n\n\tconst startIconEl = StartIcon && <StartIcon className={tagIconStyles({ size })} />;\n\tconst endIconEl = EndIcon && <EndIcon className={tagIconStyles({ size })} />;\n\n\treturn (\n\t\t<TagWrapper size={size} className={className}>\n\t\t\t<TagButton\n\t\t\t\tposition={hasClose ? \"left\" : undefined}\n\t\t\t\tstatus={status}\n\t\t\t\tfocus={focus}\n\t\t\t\tsize={size}\n\t\t\t\tonClick={onLabelClick}\n\t\t\t\tclassName={buttonClassName}\n\t\t\t\t{...rest}\n\t\t\t>\n\t\t\t\t{startIconEl}\n\t\t\t\t{children}\n\t\t\t\t{endIconEl}\n\t\t\t</TagButton>\n\n\t\t\t{hasClose && (\n\t\t\t\t<>\n\t\t\t\t\t<TagDivider status={status} />\n\t\t\t\t\t<TagClose status={status} focus={focus} size={size} onClick={onClose} />\n\t\t\t\t</>\n\t\t\t)}\n\t\t</TagWrapper>\n\t);\n};\n\nTag.displayName = \"Tag\";\n"],"names":["tagBaseStyles","tv","TagBase","asChild","children","props","jsx","Slot","tagButtonStyles","TagButton","className","rest","Comp","styles","tagCloseStyles","tagIconStyles","TagClose","icon","X","size","Tag","Icon","tagDividerStyles","TagDivider","status","tagWrapperStyles","TagWrapper","StartIcon","EndIcon","onLabelClick","onClose","focus","buttonClassName","hasClose","startIconEl","endIconEl","jsxs","Fragment"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Text-DeBE8AKl.js","sources":["../src/components/text/Text.tsx"],"sourcesContent":["import { VariantsConfig } from \"@/lib/utils/variants\";\r\nimport React from \"react\";\r\nimport { tv } from \"tailwind-variants\";\r\n\r\ntype TextVariants = {\r\n\tsize?: \"xs\" | \"sm\";\r\n};\r\n\r\nconst textStyles = tv({\r\n\tbase: \"font-normal text-secondary-fg\",\r\n\tvariants: {\r\n\t\tsize: {\r\n\t\t\txs: \"text-xs\",\r\n\t\t\tsm: \"text-sm\"\r\n\t\t}\r\n\t} satisfies VariantsConfig<TextVariants>,\r\n\tdefaultVariants: {\r\n\t\tsize: \"sm\"\r\n\t}\r\n});\r\n\r\nexport type TextProps = React.HTMLAttributes<HTMLDivElement> & React.PropsWithChildren & TextVariants;\r\n\r\nexport const Text = React.forwardRef<HTMLDivElement, TextProps>(\r\n\t({ className, children, size = \"sm\", ...props }, ref) => {\r\n\t\treturn (\r\n\t\t\t<span ref={ref} className={textStyles({ class: className, size })} {...props}>\r\n\t\t\t\t{children}\r\n\t\t\t</span>\r\n\t\t);\r\n\t}\r\n);\r\n\r\nText.displayName = \"Text\";\r\n"],"names":["textStyles","tv","Text","React","className","children","size","props","ref","jsx"],"mappings":";;;AAQA,MAAMA,IAAaC,EAAG;AAAA,EACrB,MAAM;AAAA,EACN,UAAU;AAAA,IACT,MAAM;AAAA,MACL,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EAEN;AAAA,EACA,iBAAiB;AAAA,IAChB,MAAM;AAAA,EAAA;AAER,CAAC,GAIYC,IAAOC,EAAM;AAAA,EACzB,CAAC,EAAE,WAAAC,GAAW,UAAAC,GAAU,MAAAC,IAAO,MAAM,GAAGC,EAAM,GAAGC,MAE9C,gBAAAC,EAAA,QAAA,EAAK,KAAAD,GAAU,WAAWR,EAAW,EAAE,OAAOI,GAAW,MAAAE,EAAM,CAAA,GAAI,GAAGC,GACrE,UAAAF,EACF,CAAA;AAGH;AAEAH,EAAK,cAAc;"}
1
+ {"version":3,"file":"Text-DeBE8AKl.js","sources":["../src/components/text/Text.tsx"],"sourcesContent":["import { VariantsConfig } from \"@/lib/utils/variants\";\nimport React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\ntype TextVariants = {\n\tsize?: \"xs\" | \"sm\";\n};\n\nconst textStyles = tv({\n\tbase: \"font-normal text-secondary-fg\",\n\tvariants: {\n\t\tsize: {\n\t\t\txs: \"text-xs\",\n\t\t\tsm: \"text-sm\"\n\t\t}\n\t} satisfies VariantsConfig<TextVariants>,\n\tdefaultVariants: {\n\t\tsize: \"sm\"\n\t}\n});\n\nexport type TextProps = React.HTMLAttributes<HTMLDivElement> & React.PropsWithChildren & TextVariants;\n\nexport const Text = React.forwardRef<HTMLDivElement, TextProps>(\n\t({ className, children, size = \"sm\", ...props }, ref) => {\n\t\treturn (\n\t\t\t<span ref={ref} className={textStyles({ class: className, size })} {...props}>\n\t\t\t\t{children}\n\t\t\t</span>\n\t\t);\n\t}\n);\n\nText.displayName = \"Text\";\n"],"names":["textStyles","tv","Text","React","className","children","size","props","ref","jsx"],"mappings":";;;AAQA,MAAMA,IAAaC,EAAG;AAAA,EACrB,MAAM;AAAA,EACN,UAAU;AAAA,IACT,MAAM;AAAA,MACL,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EAEN;AAAA,EACA,iBAAiB;AAAA,IAChB,MAAM;AAAA,EAAA;AAER,CAAC,GAIYC,IAAOC,EAAM;AAAA,EACzB,CAAC,EAAE,WAAAC,GAAW,UAAAC,GAAU,MAAAC,IAAO,MAAM,GAAGC,EAAM,GAAGC,MAE9C,gBAAAC,EAAA,QAAA,EAAK,KAAAD,GAAU,WAAWR,EAAW,EAAE,OAAOI,GAAW,MAAAE,EAAM,CAAA,GAAI,GAAGC,GACrE,UAAAF,EACF,CAAA;AAGH;AAEAH,EAAK,cAAc;"}
@@ -1 +1 @@
1
- {"version":3,"file":"TextInput-CoL8nOyt.js","sources":["../node_modules/.pnpm/lucide-react@0.460.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/copy.js","../src/hooks/useControlledValue.ts","../src/hooks/useCopyAction.ts","../src/hooks/useAutofill.ts","../src/hooks/useInputWithActions.ts","../src/components/input/text-input/TextInput.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Copy = createLucideIcon(\"Copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.js.map\n","import { useCallback, useEffect, useRef, useState } from \"react\";\r\n\r\n/**\r\n * Хук для управления контролируемым и неконтролируемым состоянием\r\n */\r\nexport function useControlledValue(\r\n\tvalue: string | number | readonly string[] | undefined,\r\n\tdefaultValue: string | number | readonly string[] | undefined,\r\n\tonChange?: (value: string | null) => void\r\n) {\r\n\tconst [uncontrolledValue, setUncontrolledValue] = useState(\r\n\t\ttypeof defaultValue === \"string\" ? defaultValue : String(defaultValue ?? \"\")\r\n\t);\r\n\tconst inputRef = useRef<HTMLInputElement>(null);\r\n\r\n\t// Добавляем обработчик для отслеживания изменений в uncontrolled режиме\r\n\tuseEffect(() => {\r\n\t\tif (value !== undefined) return;\r\n\r\n\t\tconst input = inputRef.current;\r\n\t\tif (!input) return;\r\n\r\n\t\tconst handleInput = () => {\r\n\t\t\tsetUncontrolledValue(input.value);\r\n\t\t};\r\n\r\n\t\tinput.addEventListener(\"input\", handleInput);\r\n\t\treturn () => input.removeEventListener(\"input\", handleInput);\r\n\t}, [value, inputRef]);\r\n\r\n\tconst getCurrentValue = useCallback(() => {\r\n\t\tif (value !== undefined) return String(value);\r\n\t\treturn uncontrolledValue;\r\n\t}, [value, uncontrolledValue]);\r\n\r\n\tconst handleChange = useCallback(\r\n\t\t(e: React.ChangeEvent<HTMLInputElement>) => {\r\n\t\t\tonChange?.(e.target.value);\r\n\t\t},\r\n\t\t[onChange]\r\n\t);\r\n\r\n\treturn {\r\n\t\tinputRef,\r\n\t\tgetCurrentValue,\r\n\t\thandleChange,\r\n\t\tcurrentValue: getCurrentValue()\r\n\t};\r\n}\r\n","import { useCallback, useEffect, useState } from \"react\";\r\n\r\n/**\r\n * Хук для копирования содержимого в буфер обмена\r\n */\r\nexport function useCopyAction() {\r\n\tconst [hasCopied, setHasCopied] = useState(false);\r\n\r\n\t// Эффект для сброса статуса копирования\r\n\tuseEffect(() => {\r\n\t\tif (!hasCopied) return;\r\n\t\tconst timeout = setTimeout(() => {\r\n\t\t\tsetHasCopied(false);\r\n\t\t}, 2000);\r\n\t\treturn () => clearTimeout(timeout);\r\n\t}, [hasCopied]);\r\n\r\n\tconst handleCopy = useCallback((value: string) => {\r\n\t\tif (value) {\r\n\t\t\tnavigator.clipboard.writeText(value);\r\n\t\t\tsetHasCopied(true);\r\n\t\t}\r\n\t}, []);\r\n\r\n\treturn {\r\n\t\thasCopied,\r\n\t\thandleCopy\r\n\t};\r\n}\r\n","import { useEffect, useRef, useState } from \"react\";\r\n\r\n/**\r\n * Хук для определения состояния автозаполнения input'а\r\n */\r\nexport function useAutofill() {\r\n\tconst [isAutofilled, setIsAutofilled] = useState(false);\r\n\tconst inputRef = useRef<HTMLInputElement>(null);\r\n\r\n\tuseEffect(() => {\r\n\t\tconst input = inputRef.current;\r\n\t\tif (!input) return;\r\n\r\n\t\tconst checkAutofill = (element: Element): boolean => {\r\n\t\t\ttry {\r\n\t\t\t\treturn element.matches(\":-webkit-autofill\");\r\n\t\t\t} catch {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\tconst updateAutofillState = () => {\r\n\t\t\tconst autofilled = checkAutofill(input);\r\n\t\t\tsetIsAutofilled(autofilled);\r\n\t\t};\r\n\r\n\t\tinput.addEventListener(\"input\", updateAutofillState);\r\n\r\n\t\tlet intervalCounter = 0;\r\n\t\tconst intervalTime = 25;\r\n\t\t// Максимальное время ожидания появления autofill, в ms\r\n\t\tconst intervalTimeLimit = 1000;\r\n\r\n\t\tconst interval = setInterval(() => {\r\n\t\t\tintervalCounter += intervalTime;\r\n\t\t\tif (intervalCounter > intervalTimeLimit) {\r\n\t\t\t\tclearInterval(interval);\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif (checkAutofill(input)) {\r\n\t\t\t\tsetIsAutofilled(true);\r\n\t\t\t\tclearInterval(interval);\r\n\t\t\t}\r\n\t\t}, intervalTime);\r\n\r\n\t\tupdateAutofillState();\r\n\r\n\t\treturn () => {\r\n\t\t\tclearInterval(interval);\r\n\t\t\tinput.removeEventListener(\"input\", updateAutofillState);\r\n\t\t};\r\n\t}, []);\r\n\r\n\treturn {\r\n\t\tisAutofilled,\r\n\t\tinputRef\r\n\t};\r\n}\r\n","import { useCallback, useMemo } from \"react\";\r\nimport { useControlledValue } from \"./useControlledValue\";\r\nimport { useCopyAction } from \"./useCopyAction\";\r\nimport { useAutofill } from \"./useAutofill\";\r\n\r\nexport interface UseInputWithActionsOptions {\r\n\t/** Значение input (для контролируемого режима) */\r\n\tvalue?: string | number | readonly string[];\r\n\t/** Значение по умолчанию (для неконтролируемого режима) */\r\n\tdefaultValue?: string | number | readonly string[];\r\n\t/** Колбэк на изменение значения */\r\n\tonChange?: (value: string | null) => void;\r\n\t/** Флаг только для чтения */\r\n\treadOnly?: boolean;\r\n\t/** Флаг отключения */\r\n\tdisabled?: boolean;\r\n\t/** Флаг для отображения кнопки очистки */\r\n\tshowClearIcon?: boolean;\r\n\t/** Флаг для отображения кнопки копирования */\r\n\tshowCopyIcon?: boolean;\r\n}\r\n\r\n/**\r\n * Общий хук для input с полным функционалом копирования и очистки\r\n */\r\nexport function useInputWithActions({\r\n\tvalue,\r\n\tdefaultValue,\r\n\tonChange,\r\n\treadOnly,\r\n\tdisabled,\r\n\tshowClearIcon = false,\r\n\tshowCopyIcon = false\r\n}: UseInputWithActionsOptions) {\r\n\tconst controlledValue = useControlledValue(value, defaultValue, onChange);\r\n\tconst copyAction = useCopyAction();\r\n\tconst { isAutofilled } = useAutofill();\r\n\r\n\tconst isEditable = useMemo(() => {\r\n\t\treturn !readOnly && !disabled;\r\n\t}, [readOnly, disabled]);\r\n\r\n\tconst handleClear = useCallback(() => {\r\n\t\tif (value !== undefined) {\r\n\t\t\t// Controlled mode\r\n\t\t\tonChange?.(\"\");\r\n\t\t} else {\r\n\t\t\t// Uncontrolled mode\r\n\t\t\tif (controlledValue.inputRef.current) {\r\n\t\t\t\tcontrolledValue.inputRef.current.value = \"\";\r\n\t\t\t\tcontrolledValue.inputRef.current.dispatchEvent(new Event(\"input\", { bubbles: true }));\r\n\t\t\t}\r\n\t\t}\r\n\t}, [onChange, value, controlledValue.inputRef]);\r\n\r\n\tconst handleCopyValue = useCallback(() => {\r\n\t\tcopyAction.handleCopy(String(controlledValue.currentValue));\r\n\t}, [copyAction.handleCopy, controlledValue.currentValue]);\r\n\r\n\tconst shouldShowClearIcon = showClearIcon && isEditable && controlledValue.currentValue;\r\n\tconst shouldShowCopyIcon = showCopyIcon && controlledValue.currentValue;\r\n\r\n\treturn {\r\n\t\t// Значения и состояние\r\n\t\tcurrentValue: controlledValue.currentValue,\r\n\t\tinputRef: controlledValue.inputRef,\r\n\t\tisEditable,\r\n\r\n\t\t// Обработчики\r\n\t\thandleChange: controlledValue.handleChange,\r\n\t\thandleClear,\r\n\t\thandleCopy: handleCopyValue,\r\n\r\n\t\t// Состояние копирования\r\n\t\thasCopied: copyAction.hasCopied,\r\n\r\n\t\t// Состояние автозаполнения\r\n\t\tisAutofilled,\r\n\r\n\t\t// Флаги видимости кнопок\r\n\t\tshouldShowClearIcon,\r\n\t\tshouldShowCopyIcon\r\n\t};\r\n}\r\n","import React, { HTMLAttributes } from \"react\";\r\nimport { useMergeRefs } from \"@/hooks/useMergeRefs\";\r\nimport { useInputWithActions } from \"@/hooks/useInputWithActions\";\r\nimport { InputGroup, InputGroupInput, InputGroupButton, InputGroupText } from \"../input-group/InputGroup\";\r\nimport { CircleX, Copy, Check } from \"lucide-react\";\r\nimport { tv } from \"tailwind-variants\";\r\nimport { InputProps } from \"../input/Input\";\r\n\r\nconst textInputStyles = tv({\r\n\tbase: \"\",\r\n\tslots: {\r\n\t\taction: \"hidden group-focus-within/input-group:block group-hover/input-group:block\",\r\n\t\tstartIcon: \"border-r-0! pr-0 text-muted\",\r\n\t\tendIcon: \"border-l-0 pl-0 text-muted\",\r\n\t\tinput: \"\"\r\n\t},\r\n\tvariants: {\r\n\t\thasStartIcon: { true: { input: \"pl-2\" } }\r\n\t}\r\n});\r\n\r\nexport interface TextInputProps\r\n\textends Omit<InputProps, \"onChange\">,\r\n\t\tOmit<HTMLAttributes<HTMLInputElement>, \"onChange\"> {\r\n\t/** Иконка, отображаемая в начале текстового поля */\r\n\tstartIcon?: React.ReactNode;\r\n\t/** Иконка, отображаемая в конце текстового поля */\r\n\tendIcon?: React.ReactNode;\r\n\t/** Флаг для отображения кнопки очистки значения */\r\n\tshowClearIcon?: boolean;\r\n\t/** Флаг для отображения кнопки копирования значения */\r\n\tshowCopyIcon?: boolean;\r\n\t/** Колбэк на изменение значения */\r\n\tonChange?: (value: string | null) => void;\r\n}\r\n\r\n/**\r\n * Компонент текстового поля ввода с поддержкой иконок и дополнительных действий.\r\n */\r\nexport const TextInput = React.forwardRef<HTMLInputElement, TextInputProps>(\r\n\t(\r\n\t\t{\r\n\t\t\tstartIcon,\r\n\t\t\tendIcon,\r\n\t\t\tshowClearIcon,\r\n\t\t\tshowCopyIcon,\r\n\t\t\tvalue,\r\n\t\t\tdefaultValue,\r\n\t\t\tonChange,\r\n\t\t\treadOnly,\r\n\t\t\tdisabled,\r\n\t\t\terror,\r\n\t\t\tclassName,\r\n\t\t\t...props\r\n\t\t},\r\n\t\tref\r\n\t) => {\r\n\t\tconst styles = textInputStyles();\r\n\r\n\t\tconst inputActions = useInputWithActions({\r\n\t\t\tvalue,\r\n\t\t\tdefaultValue,\r\n\t\t\tonChange,\r\n\t\t\treadOnly,\r\n\t\t\tdisabled,\r\n\t\t\tshowClearIcon,\r\n\t\t\tshowCopyIcon\r\n\t\t});\r\n\r\n\t\tconst mergedRef = useMergeRefs(ref, inputActions.inputRef);\r\n\r\n\t\treturn (\r\n\t\t\t<InputGroup className={styles.base({ className })}>\r\n\t\t\t\t{startIcon && <InputGroupText className={styles.startIcon()}>{startIcon}</InputGroupText>}\r\n\r\n\t\t\t\t<InputGroupInput\r\n\t\t\t\t\tref={mergedRef}\r\n\t\t\t\t\tvalue={value}\r\n\t\t\t\t\tdefaultValue={defaultValue}\r\n\t\t\t\t\tonChange={inputActions.handleChange}\r\n\t\t\t\t\treadOnly={readOnly}\r\n\t\t\t\t\tdisabled={disabled}\r\n\t\t\t\t\terror={error}\r\n\t\t\t\t\tclassName={styles.input({ hasStartIcon: !!startIcon })}\r\n\t\t\t\t\t{...props}\r\n\t\t\t\t/>\r\n\r\n\t\t\t\t{inputActions.shouldShowClearIcon && (\r\n\t\t\t\t\t<InputGroupButton\r\n\t\t\t\t\t\ticon={CircleX}\r\n\t\t\t\t\t\tonClick={inputActions.handleClear}\r\n\t\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t\tclassName={styles.action()}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\r\n\t\t\t\t{inputActions.shouldShowCopyIcon && (\r\n\t\t\t\t\t<InputGroupButton\r\n\t\t\t\t\t\ticon={inputActions.hasCopied ? Check : Copy}\r\n\t\t\t\t\t\tonClick={inputActions.handleCopy}\r\n\t\t\t\t\t\ttype=\"button\"\r\n\t\t\t\t\t\tclassName={styles.action()}\r\n\t\t\t\t\t/>\r\n\t\t\t\t)}\r\n\r\n\t\t\t\t{endIcon && <InputGroupText className={styles.endIcon()}>{endIcon}</InputGroupText>}\r\n\t\t\t</InputGroup>\r\n\t\t);\r\n\t}\r\n);\r\n\r\nTextInput.displayName = \"TextInput\";\r\n\r\nexport default TextInput;\r\n"],"names":["Copy","createLucideIcon","useControlledValue","value","defaultValue","onChange","uncontrolledValue","setUncontrolledValue","useState","inputRef","useRef","useEffect","input","handleInput","getCurrentValue","useCallback","handleChange","e","useCopyAction","hasCopied","setHasCopied","timeout","handleCopy","useAutofill","isAutofilled","setIsAutofilled","checkAutofill","element","updateAutofillState","autofilled","intervalCounter","intervalTime","intervalTimeLimit","interval","useInputWithActions","readOnly","disabled","showClearIcon","showCopyIcon","controlledValue","copyAction","isEditable","useMemo","handleClear","handleCopyValue","shouldShowClearIcon","shouldShowCopyIcon","textInputStyles","tv","TextInput","React","startIcon","endIcon","error","className","props","ref","styles","inputActions","mergedRef","useMergeRefs","jsxs","InputGroup","InputGroupText","jsx","InputGroupInput","InputGroupButton","CircleX","Check"],"mappings":"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","x_google_ignoreList":[0]}
1
+ {"version":3,"file":"TextInput-CoL8nOyt.js","sources":["../node_modules/.pnpm/lucide-react@0.460.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/copy.js","../src/hooks/useControlledValue.ts","../src/hooks/useCopyAction.ts","../src/hooks/useAutofill.ts","../src/hooks/useInputWithActions.ts","../src/components/input/text-input/TextInput.tsx"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst Copy = createLucideIcon(\"Copy\", [\n [\"rect\", { width: \"14\", height: \"14\", x: \"8\", y: \"8\", rx: \"2\", ry: \"2\", key: \"17jyea\" }],\n [\"path\", { d: \"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\", key: \"zix9uf\" }]\n]);\n\nexport { Copy as default };\n//# sourceMappingURL=copy.js.map\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Хук для управления контролируемым и неконтролируемым состоянием\n */\nexport function useControlledValue(\n\tvalue: string | number | readonly string[] | undefined,\n\tdefaultValue: string | number | readonly string[] | undefined,\n\tonChange?: (value: string | null) => void\n) {\n\tconst [uncontrolledValue, setUncontrolledValue] = useState(\n\t\ttypeof defaultValue === \"string\" ? defaultValue : String(defaultValue ?? \"\")\n\t);\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\n\t// Добавляем обработчик для отслеживания изменений в uncontrolled режиме\n\tuseEffect(() => {\n\t\tif (value !== undefined) return;\n\n\t\tconst input = inputRef.current;\n\t\tif (!input) return;\n\n\t\tconst handleInput = () => {\n\t\t\tsetUncontrolledValue(input.value);\n\t\t};\n\n\t\tinput.addEventListener(\"input\", handleInput);\n\t\treturn () => input.removeEventListener(\"input\", handleInput);\n\t}, [value, inputRef]);\n\n\tconst getCurrentValue = useCallback(() => {\n\t\tif (value !== undefined) return String(value);\n\t\treturn uncontrolledValue;\n\t}, [value, uncontrolledValue]);\n\n\tconst handleChange = useCallback(\n\t\t(e: React.ChangeEvent<HTMLInputElement>) => {\n\t\t\tonChange?.(e.target.value);\n\t\t},\n\t\t[onChange]\n\t);\n\n\treturn {\n\t\tinputRef,\n\t\tgetCurrentValue,\n\t\thandleChange,\n\t\tcurrentValue: getCurrentValue()\n\t};\n}\n","import { useCallback, useEffect, useState } from \"react\";\n\n/**\n * Хук для копирования содержимого в буфер обмена\n */\nexport function useCopyAction() {\n\tconst [hasCopied, setHasCopied] = useState(false);\n\n\t// Эффект для сброса статуса копирования\n\tuseEffect(() => {\n\t\tif (!hasCopied) return;\n\t\tconst timeout = setTimeout(() => {\n\t\t\tsetHasCopied(false);\n\t\t}, 2000);\n\t\treturn () => clearTimeout(timeout);\n\t}, [hasCopied]);\n\n\tconst handleCopy = useCallback((value: string) => {\n\t\tif (value) {\n\t\t\tnavigator.clipboard.writeText(value);\n\t\t\tsetHasCopied(true);\n\t\t}\n\t}, []);\n\n\treturn {\n\t\thasCopied,\n\t\thandleCopy\n\t};\n}\n","import { useEffect, useRef, useState } from \"react\";\n\n/**\n * Хук для определения состояния автозаполнения input'а\n */\nexport function useAutofill() {\n\tconst [isAutofilled, setIsAutofilled] = useState(false);\n\tconst inputRef = useRef<HTMLInputElement>(null);\n\n\tuseEffect(() => {\n\t\tconst input = inputRef.current;\n\t\tif (!input) return;\n\n\t\tconst checkAutofill = (element: Element): boolean => {\n\t\t\ttry {\n\t\t\t\treturn element.matches(\":-webkit-autofill\");\n\t\t\t} catch {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\n\t\tconst updateAutofillState = () => {\n\t\t\tconst autofilled = checkAutofill(input);\n\t\t\tsetIsAutofilled(autofilled);\n\t\t};\n\n\t\tinput.addEventListener(\"input\", updateAutofillState);\n\n\t\tlet intervalCounter = 0;\n\t\tconst intervalTime = 25;\n\t\t// Максимальное время ожидания появления autofill, в ms\n\t\tconst intervalTimeLimit = 1000;\n\n\t\tconst interval = setInterval(() => {\n\t\t\tintervalCounter += intervalTime;\n\t\t\tif (intervalCounter > intervalTimeLimit) {\n\t\t\t\tclearInterval(interval);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (checkAutofill(input)) {\n\t\t\t\tsetIsAutofilled(true);\n\t\t\t\tclearInterval(interval);\n\t\t\t}\n\t\t}, intervalTime);\n\n\t\tupdateAutofillState();\n\n\t\treturn () => {\n\t\t\tclearInterval(interval);\n\t\t\tinput.removeEventListener(\"input\", updateAutofillState);\n\t\t};\n\t}, []);\n\n\treturn {\n\t\tisAutofilled,\n\t\tinputRef\n\t};\n}\n","import { useCallback, useMemo } from \"react\";\nimport { useControlledValue } from \"./useControlledValue\";\nimport { useCopyAction } from \"./useCopyAction\";\nimport { useAutofill } from \"./useAutofill\";\n\nexport interface UseInputWithActionsOptions {\n\t/** Значение input (для контролируемого режима) */\n\tvalue?: string | number | readonly string[];\n\t/** Значение по умолчанию (для неконтролируемого режима) */\n\tdefaultValue?: string | number | readonly string[];\n\t/** Колбэк на изменение значения */\n\tonChange?: (value: string | null) => void;\n\t/** Флаг только для чтения */\n\treadOnly?: boolean;\n\t/** Флаг отключения */\n\tdisabled?: boolean;\n\t/** Флаг для отображения кнопки очистки */\n\tshowClearIcon?: boolean;\n\t/** Флаг для отображения кнопки копирования */\n\tshowCopyIcon?: boolean;\n}\n\n/**\n * Общий хук для input с полным функционалом копирования и очистки\n */\nexport function useInputWithActions({\n\tvalue,\n\tdefaultValue,\n\tonChange,\n\treadOnly,\n\tdisabled,\n\tshowClearIcon = false,\n\tshowCopyIcon = false\n}: UseInputWithActionsOptions) {\n\tconst controlledValue = useControlledValue(value, defaultValue, onChange);\n\tconst copyAction = useCopyAction();\n\tconst { isAutofilled } = useAutofill();\n\n\tconst isEditable = useMemo(() => {\n\t\treturn !readOnly && !disabled;\n\t}, [readOnly, disabled]);\n\n\tconst handleClear = useCallback(() => {\n\t\tif (value !== undefined) {\n\t\t\t// Controlled mode\n\t\t\tonChange?.(\"\");\n\t\t} else {\n\t\t\t// Uncontrolled mode\n\t\t\tif (controlledValue.inputRef.current) {\n\t\t\t\tcontrolledValue.inputRef.current.value = \"\";\n\t\t\t\tcontrolledValue.inputRef.current.dispatchEvent(new Event(\"input\", { bubbles: true }));\n\t\t\t}\n\t\t}\n\t}, [onChange, value, controlledValue.inputRef]);\n\n\tconst handleCopyValue = useCallback(() => {\n\t\tcopyAction.handleCopy(String(controlledValue.currentValue));\n\t}, [copyAction.handleCopy, controlledValue.currentValue]);\n\n\tconst shouldShowClearIcon = showClearIcon && isEditable && controlledValue.currentValue;\n\tconst shouldShowCopyIcon = showCopyIcon && controlledValue.currentValue;\n\n\treturn {\n\t\t// Значения и состояние\n\t\tcurrentValue: controlledValue.currentValue,\n\t\tinputRef: controlledValue.inputRef,\n\t\tisEditable,\n\n\t\t// Обработчики\n\t\thandleChange: controlledValue.handleChange,\n\t\thandleClear,\n\t\thandleCopy: handleCopyValue,\n\n\t\t// Состояние копирования\n\t\thasCopied: copyAction.hasCopied,\n\n\t\t// Состояние автозаполнения\n\t\tisAutofilled,\n\n\t\t// Флаги видимости кнопок\n\t\tshouldShowClearIcon,\n\t\tshouldShowCopyIcon\n\t};\n}\n","import React, { HTMLAttributes } from \"react\";\nimport { useMergeRefs } from \"@/hooks/useMergeRefs\";\nimport { useInputWithActions } from \"@/hooks/useInputWithActions\";\nimport { InputGroup, InputGroupInput, InputGroupButton, InputGroupText } from \"../input-group/InputGroup\";\nimport { CircleX, Copy, Check } from \"lucide-react\";\nimport { tv } from \"tailwind-variants\";\nimport { InputProps } from \"../input/Input\";\n\nconst textInputStyles = tv({\n\tbase: \"\",\n\tslots: {\n\t\taction: \"hidden group-focus-within/input-group:block group-hover/input-group:block\",\n\t\tstartIcon: \"border-r-0! pr-0 text-muted\",\n\t\tendIcon: \"border-l-0 pl-0 text-muted\",\n\t\tinput: \"\"\n\t},\n\tvariants: {\n\t\thasStartIcon: { true: { input: \"pl-2\" } }\n\t}\n});\n\nexport interface TextInputProps\n\textends Omit<InputProps, \"onChange\">,\n\t\tOmit<HTMLAttributes<HTMLInputElement>, \"onChange\"> {\n\t/** Иконка, отображаемая в начале текстового поля */\n\tstartIcon?: React.ReactNode;\n\t/** Иконка, отображаемая в конце текстового поля */\n\tendIcon?: React.ReactNode;\n\t/** Флаг для отображения кнопки очистки значения */\n\tshowClearIcon?: boolean;\n\t/** Флаг для отображения кнопки копирования значения */\n\tshowCopyIcon?: boolean;\n\t/** Колбэк на изменение значения */\n\tonChange?: (value: string | null) => void;\n}\n\n/**\n * Компонент текстового поля ввода с поддержкой иконок и дополнительных действий.\n */\nexport const TextInput = React.forwardRef<HTMLInputElement, TextInputProps>(\n\t(\n\t\t{\n\t\t\tstartIcon,\n\t\t\tendIcon,\n\t\t\tshowClearIcon,\n\t\t\tshowCopyIcon,\n\t\t\tvalue,\n\t\t\tdefaultValue,\n\t\t\tonChange,\n\t\t\treadOnly,\n\t\t\tdisabled,\n\t\t\terror,\n\t\t\tclassName,\n\t\t\t...props\n\t\t},\n\t\tref\n\t) => {\n\t\tconst styles = textInputStyles();\n\n\t\tconst inputActions = useInputWithActions({\n\t\t\tvalue,\n\t\t\tdefaultValue,\n\t\t\tonChange,\n\t\t\treadOnly,\n\t\t\tdisabled,\n\t\t\tshowClearIcon,\n\t\t\tshowCopyIcon\n\t\t});\n\n\t\tconst mergedRef = useMergeRefs(ref, inputActions.inputRef);\n\n\t\treturn (\n\t\t\t<InputGroup className={styles.base({ className })}>\n\t\t\t\t{startIcon && <InputGroupText className={styles.startIcon()}>{startIcon}</InputGroupText>}\n\n\t\t\t\t<InputGroupInput\n\t\t\t\t\tref={mergedRef}\n\t\t\t\t\tvalue={value}\n\t\t\t\t\tdefaultValue={defaultValue}\n\t\t\t\t\tonChange={inputActions.handleChange}\n\t\t\t\t\treadOnly={readOnly}\n\t\t\t\t\tdisabled={disabled}\n\t\t\t\t\terror={error}\n\t\t\t\t\tclassName={styles.input({ hasStartIcon: !!startIcon })}\n\t\t\t\t\t{...props}\n\t\t\t\t/>\n\n\t\t\t\t{inputActions.shouldShowClearIcon && (\n\t\t\t\t\t<InputGroupButton\n\t\t\t\t\t\ticon={CircleX}\n\t\t\t\t\t\tonClick={inputActions.handleClear}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName={styles.action()}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t\t{inputActions.shouldShowCopyIcon && (\n\t\t\t\t\t<InputGroupButton\n\t\t\t\t\t\ticon={inputActions.hasCopied ? Check : Copy}\n\t\t\t\t\t\tonClick={inputActions.handleCopy}\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName={styles.action()}\n\t\t\t\t\t/>\n\t\t\t\t)}\n\n\t\t\t\t{endIcon && <InputGroupText className={styles.endIcon()}>{endIcon}</InputGroupText>}\n\t\t\t</InputGroup>\n\t\t);\n\t}\n);\n\nTextInput.displayName = \"TextInput\";\n\nexport default TextInput;\n"],"names":["Copy","createLucideIcon","useControlledValue","value","defaultValue","onChange","uncontrolledValue","setUncontrolledValue","useState","inputRef","useRef","useEffect","input","handleInput","getCurrentValue","useCallback","handleChange","e","useCopyAction","hasCopied","setHasCopied","timeout","handleCopy","useAutofill","isAutofilled","setIsAutofilled","checkAutofill","element","updateAutofillState","autofilled","intervalCounter","intervalTime","intervalTimeLimit","interval","useInputWithActions","readOnly","disabled","showClearIcon","showCopyIcon","controlledValue","copyAction","isEditable","useMemo","handleClear","handleCopyValue","shouldShowClearIcon","shouldShowCopyIcon","textInputStyles","tv","TextInput","React","startIcon","endIcon","error","className","props","ref","styles","inputActions","mergedRef","useMergeRefs","jsxs","InputGroup","InputGroupText","jsx","InputGroupInput","InputGroupButton","CircleX","Check"],"mappings":"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","x_google_ignoreList":[0]}
@@ -1 +1 @@
1
- {"version":3,"file":"TextOverflowTooltip-XPDdO9Dz.js","sources":["../src/lib/utils/dom.ts","../src/components/overflow-tooltip/useOverflowTooltip.ts","../src/components/overflow-tooltip/OverflowTooltip.tsx","../src/components/overflow-tooltip/TextOverflowTooltip.tsx"],"sourcesContent":["/**\n * Проверяет, переполнен ли элемент (дочерние элементы выходят за пределы родительского элемента)\n * @param element - HTML элемент для проверки\n * @returns true, если элемент переполнен по ширине или высоте\n *\n * @example\n * // подсказку показываем только там, где текст обрезан\n * const truncated = isElementOverflowing(labelRef.current);\n */\nexport const isElementOverflowing = (element: HTMLElement): boolean => {\n\treturn element.scrollWidth > element.offsetWidth || element.scrollHeight > element.offsetHeight;\n};\n\n/**\n * Canvas для измерения текста переиспользуется: на каждый вызов создавать его расточительно.\n *\n * Контекст один на все поля страницы, и это безопасно ровно до тех пор, пока каждое\n * измерение выставляет **все** влияющие на ширину свойства. Условное присваивание оставило бы\n * настройку от предыдущего поля: соседняя таблица со своим `letter-spacing` мерила бы текст\n * чужим трекингом. Поэтому свойства ниже пишутся всегда, а сам canvas остаётся приватным\n * для этого модуля — иначе инвариант незаметно нарушит следующий пользователь.\n */\nlet measureContext: CanvasRenderingContext2D | null | undefined;\n\nconst getMeasureContext = () => {\n\tif (measureContext === undefined) measureContext = document.createElement(\"canvas\").getContext(\"2d\");\n\treturn measureContext;\n};\n\n/**\n * Ставит каретку в `input`/`textarea` по горизонтальной координате указателя (`clientX`).\n *\n * Нужно там, где поле появляется по клику уже после самого клика — например, при переходе\n * ячейки таблицы в режим редактирования по двойному щелчку: без этого каретка встаёт\n * в начало или конец, а не туда, куда целился пользователь.\n *\n * `caretPositionFromPoint` / `caretRangeFromPoint` здесь бесполезны: содержимое `input`\n * не является частью DOM-дерева, и Range/Selection API до него не достаёт — вернётся сам\n * элемент, а не позиция в тексте. Поэтому индекс считается вручную: текст измеряется\n * на offscreen canvas тем же шрифтом, и выбирается ближайшая к точке граница символа.\n * Ширины префиксов монотонно растут, так что перебор обрывается, как только начал удаляться\n * от цели.\n *\n * Учитывается только горизонталь, поэтому для многострочного текста функция не годится —\n * там нужен `placeCaretAtClientPoint` по `contenteditable`.\n *\n * Возвращает `false`, если поставить каретку не удалось (поле пустое, тип поля не поддерживает\n * выделение или canvas недоступен) — вызывающему коду в этом случае стоит оставить поведение\n * по умолчанию.\n *\n * @example\n * // координата запоминается на dblclick, применяется, когда поле получило фокус\n * <input\n * autoFocus\n * onFocus={(event) => {\n * const input = event.currentTarget;\n * if (!placeCaretAtPoint(input, caretX)) placeCaretAtEnd(input);\n * }}\n * />\n */\nexport const placeCaretAtPoint = (element: HTMLInputElement | HTMLTextAreaElement, clientX: number): boolean => {\n\tconst value = element.value;\n\tif (!value) return false;\n\n\t// У `type=number|email|date|time|color` выделения нет, а `setSelectionRange` на них кидает\n\t// `InvalidStateError`. Тип полей задаёт прикладной код, поэтому проверяем, а не полагаемся.\n\tif (element.selectionStart === null) return false;\n\n\tconst context = getMeasureContext();\n\tif (!context) return false;\n\n\tconst style = window.getComputedStyle(element);\n\tcontext.font = `${style.fontStyle} ${style.fontWeight} ${style.fontSize} ${style.fontFamily}`;\n\t// `letterSpacing` у canvas принимает только длину: `normal` из вычисленных стилей его сломает.\n\t// Пишется на каждом вызове — иначе значение утечёт в следующее поле, см. `measureContext`.\n\tif (\"letterSpacing\" in context) {\n\t\tcontext.letterSpacing = style.letterSpacing.endsWith(\"px\") ? style.letterSpacing : \"0px\";\n\t}\n\n\tconst rect = element.getBoundingClientRect();\n\tconst borderLeft = parseFloat(style.borderLeftWidth) || 0;\n\tconst borderRight = parseFloat(style.borderRightWidth) || 0;\n\tconst paddingLeft = parseFloat(style.paddingLeft) || 0;\n\tconst paddingRight = parseFloat(style.paddingRight) || 0;\n\tconst contentLeft = rect.left + borderLeft + paddingLeft;\n\tconst contentWidth = rect.width - borderLeft - borderRight - paddingLeft - paddingRight;\n\n\t// Текст короче поля прижимается по `text-align`, и отсчитывать позицию от левого края\n\t// нельзя — у выровненного вправо поля это промах на всю свободную ширину.\n\tconst slack = contentWidth - context.measureText(value).width;\n\tlet originX = contentLeft - element.scrollLeft;\n\tif (slack > 0) {\n\t\tif (style.textAlign === \"right\" || style.textAlign === \"end\") originX += slack;\n\t\telse if (style.textAlign === \"center\") originX += slack / 2;\n\t}\n\n\tconst targetX = clientX - originX;\n\tlet bestIndex = 0;\n\tlet bestDistance = Infinity;\n\tfor (let index = 0; index <= value.length; index++) {\n\t\tconst distance = Math.abs(context.measureText(value.slice(0, index)).width - targetX);\n\t\tif (distance > bestDistance) break;\n\t\tbestDistance = distance;\n\t\tbestIndex = index;\n\t}\n\n\telement.setSelectionRange(bestIndex, bestIndex);\n\treturn true;\n};\n\n/**\n * Ставит каретку в `contenteditable` по точке указателя.\n *\n * В отличие от `input`, текст здесь — обычные узлы DOM, поэтому измерять ничего не нужно:\n * браузер сам отдаёт позицию по координатам. Работает и с переносами, так что это тот случай,\n * когда многострочная правка делается редактируемым `div`, а не `textarea`.\n *\n * Возвращает `false`, если точка не попала в текст элемента, — вызывающему коду стоит\n * поставить каретку в конец через `placeCaretAtEnd`.\n *\n * @example\n * const editor = event.currentTarget;\n * if (!placeCaretAtClientPoint(editor, event.clientX, event.clientY)) placeCaretAtEnd(editor);\n */\nexport const placeCaretAtClientPoint = (element: HTMLElement, clientX: number, clientY: number): boolean => {\n\tconst selection = window.getSelection();\n\tif (!selection) return false;\n\n\tconst range = caretRangeAtPoint(clientX, clientY);\n\t// Точка могла прийтись на отступ ячейки или на соседний узел: чужую позицию не ставим.\n\tif (!range || !element.contains(range.startContainer)) return false;\n\n\tselection.removeAllRanges();\n\tselection.addRange(range);\n\treturn true;\n};\n\n/**\n * Оба способа спросить у браузера позицию каретки по координатам — объявлены здесь сами.\n *\n * `caretPositionFromPoint` — стандартный, но в `lib.dom` TS 5.6 его ещё нет.\n * `caretRangeFromPoint` — легаси WebKit, в `lib.dom` он помечен `@deprecated`; берётся\n * только фолбэком для Safari до 17.4, где стандартного метода ещё не было. Объявление\n * собрано в одном месте намеренно: обращение идёт к нему, а не к устаревшему члену `Document`,\n * и причина использования легаси видна рядом, а не прячется за подавленной подсказкой.\n */\ntype DocumentWithCaretApi = Document & {\n\tcaretPositionFromPoint?: (x: number, y: number) => { offsetNode: Node; offset: number } | null;\n\tcaretRangeFromPoint?: (x: number, y: number) => Range | null;\n};\n\nconst caretRangeAtPoint = (clientX: number, clientY: number): Range | null => {\n\tconst doc = document as DocumentWithCaretApi;\n\n\tif (doc.caretPositionFromPoint) {\n\t\tconst position = doc.caretPositionFromPoint(clientX, clientY);\n\t\tif (!position) return null;\n\t\tconst range = document.createRange();\n\t\trange.setStart(position.offsetNode, position.offset);\n\t\trange.collapse(true);\n\t\treturn range;\n\t}\n\n\treturn doc.caretRangeFromPoint?.(clientX, clientY) ?? null;\n};\n\n/**\n * Ставит каретку в конец содержимого `contenteditable` — поведение F2 в Excel.\n *\n * @example\n * // F2 открывает правку с кареткой в конце\n * if (event.key === \"F2\") placeCaretAtEnd(editorRef.current);\n */\nexport const placeCaretAtEnd = (element: HTMLElement): void => {\n\tconst selection = window.getSelection();\n\tif (!selection) return;\n\n\tconst range = document.createRange();\n\trange.selectNodeContents(element);\n\trange.collapse(false);\n\tselection.removeAllRanges();\n\tselection.addRange(range);\n};\n\n/**\n * Вставляет текст в текущую позицию каретки внутри `contenteditable`, заменяя выделенное.\n *\n * Нужно на вставке из буфера: по умолчанию `contenteditable` принимает разметку, и в ячейку\n * приезжает чужое форматирование вместе с текстом.\n *\n * @example\n * onPaste={(event) => {\n * event.preventDefault();\n * insertTextAtCaret(event.currentTarget, event.clipboardData.getData(\"text/plain\"));\n * }}\n */\nexport const insertTextAtCaret = (element: HTMLElement, text: string): void => {\n\tconst selection = window.getSelection();\n\tif (!selection?.rangeCount) return;\n\n\tconst range = selection.getRangeAt(0);\n\tif (!element.contains(range.startContainer)) return;\n\n\trange.deleteContents();\n\tconst node = document.createTextNode(text);\n\trange.insertNode(node);\n\trange.setStartAfter(node);\n\trange.collapse(true);\n\tselection.removeAllRanges();\n\tselection.addRange(range);\n};\n","import { useCallback, useRef, useState } from \"react\";\r\nimport { isElementOverflowing } from \"../../lib/utils/dom\";\r\n\r\nexport const useOverflowTooltip = <T extends HTMLElement>() => {\r\n\tconst [open, setOpen] = useState(false);\r\n\tconst ref = useRef<T>(null);\r\n\r\n\tconst onOpenChange = useCallback((newOpen: boolean) => {\r\n\t\tif (newOpen === false) {\r\n\t\t\tsetOpen(false);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tif (!ref.current) return;\r\n\t\tif (isElementOverflowing(ref.current)) {\r\n\t\t\tsetOpen(true);\r\n\t\t}\r\n\t}, []);\r\n\r\n\treturn { open, onOpenChange, ref };\r\n};\r\n","import { cn } from \"@/lib/utils\";\r\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../tooltip\";\r\nimport { useOverflowTooltip } from \"./useOverflowTooltip\";\r\nimport React from \"react\";\r\n\r\ntype OverflowTooltipProps = {\r\n\tchildren: React.ReactNode;\r\n\t/**\r\n\t * HTML-элемент для обертки содержимого.\r\n\t * Используется для соблюдения правильной HTML-семантики.\r\n\t * Например:\r\n\t * - span (по умолчанию) для текста и инлайн-элементов\r\n\t * - div для блочного содержимого и сложных структур\r\n\t * @default span\r\n\t */\r\n\ttriggerTag?: React.ElementType;\r\n\t/**\r\n\t * Классы для обработки переполненного содержимого.\r\n\t * Например: \"truncate\", \"line-clamp-3\" и т.д.\r\n\t */\r\n\tclassName?: string;\r\n\t/**\r\n\t * Классы для содержимого тултипа.\r\n\t * С помощью них можно управлять стилями тултипа, например шириной, переносом текста и т.д.\r\n\t */\r\n\ttooltipClassName?: string;\r\n\tfocus?: \"high\";\r\n};\r\n\r\nexport const OverflowTooltip = ({ children, className, focus, triggerTag, tooltipClassName }: OverflowTooltipProps) => {\r\n\tconst { open, onOpenChange, ref } = useOverflowTooltip<HTMLDivElement>();\r\n\tconst TriggerTag = triggerTag || \"span\";\r\n\treturn (\r\n\t\t<TooltipProvider>\r\n\t\t\t<Tooltip open={open} onOpenChange={onOpenChange}>\r\n\t\t\t\t<TooltipTrigger asChild>\r\n\t\t\t\t\t<TriggerTag ref={ref} className={cn(className)}>\r\n\t\t\t\t\t\t{children}\r\n\t\t\t\t\t</TriggerTag>\r\n\t\t\t\t</TooltipTrigger>\r\n\t\t\t\t<TooltipContent focus={focus} className={cn(\"max-w-xs\", tooltipClassName)}>\r\n\t\t\t\t\t{children}\r\n\t\t\t\t</TooltipContent>\r\n\t\t\t</Tooltip>\r\n\t\t</TooltipProvider>\r\n\t);\r\n};\r\n\r\nOverflowTooltip.displayName = \"OverflowTooltip\";\r\n","import { cn } from \"@/lib/utils\";\r\nimport React from \"react\";\r\nimport { OverflowTooltip } from \"./OverflowTooltip\";\r\n\r\ntype TextOverflowTooltipProps = {\r\n\tchildren?: React.ReactNode;\r\n\tclassName?: string;\r\n\ttooltipClassName?: string;\r\n};\r\n\r\nexport const TextOverflowTooltip = ({ children, className, tooltipClassName }: TextOverflowTooltipProps) => {\r\n\treturn (\r\n\t\t<OverflowTooltip\r\n\t\t\tclassName={cn(\"inline-block max-w-full truncate\", className)}\r\n\t\t\ttooltipClassName={tooltipClassName}\r\n\t\t>\r\n\t\t\t{children}\r\n\t\t</OverflowTooltip>\r\n\t);\r\n};\r\n\r\nTextOverflowTooltip.displayName = \"TextOverflowTooltip\";\r\n"],"names":["isElementOverflowing","element","useOverflowTooltip","open","setOpen","useState","ref","useRef","onOpenChange","useCallback","newOpen","OverflowTooltip","children","className","focus","triggerTag","tooltipClassName","jsx","TooltipProvider","jsxs","Tooltip","TooltipTrigger","cn","TooltipContent","TextOverflowTooltip"],"mappings":";;;;AASa,MAAAA,IAAuB,CAACC,MAC7BA,EAAQ,cAAcA,EAAQ,eAAeA,EAAQ,eAAeA,EAAQ,cCPvEC,IAAqB,MAA6B;AAC9D,QAAM,CAACC,GAAMC,CAAO,IAAIC,EAAS,EAAK,GAChCC,IAAMC,EAAU,IAAI,GAEpBC,IAAeC,EAAY,CAACC,MAAqB;AACtD,QAAIA,MAAY,IAAO;AACtB,MAAAN,EAAQ,EAAK;AACb;AAAA,IAAA;AAEG,IAACE,EAAI,WACLN,EAAqBM,EAAI,OAAO,KACnCF,EAAQ,EAAI;AAAA,EAEd,GAAG,EAAE;AAEE,SAAA,EAAE,MAAAD,GAAM,cAAAK,GAAc,KAAAF,EAAI;AAClC,GCUaK,IAAkB,CAAC,EAAE,UAAAC,GAAU,WAAAC,GAAW,OAAAC,GAAO,YAAAC,GAAY,kBAAAC,QAA6C;AACtH,QAAM,EAAE,MAAAb,GAAM,cAAAK,GAAc,KAAAF,EAAA,IAAQJ,EAAmC;AAEvE,SACE,gBAAAe,EAAAC,GAAA,EACA,UAAC,gBAAAC,EAAAC,GAAA,EAAQ,MAAAjB,GAAY,cAAAK,GACpB,UAAA;AAAA,IAAC,gBAAAS,EAAAI,GAAA,EAAe,SAAO,IACtB,UAAC,gBAAAJ,EALcF,KAAc,QAK5B,EAAW,KAAAT,GAAU,WAAWgB,EAAGT,CAAS,GAC3C,UAAAD,EACF,CAAA,GACD;AAAA,IACA,gBAAAK,EAACM,KAAe,OAAAT,GAAc,WAAWQ,EAAG,YAAYN,CAAgB,GACtE,UAAAJ,EACF,CAAA;AAAA,EAAA,EAAA,CACD,EACD,CAAA;AAEF;AAEAD,EAAgB,cAAc;ACtCvB,MAAMa,IAAsB,CAAC,EAAE,UAAAZ,GAAU,WAAAC,GAAW,kBAAAG,QAEzD,gBAAAC;AAAA,EAACN;AAAA,EAAA;AAAA,IACA,WAAWW,EAAG,oCAAoCT,CAAS;AAAA,IAC3D,kBAAAG;AAAA,IAEC,UAAAJ;AAAA,EAAA;AACF;AAIFY,EAAoB,cAAc;"}
1
+ {"version":3,"file":"TextOverflowTooltip-XPDdO9Dz.js","sources":["../src/lib/utils/dom.ts","../src/components/overflow-tooltip/useOverflowTooltip.ts","../src/components/overflow-tooltip/OverflowTooltip.tsx","../src/components/overflow-tooltip/TextOverflowTooltip.tsx"],"sourcesContent":["/**\n * Проверяет, переполнен ли элемент (дочерние элементы выходят за пределы родительского элемента)\n * @param element - HTML элемент для проверки\n * @returns true, если элемент переполнен по ширине или высоте\n *\n * @example\n * // подсказку показываем только там, где текст обрезан\n * const truncated = isElementOverflowing(labelRef.current);\n */\nexport const isElementOverflowing = (element: HTMLElement): boolean => {\n\treturn element.scrollWidth > element.offsetWidth || element.scrollHeight > element.offsetHeight;\n};\n\n/**\n * Canvas для измерения текста переиспользуется: на каждый вызов создавать его расточительно.\n *\n * Контекст один на все поля страницы, и это безопасно ровно до тех пор, пока каждое\n * измерение выставляет **все** влияющие на ширину свойства. Условное присваивание оставило бы\n * настройку от предыдущего поля: соседняя таблица со своим `letter-spacing` мерила бы текст\n * чужим трекингом. Поэтому свойства ниже пишутся всегда, а сам canvas остаётся приватным\n * для этого модуля — иначе инвариант незаметно нарушит следующий пользователь.\n */\nlet measureContext: CanvasRenderingContext2D | null | undefined;\n\nconst getMeasureContext = () => {\n\tif (measureContext === undefined) measureContext = document.createElement(\"canvas\").getContext(\"2d\");\n\treturn measureContext;\n};\n\n/**\n * Ставит каретку в `input`/`textarea` по горизонтальной координате указателя (`clientX`).\n *\n * Нужно там, где поле появляется по клику уже после самого клика — например, при переходе\n * ячейки таблицы в режим редактирования по двойному щелчку: без этого каретка встаёт\n * в начало или конец, а не туда, куда целился пользователь.\n *\n * `caretPositionFromPoint` / `caretRangeFromPoint` здесь бесполезны: содержимое `input`\n * не является частью DOM-дерева, и Range/Selection API до него не достаёт — вернётся сам\n * элемент, а не позиция в тексте. Поэтому индекс считается вручную: текст измеряется\n * на offscreen canvas тем же шрифтом, и выбирается ближайшая к точке граница символа.\n * Ширины префиксов монотонно растут, так что перебор обрывается, как только начал удаляться\n * от цели.\n *\n * Учитывается только горизонталь, поэтому для многострочного текста функция не годится —\n * там нужен `placeCaretAtClientPoint` по `contenteditable`.\n *\n * Возвращает `false`, если поставить каретку не удалось (поле пустое, тип поля не поддерживает\n * выделение или canvas недоступен) — вызывающему коду в этом случае стоит оставить поведение\n * по умолчанию.\n *\n * @example\n * // координата запоминается на dblclick, применяется, когда поле получило фокус\n * <input\n * autoFocus\n * onFocus={(event) => {\n * const input = event.currentTarget;\n * if (!placeCaretAtPoint(input, caretX)) placeCaretAtEnd(input);\n * }}\n * />\n */\nexport const placeCaretAtPoint = (element: HTMLInputElement | HTMLTextAreaElement, clientX: number): boolean => {\n\tconst value = element.value;\n\tif (!value) return false;\n\n\t// У `type=number|email|date|time|color` выделения нет, а `setSelectionRange` на них кидает\n\t// `InvalidStateError`. Тип полей задаёт прикладной код, поэтому проверяем, а не полагаемся.\n\tif (element.selectionStart === null) return false;\n\n\tconst context = getMeasureContext();\n\tif (!context) return false;\n\n\tconst style = window.getComputedStyle(element);\n\tcontext.font = `${style.fontStyle} ${style.fontWeight} ${style.fontSize} ${style.fontFamily}`;\n\t// `letterSpacing` у canvas принимает только длину: `normal` из вычисленных стилей его сломает.\n\t// Пишется на каждом вызове — иначе значение утечёт в следующее поле, см. `measureContext`.\n\tif (\"letterSpacing\" in context) {\n\t\tcontext.letterSpacing = style.letterSpacing.endsWith(\"px\") ? style.letterSpacing : \"0px\";\n\t}\n\n\tconst rect = element.getBoundingClientRect();\n\tconst borderLeft = parseFloat(style.borderLeftWidth) || 0;\n\tconst borderRight = parseFloat(style.borderRightWidth) || 0;\n\tconst paddingLeft = parseFloat(style.paddingLeft) || 0;\n\tconst paddingRight = parseFloat(style.paddingRight) || 0;\n\tconst contentLeft = rect.left + borderLeft + paddingLeft;\n\tconst contentWidth = rect.width - borderLeft - borderRight - paddingLeft - paddingRight;\n\n\t// Текст короче поля прижимается по `text-align`, и отсчитывать позицию от левого края\n\t// нельзя — у выровненного вправо поля это промах на всю свободную ширину.\n\tconst slack = contentWidth - context.measureText(value).width;\n\tlet originX = contentLeft - element.scrollLeft;\n\tif (slack > 0) {\n\t\tif (style.textAlign === \"right\" || style.textAlign === \"end\") originX += slack;\n\t\telse if (style.textAlign === \"center\") originX += slack / 2;\n\t}\n\n\tconst targetX = clientX - originX;\n\tlet bestIndex = 0;\n\tlet bestDistance = Infinity;\n\tfor (let index = 0; index <= value.length; index++) {\n\t\tconst distance = Math.abs(context.measureText(value.slice(0, index)).width - targetX);\n\t\tif (distance > bestDistance) break;\n\t\tbestDistance = distance;\n\t\tbestIndex = index;\n\t}\n\n\telement.setSelectionRange(bestIndex, bestIndex);\n\treturn true;\n};\n\n/**\n * Ставит каретку в `contenteditable` по точке указателя.\n *\n * В отличие от `input`, текст здесь — обычные узлы DOM, поэтому измерять ничего не нужно:\n * браузер сам отдаёт позицию по координатам. Работает и с переносами, так что это тот случай,\n * когда многострочная правка делается редактируемым `div`, а не `textarea`.\n *\n * Возвращает `false`, если точка не попала в текст элемента, — вызывающему коду стоит\n * поставить каретку в конец через `placeCaretAtEnd`.\n *\n * @example\n * const editor = event.currentTarget;\n * if (!placeCaretAtClientPoint(editor, event.clientX, event.clientY)) placeCaretAtEnd(editor);\n */\nexport const placeCaretAtClientPoint = (element: HTMLElement, clientX: number, clientY: number): boolean => {\n\tconst selection = window.getSelection();\n\tif (!selection) return false;\n\n\tconst range = caretRangeAtPoint(clientX, clientY);\n\t// Точка могла прийтись на отступ ячейки или на соседний узел: чужую позицию не ставим.\n\tif (!range || !element.contains(range.startContainer)) return false;\n\n\tselection.removeAllRanges();\n\tselection.addRange(range);\n\treturn true;\n};\n\n/**\n * Оба способа спросить у браузера позицию каретки по координатам — объявлены здесь сами.\n *\n * `caretPositionFromPoint` — стандартный, но в `lib.dom` TS 5.6 его ещё нет.\n * `caretRangeFromPoint` — легаси WebKit, в `lib.dom` он помечен `@deprecated`; берётся\n * только фолбэком для Safari до 17.4, где стандартного метода ещё не было. Объявление\n * собрано в одном месте намеренно: обращение идёт к нему, а не к устаревшему члену `Document`,\n * и причина использования легаси видна рядом, а не прячется за подавленной подсказкой.\n */\ntype DocumentWithCaretApi = Document & {\n\tcaretPositionFromPoint?: (x: number, y: number) => { offsetNode: Node; offset: number } | null;\n\tcaretRangeFromPoint?: (x: number, y: number) => Range | null;\n};\n\nconst caretRangeAtPoint = (clientX: number, clientY: number): Range | null => {\n\tconst doc = document as DocumentWithCaretApi;\n\n\tif (doc.caretPositionFromPoint) {\n\t\tconst position = doc.caretPositionFromPoint(clientX, clientY);\n\t\tif (!position) return null;\n\t\tconst range = document.createRange();\n\t\trange.setStart(position.offsetNode, position.offset);\n\t\trange.collapse(true);\n\t\treturn range;\n\t}\n\n\treturn doc.caretRangeFromPoint?.(clientX, clientY) ?? null;\n};\n\n/**\n * Ставит каретку в конец содержимого `contenteditable` — поведение F2 в Excel.\n *\n * @example\n * // F2 открывает правку с кареткой в конце\n * if (event.key === \"F2\") placeCaretAtEnd(editorRef.current);\n */\nexport const placeCaretAtEnd = (element: HTMLElement): void => {\n\tconst selection = window.getSelection();\n\tif (!selection) return;\n\n\tconst range = document.createRange();\n\trange.selectNodeContents(element);\n\trange.collapse(false);\n\tselection.removeAllRanges();\n\tselection.addRange(range);\n};\n\n/**\n * Вставляет текст в текущую позицию каретки внутри `contenteditable`, заменяя выделенное.\n *\n * Нужно на вставке из буфера: по умолчанию `contenteditable` принимает разметку, и в ячейку\n * приезжает чужое форматирование вместе с текстом.\n *\n * @example\n * onPaste={(event) => {\n * event.preventDefault();\n * insertTextAtCaret(event.currentTarget, event.clipboardData.getData(\"text/plain\"));\n * }}\n */\nexport const insertTextAtCaret = (element: HTMLElement, text: string): void => {\n\tconst selection = window.getSelection();\n\tif (!selection?.rangeCount) return;\n\n\tconst range = selection.getRangeAt(0);\n\tif (!element.contains(range.startContainer)) return;\n\n\trange.deleteContents();\n\tconst node = document.createTextNode(text);\n\trange.insertNode(node);\n\trange.setStartAfter(node);\n\trange.collapse(true);\n\tselection.removeAllRanges();\n\tselection.addRange(range);\n};\n","import { useCallback, useRef, useState } from \"react\";\nimport { isElementOverflowing } from \"../../lib/utils/dom\";\n\nexport const useOverflowTooltip = <T extends HTMLElement>() => {\n\tconst [open, setOpen] = useState(false);\n\tconst ref = useRef<T>(null);\n\n\tconst onOpenChange = useCallback((newOpen: boolean) => {\n\t\tif (newOpen === false) {\n\t\t\tsetOpen(false);\n\t\t\treturn;\n\t\t}\n\t\tif (!ref.current) return;\n\t\tif (isElementOverflowing(ref.current)) {\n\t\t\tsetOpen(true);\n\t\t}\n\t}, []);\n\n\treturn { open, onOpenChange, ref };\n};\n","import { cn } from \"@/lib/utils\";\nimport { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from \"../tooltip\";\nimport { useOverflowTooltip } from \"./useOverflowTooltip\";\nimport React from \"react\";\n\ntype OverflowTooltipProps = {\n\tchildren: React.ReactNode;\n\t/**\n\t * HTML-элемент для обертки содержимого.\n\t * Используется для соблюдения правильной HTML-семантики.\n\t * Например:\n\t * - span (по умолчанию) для текста и инлайн-элементов\n\t * - div для блочного содержимого и сложных структур\n\t * @default span\n\t */\n\ttriggerTag?: React.ElementType;\n\t/**\n\t * Классы для обработки переполненного содержимого.\n\t * Например: \"truncate\", \"line-clamp-3\" и т.д.\n\t */\n\tclassName?: string;\n\t/**\n\t * Классы для содержимого тултипа.\n\t * С помощью них можно управлять стилями тултипа, например шириной, переносом текста и т.д.\n\t */\n\ttooltipClassName?: string;\n\tfocus?: \"high\";\n};\n\nexport const OverflowTooltip = ({ children, className, focus, triggerTag, tooltipClassName }: OverflowTooltipProps) => {\n\tconst { open, onOpenChange, ref } = useOverflowTooltip<HTMLDivElement>();\n\tconst TriggerTag = triggerTag || \"span\";\n\treturn (\n\t\t<TooltipProvider>\n\t\t\t<Tooltip open={open} onOpenChange={onOpenChange}>\n\t\t\t\t<TooltipTrigger asChild>\n\t\t\t\t\t<TriggerTag ref={ref} className={cn(className)}>\n\t\t\t\t\t\t{children}\n\t\t\t\t\t</TriggerTag>\n\t\t\t\t</TooltipTrigger>\n\t\t\t\t<TooltipContent focus={focus} className={cn(\"max-w-xs\", tooltipClassName)}>\n\t\t\t\t\t{children}\n\t\t\t\t</TooltipContent>\n\t\t\t</Tooltip>\n\t\t</TooltipProvider>\n\t);\n};\n\nOverflowTooltip.displayName = \"OverflowTooltip\";\n","import { cn } from \"@/lib/utils\";\nimport React from \"react\";\nimport { OverflowTooltip } from \"./OverflowTooltip\";\n\ntype TextOverflowTooltipProps = {\n\tchildren?: React.ReactNode;\n\tclassName?: string;\n\ttooltipClassName?: string;\n};\n\nexport const TextOverflowTooltip = ({ children, className, tooltipClassName }: TextOverflowTooltipProps) => {\n\treturn (\n\t\t<OverflowTooltip\n\t\t\tclassName={cn(\"inline-block max-w-full truncate\", className)}\n\t\t\ttooltipClassName={tooltipClassName}\n\t\t>\n\t\t\t{children}\n\t\t</OverflowTooltip>\n\t);\n};\n\nTextOverflowTooltip.displayName = \"TextOverflowTooltip\";\n"],"names":["isElementOverflowing","element","useOverflowTooltip","open","setOpen","useState","ref","useRef","onOpenChange","useCallback","newOpen","OverflowTooltip","children","className","focus","triggerTag","tooltipClassName","jsx","TooltipProvider","jsxs","Tooltip","TooltipTrigger","cn","TooltipContent","TextOverflowTooltip"],"mappings":";;;;AASa,MAAAA,IAAuB,CAACC,MAC7BA,EAAQ,cAAcA,EAAQ,eAAeA,EAAQ,eAAeA,EAAQ,cCPvEC,IAAqB,MAA6B;AAC9D,QAAM,CAACC,GAAMC,CAAO,IAAIC,EAAS,EAAK,GAChCC,IAAMC,EAAU,IAAI,GAEpBC,IAAeC,EAAY,CAACC,MAAqB;AACtD,QAAIA,MAAY,IAAO;AACtB,MAAAN,EAAQ,EAAK;AACb;AAAA,IAAA;AAEG,IAACE,EAAI,WACLN,EAAqBM,EAAI,OAAO,KACnCF,EAAQ,EAAI;AAAA,EAEd,GAAG,EAAE;AAEE,SAAA,EAAE,MAAAD,GAAM,cAAAK,GAAc,KAAAF,EAAI;AAClC,GCUaK,IAAkB,CAAC,EAAE,UAAAC,GAAU,WAAAC,GAAW,OAAAC,GAAO,YAAAC,GAAY,kBAAAC,QAA6C;AACtH,QAAM,EAAE,MAAAb,GAAM,cAAAK,GAAc,KAAAF,EAAA,IAAQJ,EAAmC;AAEvE,SACE,gBAAAe,EAAAC,GAAA,EACA,UAAC,gBAAAC,EAAAC,GAAA,EAAQ,MAAAjB,GAAY,cAAAK,GACpB,UAAA;AAAA,IAAC,gBAAAS,EAAAI,GAAA,EAAe,SAAO,IACtB,UAAC,gBAAAJ,EALcF,KAAc,QAK5B,EAAW,KAAAT,GAAU,WAAWgB,EAAGT,CAAS,GAC3C,UAAAD,EACF,CAAA,GACD;AAAA,IACA,gBAAAK,EAACM,KAAe,OAAAT,GAAc,WAAWQ,EAAG,YAAYN,CAAgB,GACtE,UAAAJ,EACF,CAAA;AAAA,EAAA,EAAA,CACD,EACD,CAAA;AAEF;AAEAD,EAAgB,cAAc;ACtCvB,MAAMa,IAAsB,CAAC,EAAE,UAAAZ,GAAU,WAAAC,GAAW,kBAAAG,QAEzD,gBAAAC;AAAA,EAACN;AAAA,EAAA;AAAA,IACA,WAAWW,EAAG,oCAAoCT,CAAS;AAAA,IAC3D,kBAAAG;AAAA,IAEC,UAAAJ;AAAA,EAAA;AACF;AAIFY,EAAoB,cAAc;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Toggle-CmalMf4O.js","sources":["../src/components/toggle/Toggle.tsx"],"sourcesContent":["import * as React from \"react\";\r\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\r\nimport { cn } from \"@/lib/utils\";\r\nimport { tv } from \"tailwind-variants\";\r\nimport { VariantsConfig } from \"@/lib/utils/variants\";\r\n\r\nexport interface ToggleVariants {\r\n\tvariant?: \"default\" | \"outline\" | \"ghost\";\r\n\tsize?: \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\r\n}\r\n\r\nconst toggleStyles = tv({\r\n\tbase: [\r\n\t\t\"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium leading-none text-primary-fg transition-colors\",\r\n\t\t\"hover:bg-secondary-bg-hover hover:text-muted\",\r\n\t\t\"focus-visible:border-secondary-border focus-visible:shadow-focus focus-visible:outline-hidden\",\r\n\t\t\"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50\",\r\n\t\t\"data-[state=on]:bg-primary-bg-hover data-[state=on]:text-primary-fg\",\r\n\t\t\"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\"\r\n\t],\r\n\tvariants: {\r\n\t\tvariant: {\r\n\t\t\tdefault: \"bg-transparent\",\r\n\t\t\toutline:\r\n\t\t\t\t\"border border-secondary-border bg-secondary-bg shadow-soft-sm data-[state=on]:border-primary-border\",\r\n\t\t\tghost: \"bg-transparent hover:text-primary-fg hover:opacity-65 data-[state=on]:bg-secondary-bg-hover\"\r\n\t\t},\r\n\t\tsize: {\r\n\t\t\t\"2xs\": \"h-6 min-w-6 gap-1 rounded-sm p-1\",\r\n\t\t\txs: \"h-7 min-w-7 gap-1.5 rounded-sm p-1.5\",\r\n\t\t\tsm: \"h-8 min-w-8 rounded-sm p-2\",\r\n\t\t\tmd: \"h-9 min-w-9 p-2.5\",\r\n\t\t\tlg: \"h-10 min-w-10 px-3 py-2\",\r\n\t\t\txl: \"h-11 min-w-11 px-4 py-3 text-base leading-none [&_svg]:size-5\"\r\n\t\t}\r\n\t} satisfies VariantsConfig<ToggleVariants>,\r\n\tdefaultVariants: {\r\n\t\tvariant: \"default\",\r\n\t\tsize: \"md\"\r\n\t}\r\n});\r\n\r\nconst Toggle = React.forwardRef<\r\n\tReact.ElementRef<typeof TogglePrimitive.Root>,\r\n\tReact.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & ToggleVariants\r\n>(({ className, variant, size, ...props }, ref) => (\r\n\t<TogglePrimitive.Root ref={ref} className={cn(toggleStyles({ variant, size, className }))} {...props} />\r\n));\r\n\r\nToggle.displayName = TogglePrimitive.Root.displayName;\r\n\r\nexport { Toggle, toggleStyles as toggleVariants };\r\n"],"names":["toggleStyles","tv","Toggle","React","className","variant","size","props","ref","jsx","TogglePrimitive.Root","cn"],"mappings":";;;;;AAWA,MAAMA,IAAeC,EAAG;AAAA,EACvB,MAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAAA,EACA,UAAU;AAAA,IACT,SAAS;AAAA,MACR,SAAS;AAAA,MACT,SACC;AAAA,MACD,OAAO;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACL,OAAO;AAAA,MACP,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EAEN;AAAA,EACA,iBAAiB;AAAA,IAChB,SAAS;AAAA,IACT,MAAM;AAAA,EAAA;AAER,CAAC,GAEKC,IAASC,EAAM,WAGnB,CAAC,EAAE,WAAAC,GAAW,SAAAC,GAAS,MAAAC,GAAM,GAAGC,KAASC,MACzC,gBAAAC,EAAAC,GAAA,EAAqB,KAAAF,GAAU,WAAWG,EAAGX,EAAa,EAAE,SAAAK,GAAS,MAAAC,GAAM,WAAAF,EAAW,CAAA,CAAC,GAAI,GAAGG,GAAO,CACtG;AAEDL,EAAO,cAAcQ,EAAqB;"}
1
+ {"version":3,"file":"Toggle-CmalMf4O.js","sources":["../src/components/toggle/Toggle.tsx"],"sourcesContent":["import * as React from \"react\";\nimport * as TogglePrimitive from \"@radix-ui/react-toggle\";\nimport { cn } from \"@/lib/utils\";\nimport { tv } from \"tailwind-variants\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\n\nexport interface ToggleVariants {\n\tvariant?: \"default\" | \"outline\" | \"ghost\";\n\tsize?: \"2xs\" | \"xs\" | \"sm\" | \"md\" | \"lg\" | \"xl\";\n}\n\nconst toggleStyles = tv({\n\tbase: [\n\t\t\"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium leading-none text-primary-fg transition-colors\",\n\t\t\"hover:bg-secondary-bg-hover hover:text-muted\",\n\t\t\"focus-visible:border-secondary-border focus-visible:shadow-focus focus-visible:outline-hidden\",\n\t\t\"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50\",\n\t\t\"data-[state=on]:bg-primary-bg-hover data-[state=on]:text-primary-fg\",\n\t\t\"[&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\"\n\t],\n\tvariants: {\n\t\tvariant: {\n\t\t\tdefault: \"bg-transparent\",\n\t\t\toutline:\n\t\t\t\t\"border border-secondary-border bg-secondary-bg shadow-soft-sm data-[state=on]:border-primary-border\",\n\t\t\tghost: \"bg-transparent hover:text-primary-fg hover:opacity-65 data-[state=on]:bg-secondary-bg-hover\"\n\t\t},\n\t\tsize: {\n\t\t\t\"2xs\": \"h-6 min-w-6 gap-1 rounded-sm p-1\",\n\t\t\txs: \"h-7 min-w-7 gap-1.5 rounded-sm p-1.5\",\n\t\t\tsm: \"h-8 min-w-8 rounded-sm p-2\",\n\t\t\tmd: \"h-9 min-w-9 p-2.5\",\n\t\t\tlg: \"h-10 min-w-10 px-3 py-2\",\n\t\t\txl: \"h-11 min-w-11 px-4 py-3 text-base leading-none [&_svg]:size-5\"\n\t\t}\n\t} satisfies VariantsConfig<ToggleVariants>,\n\tdefaultVariants: {\n\t\tvariant: \"default\",\n\t\tsize: \"md\"\n\t}\n});\n\nconst Toggle = React.forwardRef<\n\tReact.ElementRef<typeof TogglePrimitive.Root>,\n\tReact.ComponentPropsWithoutRef<typeof TogglePrimitive.Root> & ToggleVariants\n>(({ className, variant, size, ...props }, ref) => (\n\t<TogglePrimitive.Root ref={ref} className={cn(toggleStyles({ variant, size, className }))} {...props} />\n));\n\nToggle.displayName = TogglePrimitive.Root.displayName;\n\nexport { Toggle, toggleStyles as toggleVariants };\n"],"names":["toggleStyles","tv","Toggle","React","className","variant","size","props","ref","jsx","TogglePrimitive.Root","cn"],"mappings":";;;;;AAWA,MAAMA,IAAeC,EAAG;AAAA,EACvB,MAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AAAA,EACA,UAAU;AAAA,IACT,SAAS;AAAA,MACR,SAAS;AAAA,MACT,SACC;AAAA,MACD,OAAO;AAAA,IACR;AAAA,IACA,MAAM;AAAA,MACL,OAAO;AAAA,MACP,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,EAEN;AAAA,EACA,iBAAiB;AAAA,IAChB,SAAS;AAAA,IACT,MAAM;AAAA,EAAA;AAER,CAAC,GAEKC,IAASC,EAAM,WAGnB,CAAC,EAAE,WAAAC,GAAW,SAAAC,GAAS,MAAAC,GAAM,GAAGC,KAASC,MACzC,gBAAAC,EAAAC,GAAA,EAAqB,KAAAF,GAAU,WAAWG,EAAGX,EAAa,EAAE,SAAAK,GAAS,MAAAC,GAAM,WAAAF,EAAW,CAAA,CAAC,GAAI,GAAGG,GAAO,CACtG;AAEDL,EAAO,cAAcQ,EAAqB;"}