ics-ui-kit 0.1.13 → 0.1.15

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 (115) hide show
  1. package/dist/{AlertIcon-5B6AgZpe.js → AlertIcon-BphnEYvV.js} +3 -3
  2. package/dist/AlertIcon-BphnEYvV.js.map +1 -0
  3. package/dist/Field-CP_-li9L.js +90 -0
  4. package/dist/Field-CP_-li9L.js.map +1 -0
  5. package/dist/{FormFooterTemplate-ClTxqrIB.js → FormFooterTemplate-Cfn5Nmge.js} +2 -2
  6. package/dist/{FormFooterTemplate-ClTxqrIB.js.map → FormFooterTemplate-Cfn5Nmge.js.map} +1 -1
  7. package/dist/{FormStack-B3UBh9oF.js → FormStack-Cc_ELdWL.js} +2 -2
  8. package/dist/{FormStack-B3UBh9oF.js.map → FormStack-Cc_ELdWL.js.map} +1 -1
  9. package/dist/{SearchSelectTag-DFCX9zT1.js → SearchSelectTag-CA7Ie3Nx.js} +2 -2
  10. package/dist/{SearchSelectTag-DFCX9zT1.js.map → SearchSelectTag-CA7Ie3Nx.js.map} +1 -1
  11. package/dist/TableFillHandle-C_yvCTSl.js +65 -0
  12. package/dist/TableFillHandle-C_yvCTSl.js.map +1 -0
  13. package/dist/TextOverflowTooltip-B1I5qwAT.js.map +1 -1
  14. package/dist/blocks/auth/otp-form.js +1 -1
  15. package/dist/components/alert/Alert.d.ts +4 -0
  16. package/dist/components/alert/Alert.stories.d.ts +1 -0
  17. package/dist/components/alert-dialog.js +1 -1
  18. package/dist/components/alert.js +18 -18
  19. package/dist/components/alert.js.map +1 -1
  20. package/dist/components/card.js +1 -1
  21. package/dist/components/counter.js +6 -6
  22. package/dist/components/counter.js.map +1 -1
  23. package/dist/components/dialog/Dialog.stories.d.ts +1 -0
  24. package/dist/components/dialog.js +1 -1
  25. package/dist/components/dropdown.js +98 -98
  26. package/dist/components/dropdown.js.map +1 -1
  27. package/dist/components/field/Field.d.ts +4 -0
  28. package/dist/components/field/Field.stories.d.ts +1 -0
  29. package/dist/components/field.js +1 -1
  30. package/dist/components/file-upload.js +1 -1
  31. package/dist/components/form.js +3 -3
  32. package/dist/components/glass-toolbar/GlassToolbar.stories.d.ts +1 -0
  33. package/dist/components/glass-toolbar.js +35 -35
  34. package/dist/components/glass-toolbar.js.map +1 -1
  35. package/dist/components/search-select.js +1 -1
  36. package/dist/components/sidebar/Sidebar.stories.d.ts +278 -2
  37. package/dist/components/sidebar/SidebarContext.d.ts +2 -0
  38. package/dist/components/sidebar.js +271 -267
  39. package/dist/components/sidebar.js.map +1 -1
  40. package/dist/components/system-state.js +1 -1
  41. package/dist/components/table/Table.d.ts +109 -5
  42. package/dist/components/table/Table.stories.d.ts +285 -9
  43. package/dist/components/table/column-reorder/index.d.ts +1 -0
  44. package/dist/components/table/column-reorder/useColumnReorder.d.ts +82 -0
  45. package/dist/components/table/column-reorder.d.ts +2 -0
  46. package/dist/components/table/column-reorder.js +6 -0
  47. package/dist/components/table/column-reorder.js.map +1 -0
  48. package/dist/components/table/column-resize/columnAutoFit.d.ts +21 -0
  49. package/dist/components/table/column-resize/columnResizeSession.d.ts +9 -0
  50. package/dist/components/table/column-resize/index.d.ts +3 -0
  51. package/dist/components/table/column-resize/useColumnResize.d.ts +52 -0
  52. package/dist/components/table/column-resize.d.ts +2 -0
  53. package/dist/components/table/column-resize.js +7 -0
  54. package/dist/components/table/column-resize.js.map +1 -0
  55. package/dist/components/table/editable/TableFillHandle.d.ts +23 -0
  56. package/dist/components/table/editable/cellRange.d.ts +83 -0
  57. package/dist/components/table/editable/editableCell.d.ts +90 -0
  58. package/dist/components/table/editable/index.d.ts +3 -0
  59. package/dist/components/table/editable.d.ts +2 -0
  60. package/dist/components/table/editable.js +12 -0
  61. package/dist/components/table/editable.js.map +1 -0
  62. package/dist/components/table/index.d.ts +8 -1
  63. package/dist/components/table/opaqueCell.d.ts +47 -0
  64. package/dist/components/table/rowTint.d.ts +60 -0
  65. package/dist/components/table/sticky/index.d.ts +1 -0
  66. package/dist/components/table/sticky/stickyCell.d.ts +105 -0
  67. package/dist/components/table/sticky.d.ts +2 -0
  68. package/dist/components/table/sticky.js +22 -0
  69. package/dist/components/table/sticky.js.map +1 -0
  70. package/dist/components/table/tableStoryData.d.ts +84 -0
  71. package/dist/components/table/tableStoryParts.d.ts +72 -0
  72. package/dist/components/table/tree/TableTree.d.ts +106 -0
  73. package/dist/components/table/tree/index.d.ts +3 -0
  74. package/dist/components/table/tree/treeGeometry.d.ts +86 -0
  75. package/dist/components/table/tree/treeModel.d.ts +87 -0
  76. package/dist/components/table/tree.d.ts +2 -0
  77. package/dist/components/table/tree.js +19 -0
  78. package/dist/components/table/tree.js.map +1 -0
  79. package/dist/components/table.js +52 -79
  80. package/dist/components/table.js.map +1 -1
  81. package/dist/components/tag-input.js +1 -1
  82. package/dist/components/toolbar.js +1 -2
  83. package/dist/components/toolbar.js.map +1 -1
  84. package/dist/hooks.js +1 -1
  85. package/dist/lib/utils/dom.d.ts +72 -0
  86. package/dist/opaqueCell-SGaiyL54.js +31 -0
  87. package/dist/opaqueCell-SGaiyL54.js.map +1 -0
  88. package/dist/plus-BpxYPnAG.js +15 -0
  89. package/dist/plus-BpxYPnAG.js.map +1 -0
  90. package/dist/styles-scoped.css +327 -81
  91. package/dist/styles.css +327 -81
  92. package/dist/theme.css +2 -0
  93. package/dist/treeModel-BlPWVj4W.js +319 -0
  94. package/dist/treeModel-BlPWVj4W.js.map +1 -0
  95. package/dist/useBreakpoints-DHvp74UL.js +31 -0
  96. package/dist/useBreakpoints-DHvp74UL.js.map +1 -0
  97. package/dist/useColumnReorder-BxVZQ_Y5.js +119 -0
  98. package/dist/useColumnReorder-BxVZQ_Y5.js.map +1 -0
  99. package/dist/useColumnResize-wjfEyBBg.js +130 -0
  100. package/dist/useColumnResize-wjfEyBBg.js.map +1 -0
  101. package/dist/vendors/date-fns/index.d.ts +7 -14
  102. package/dist/vendors/date-fns/locale/en-US/index.d.ts +4 -0
  103. package/dist/vendors/date-fns/locale/ru/index.d.ts +4 -0
  104. package/dist/vendors/react-day-picker/index.d.ts +8 -17
  105. package/dist/vendors/react-hook-form/index.d.ts +8 -15
  106. package/dist/vendors/tanstack/react-table/index.d.ts +12 -0
  107. package/dist/vendors/zod/index.d.ts +8 -9
  108. package/package.json +3 -2
  109. package/tailwind.preset.js +6 -2
  110. package/dist/AlertIcon-5B6AgZpe.js.map +0 -1
  111. package/dist/Field-COD9VbUX.js +0 -86
  112. package/dist/Field-COD9VbUX.js.map +0 -1
  113. package/dist/components/data-table/DataTable.stories.d.ts +0 -8
  114. package/dist/useBreakpoints-D8wKOvil.js +0 -103
  115. package/dist/useBreakpoints-D8wKOvil.js.map +0 -1
@@ -6,8 +6,8 @@ import { A as f, u as l } from "./AlertContext-CxjW1LVL.js";
6
6
  import { I as g } from "./Icon-DH3ev9GK.js";
7
7
  const b = c({
8
8
  base: [
9
- "group relative w-full items-start rounded-xl border border-secondary-border bg-secondary-bg px-4 py-3 text-sm",
10
- "grid grid-cols-[auto_1fr_auto] gap-y-1.5"
9
+ "group relative w-full min-w-80 items-start rounded-xl border border-secondary-border bg-secondary-bg px-4 py-3 text-sm",
10
+ "@container @sm:grid-cols-[auto_1fr_auto] grid grid-cols-[auto_1fr] gap-y-1.5"
11
11
  ],
12
12
  variants: {
13
13
  status: {
@@ -93,4 +93,4 @@ export {
93
93
  p as a,
94
94
  w as b
95
95
  };
96
- //# sourceMappingURL=AlertIcon-5B6AgZpe.js.map
96
+ //# sourceMappingURL=AlertIcon-BphnEYvV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AlertIcon-BphnEYvV.js","sources":["../src/components/alert/Alert.tsx","../src/components/alert/components/AlertDescription.tsx","../src/components/alert/components/AlertIcon.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { AlertContext } from \"./AlertContext\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\n\nexport interface AlertVariants {\n\t/** Статус алерта */\n\tstatus?: \"success\" | \"warning\" | \"error\" | \"info\";\n\t/** Состояние фокуса */\n\tfocus?: \"low\" | \"medium\" | \"high\";\n}\n\nconst alertStyles = tv({\n\tbase: [\n\t\t\"group relative w-full min-w-80 items-start rounded-xl border border-secondary-border bg-secondary-bg px-4 py-3 text-sm\",\n\t\t\"@container @sm:grid-cols-[auto_1fr_auto] grid grid-cols-[auto_1fr] gap-y-1.5\"\n\t],\n\tvariants: {\n\t\tstatus: {\n\t\t\tsuccess: \"border-status-success-secondary-border bg-status-success-bg\",\n\t\t\twarning: \"border-status-warning-secondary-border bg-status-warning-bg\",\n\t\t\terror: \"border-status-error-secondary-border bg-status-error-bg\",\n\t\t\tinfo: \"border-status-info-secondary-border bg-status-info-bg\"\n\t\t},\n\t\tfocus: {\n\t\t\tlow: \"border-secondary-border bg-secondary-bg\",\n\t\t\tmedium: \"bg-secondary-bg\",\n\t\t\t// Не задаем bg, чтобы не переопределять status. Определяем в compoundVariants.\n\t\t\thigh: \"\"\n\t\t}\n\t} satisfies VariantsConfig<AlertVariants>,\n\tcompoundVariants: [\n\t\t{\n\t\t\tstatus: undefined,\n\t\t\tfocus: \"high\",\n\t\t\tclass: \"bg-status-neutral-bg\"\n\t\t}\n\t],\n\tdefaultVariants: {\n\t\tfocus: \"low\"\n\t}\n});\n\nexport type AlertProps = React.HTMLAttributes<HTMLDivElement> & AlertVariants;\n\n/**\n * Компонент Alert для отображения уведомлений и сообщений\n *\n * Является container query контейнером: при ширине меньше `@sm` (384px) кнопка\n * переносится под заголовок и описание. Минимальная ширина — 320px (`min-w-80`);\n * снимается через `className=\"min-w-0\"`.\n */\nexport const Alert = React.forwardRef<HTMLDivElement, AlertProps>(\n\t({ className, status, focus = \"low\", children, ...props }, ref) => {\n\t\tconst contextValue = React.useMemo(\n\t\t\t() => ({\n\t\t\t\tstatus,\n\t\t\t\tfocus\n\t\t\t}),\n\t\t\t[status, focus]\n\t\t);\n\n\t\treturn (\n\t\t\t<AlertContext.Provider value={contextValue}>\n\t\t\t\t<div ref={ref} role=\"alert\" className={alertStyles({ status, focus, className })} {...props}>\n\t\t\t\t\t{children}\n\t\t\t\t</div>\n\t\t\t</AlertContext.Provider>\n\t\t);\n\t}\n);\n\nAlert.displayName = \"Alert\";\n","import { tv } from \"tailwind-variants\";\nimport React from \"react\";\nimport { useAlert } from \"../AlertContext\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\nimport { AlertVariants } from \"../Alert\";\n\nconst alertDescriptionStyles = tv({\n\tbase: \"col-start-2 text-sm text-muted\",\n\tvariants: {\n\t\tstatus: {\n\t\t\tsuccess: \"text-status-success-fg\",\n\t\t\twarning: \"text-status-warning-fg\",\n\t\t\terror: \"text-status-error-fg\",\n\t\t\tinfo: \"text-status-info-fg\"\n\t\t},\n\t\tfocus: {\n\t\t\tlow: \"text-muted\",\n\t\t\tmedium: \"\",\n\t\t\thigh: \"\"\n\t\t}\n\t} satisfies VariantsConfig<AlertVariants>,\n\tdefaultVariants: {\n\t\tfocus: \"low\"\n\t}\n});\n\nexport type AlertDescriptionProps = React.HTMLAttributes<HTMLParagraphElement> & AlertVariants;\n\n/**\n * Компонент AlertDescription для отображения описания алерта\n */\nexport const AlertDescription = React.forwardRef<HTMLParagraphElement, AlertDescriptionProps>(\n\t({ className, focus: focusProp, status: statusProp, ...props }, ref) => {\n\t\tconst { status, focus } = useAlert({ status: statusProp, focus: focusProp });\n\n\t\treturn <div ref={ref} className={alertDescriptionStyles({ className, focus, status })} {...props} />;\n\t}\n);\n\nAlertDescription.displayName = \"AlertDescription\";\n","import { Icon, IconProps } from \"@/components/icon/Icon\";\nimport React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { useAlert } from \"../AlertContext\";\nimport { AlertVariants } from \"../Alert\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\n\ntype AlertIconVariants = Omit<AlertVariants, \"focus\">;\n\nconst alertIconStyles = tv({\n\tbase: \"text-status-default mr-3 translate-y-0.5\",\n\tvariants: {\n\t\tstatus: {\n\t\t\tsuccess: \"text-status-success-hover\",\n\t\t\twarning: \"text-status-warning-hover\",\n\t\t\terror: \"text-status-error-hover\",\n\t\t\tinfo: \"text-status-info-hover\"\n\t\t}\n\t} satisfies VariantsConfig<AlertIconVariants>\n});\n\nexport type AlertIconProps = IconProps & AlertIconVariants;\n\n/**\n * Компонент AlertIcon для отображения иконки алерта\n */\nexport const AlertIcon = React.forwardRef<SVGSVGElement, AlertIconProps>(\n\t({ className, status: statusProp, ...props }, ref) => {\n\t\tconst { status } = useAlert({ status: statusProp });\n\n\t\treturn <Icon ref={ref} className={alertIconStyles({ status, className })} {...props} />;\n\t}\n);\n\nAlertIcon.displayName = \"AlertIcon\";\n"],"names":["alertStyles","tv","Alert","React","className","status","focus","children","props","ref","contextValue","jsx","AlertContext","alertDescriptionStyles","AlertDescription","focusProp","statusProp","useAlert","alertIconStyles","AlertIcon","Icon"],"mappings":";;;;;;AAYA,MAAMA,IAAcC,EAAG;AAAA,EACtB,MAAM;AAAA,IACL;AAAA,IACA;AAAA,EACD;AAAA,EACA,UAAU;AAAA,IACT,QAAQ;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,IACP;AAAA,IACA,OAAO;AAAA,MACN,KAAK;AAAA,MACL,QAAQ;AAAA;AAAA,MAER,MAAM;AAAA,IAAA;AAAA,EAER;AAAA,EACA,kBAAkB;AAAA,IACjB;AAAA,MACC,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,IAAA;AAAA,EAET;AAAA,EACA,iBAAiB;AAAA,IAChB,OAAO;AAAA,EAAA;AAET,CAAC,GAWYC,IAAQC,EAAM;AAAA,EAC1B,CAAC,EAAE,WAAAC,GAAW,QAAAC,GAAQ,OAAAC,IAAQ,OAAO,UAAAC,GAAU,GAAGC,EAAM,GAAGC,MAAQ;AAClE,UAAMC,IAAeP,EAAM;AAAA,MAC1B,OAAO;AAAA,QACN,QAAAE;AAAA,QACA,OAAAC;AAAA,MAAA;AAAA,MAED,CAACD,GAAQC,CAAK;AAAA,IACf;AAGC,WAAA,gBAAAK,EAACC,EAAa,UAAb,EAAsB,OAAOF,GAC7B,UAAA,gBAAAC,EAAC,OAAI,EAAA,KAAAF,GAAU,MAAK,SAAQ,WAAWT,EAAY,EAAE,QAAAK,GAAQ,OAAAC,GAAO,WAAAF,EAAW,CAAA,GAAI,GAAGI,GACpF,UAAAD,EAAA,CACF,EACD,CAAA;AAAA,EAAA;AAGH;AAEAL,EAAM,cAAc;AClEpB,MAAMW,IAAyBZ,EAAG;AAAA,EACjC,MAAM;AAAA,EACN,UAAU;AAAA,IACT,QAAQ;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,IACP;AAAA,IACA,OAAO;AAAA,MACN,KAAK;AAAA,MACL,QAAQ;AAAA,MACR,MAAM;AAAA,IAAA;AAAA,EAER;AAAA,EACA,iBAAiB;AAAA,IAChB,OAAO;AAAA,EAAA;AAET,CAAC,GAOYa,IAAmBX,EAAM;AAAA,EACrC,CAAC,EAAE,WAAAC,GAAW,OAAOW,GAAW,QAAQC,GAAY,GAAGR,EAAM,GAAGC,MAAQ;AACjE,UAAA,EAAE,QAAAJ,GAAQ,OAAAC,EAAA,IAAUW,EAAS,EAAE,QAAQD,GAAY,OAAOD,GAAW;AAE3E,WAAQ,gBAAAJ,EAAA,OAAA,EAAI,KAAAF,GAAU,WAAWI,EAAuB,EAAE,WAAAT,GAAW,OAAAE,GAAO,QAAAD,EAAO,CAAC,GAAI,GAAGG,EAAO,CAAA;AAAA,EAAA;AAEpG;AAEAM,EAAiB,cAAc;AC9B/B,MAAMI,IAAkBjB,EAAG;AAAA,EAC1B,MAAM;AAAA,EACN,UAAU;AAAA,IACT,QAAQ;AAAA,MACP,SAAS;AAAA,MACT,SAAS;AAAA,MACT,OAAO;AAAA,MACP,MAAM;AAAA,IAAA;AAAA,EACP;AAEF,CAAC,GAOYkB,IAAYhB,EAAM;AAAA,EAC9B,CAAC,EAAE,WAAAC,GAAW,QAAQY,GAAY,GAAGR,KAASC,MAAQ;AACrD,UAAM,EAAE,QAAAJ,EAAO,IAAIY,EAAS,EAAE,QAAQD,GAAY;AAE3C,WAAA,gBAAAL,EAACS,GAAK,EAAA,KAAAX,GAAU,WAAWS,EAAgB,EAAE,QAAAb,GAAQ,WAAAD,EAAU,CAAC,GAAI,GAAGI,EAAO,CAAA;AAAA,EAAA;AAEvF;AAEAW,EAAU,cAAc;"}
@@ -0,0 +1,90 @@
1
+ import { jsxs as a, jsx as p } from "react/jsx-runtime";
2
+ import * as y from "react";
3
+ import { useId as b } from "react";
4
+ import { T as v } from "./index-BVqs-uqP.js";
5
+ import { F as W } from "./FieldLabel-eyKmeWRn.js";
6
+ import { D as i } from "./Description-BTPMlTT-.js";
7
+ import { c as N } from "./createLucideIcon-DwBrHnj9.js";
8
+ /**
9
+ * @license lucide-react v0.460.0 - ISC
10
+ *
11
+ * This source code is licensed under the ISC license.
12
+ * See the LICENSE file in the root directory of this source tree.
13
+ */
14
+ const F = N("CircleHelp", [
15
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
16
+ ["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3", key: "1u773s" }],
17
+ ["path", { d: "M12 17h.01", key: "p32p05" }]
18
+ ]), z = v({
19
+ slots: {
20
+ wrapper: "flex w-full space-y-0",
21
+ labelWrapper: "flex items-center justify-between gap-3",
22
+ controlWrapper: "flex w-full min-w-0 flex-1 flex-col",
23
+ error: "text-status-error"
24
+ },
25
+ variants: {
26
+ layout: {
27
+ horizontal: {
28
+ wrapper: "flex-row gap-4",
29
+ labelWrapper: "h-10 flex-col items-start gap-0.5 pb-px pt-px lg:h-9"
30
+ },
31
+ vertical: {
32
+ wrapper: "flex-col gap-2",
33
+ labelWrapper: "h-4"
34
+ },
35
+ responsive: {
36
+ wrapper: "flex-col gap-2 lg:flex-row lg:gap-4",
37
+ labelWrapper: "h-4 lg:h-9 lg:flex-col lg:items-start lg:gap-0.5 lg:pb-px lg:pt-px"
38
+ }
39
+ },
40
+ showGap: {
41
+ true: { controlWrapper: "gap-y-2" }
42
+ }
43
+ },
44
+ defaultVariants: {
45
+ layout: "horizontal"
46
+ }
47
+ }), D = y.forwardRef(
48
+ ({
49
+ title: n,
50
+ description: e,
51
+ descriptionPlacement: o = "text",
52
+ control: f,
53
+ required: m,
54
+ error: l,
55
+ className: x,
56
+ labelClassName: d,
57
+ labelSlot: h,
58
+ layout: g,
59
+ readonly: t
60
+ }, w) => {
61
+ const s = b(), c = e && o !== "icon", u = e && o === "icon", r = z({ layout: g, showGap: !!(c || l) });
62
+ return /* @__PURE__ */ a("div", { ref: w, className: r.wrapper({ className: x }), children: [
63
+ /* @__PURE__ */ a("div", { className: r.labelWrapper({ className: d }), children: [
64
+ /* @__PURE__ */ p(
65
+ W,
66
+ {
67
+ tooltip: e,
68
+ icon: u ? F : void 0,
69
+ required: !t && m,
70
+ htmlFor: s,
71
+ children: n
72
+ }
73
+ ),
74
+ h
75
+ ] }),
76
+ /* @__PURE__ */ a("div", { className: r.controlWrapper(), children: [
77
+ f({ readonly: t, id: s, error: l }),
78
+ /* @__PURE__ */ a("div", { className: "flex flex-col gap-0.5", children: [
79
+ c && /* @__PURE__ */ p(i, { size: "xs", children: e }),
80
+ l && /* @__PURE__ */ p(i, { size: "xs", className: r.error(), children: l })
81
+ ] })
82
+ ] })
83
+ ] });
84
+ }
85
+ );
86
+ D.displayName = "Field";
87
+ export {
88
+ D as F
89
+ };
90
+ //# sourceMappingURL=Field-CP_-li9L.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Field-CP_-li9L.js","sources":["../node_modules/.pnpm/lucide-react@0.460.0_react@18.3.1/node_modules/lucide-react/dist/esm/icons/circle-help.js","../src/components/field/Field.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 CircleHelp = createLucideIcon(\"CircleHelp\", [\n [\"circle\", { cx: \"12\", cy: \"12\", r: \"10\", key: \"1mglay\" }],\n [\"path\", { d: \"M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3\", key: \"1u773s\" }],\n [\"path\", { d: \"M12 17h.01\", key: \"p32p05\" }]\n]);\n\nexport { CircleHelp as default };\n//# sourceMappingURL=circle-help.js.map\n","import * as React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { CircleHelp } from \"lucide-react\";\nimport { FieldLabel } from \"@/components/label\";\nimport { Description } from \"@/components/description\";\nimport { useId } from \"react\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\n\nexport type FieldLayout = \"horizontal\" | \"vertical\" | \"responsive\";\n\nexport interface FieldVariants {\n\t/** Вариант расположения элементов поля */\n\tlayout?: FieldLayout;\n\tshowGap?: boolean;\n}\n\nconst fieldStyles = tv({\n\tslots: {\n\t\twrapper: \"flex w-full space-y-0\",\n\t\tlabelWrapper: \"flex items-center justify-between gap-3\",\n\t\tcontrolWrapper: \"flex w-full min-w-0 flex-1 flex-col\",\n\t\terror: \"text-status-error\"\n\t},\n\tvariants: {\n\t\tlayout: {\n\t\t\thorizontal: {\n\t\t\t\twrapper: \"flex-row gap-4\",\n\t\t\t\tlabelWrapper: \"h-10 flex-col items-start gap-0.5 pb-px pt-px lg:h-9\"\n\t\t\t},\n\t\t\tvertical: {\n\t\t\t\twrapper: \"flex-col gap-2\",\n\t\t\t\tlabelWrapper: \"h-4\"\n\t\t\t},\n\t\t\tresponsive: {\n\t\t\t\twrapper: \"flex-col gap-2 lg:flex-row lg:gap-4\",\n\t\t\t\tlabelWrapper: \"h-4 lg:h-9 lg:flex-col lg:items-start lg:gap-0.5 lg:pb-px lg:pt-px\"\n\t\t\t}\n\t\t},\n\t\tshowGap: {\n\t\t\ttrue: { controlWrapper: \"gap-y-2\" }\n\t\t}\n\t} satisfies VariantsConfig<FieldVariants>,\n\tdefaultVariants: {\n\t\tlayout: \"horizontal\"\n\t}\n});\n\ntype DescriptionPlacement = \"text\" | \"icon\";\n\ntype ControlProps = {\n\t/** Режим только для чтения */\n\treadonly?: boolean;\n\t/** Идентификатор элемента. Используется для связи лейбла с элементом управления */\n\tid?: string;\n\t/** Текст сообщения об ошибке. При наличии делает поле невалидным */\n\terror?: string;\n};\n\nexport type FieldProps = Omit<FieldVariants, \"showGap\"> & {\n\t/** Заголовок поля */\n\ttitle: string;\n\t/** Описание поля */\n\tdescription?: React.ReactNode;\n\t/** Режим только для чтения */\n\treadonly?: boolean;\n\t/** Расположение описания */\n\tdescriptionPlacement?: DescriptionPlacement;\n\t/** Функция рендеринга контрола */\n\tcontrol: (props: ControlProps) => React.ReactNode;\n\t/** Обязательное поле */\n\trequired?: boolean;\n\t/** Текст ошибки */\n\terror?: string;\n\t/** Дополнительные классы для контейнера */\n\tclassName?: string;\n\t/** Дополнительные классы для лейбла */\n\tlabelClassName?: string;\n\t/** Дополнительный контент в строке лейбла, выравнивается по правому краю */\n\tlabelSlot?: React.ReactNode;\n};\n\nexport const Field = React.forwardRef<HTMLDivElement, FieldProps>(\n\t(\n\t\t{\n\t\t\ttitle,\n\t\t\tdescription,\n\t\t\tdescriptionPlacement = \"text\",\n\t\t\tcontrol,\n\t\t\trequired,\n\t\t\terror,\n\t\t\tclassName,\n\t\t\tlabelClassName,\n\t\t\tlabelSlot,\n\t\t\tlayout,\n\t\t\treadonly\n\t\t},\n\t\tref\n\t) => {\n\t\tconst generatedId = useId();\n\t\tconst showTextDescription = description && descriptionPlacement !== \"icon\";\n\t\tconst showIconDescription = description && descriptionPlacement === \"icon\";\n\n\t\tconst styles = fieldStyles({ layout, showGap: !!(showTextDescription || error) });\n\n\t\treturn (\n\t\t\t<div ref={ref} className={styles.wrapper({ className })}>\n\t\t\t\t<div className={styles.labelWrapper({ className: labelClassName })}>\n\t\t\t\t\t<FieldLabel\n\t\t\t\t\t\ttooltip={description}\n\t\t\t\t\t\ticon={showIconDescription ? CircleHelp : void 0}\n\t\t\t\t\t\trequired={!readonly && required}\n\t\t\t\t\t\thtmlFor={generatedId}\n\t\t\t\t\t>\n\t\t\t\t\t\t{title}\n\t\t\t\t\t</FieldLabel>\n\t\t\t\t\t{labelSlot}\n\t\t\t\t</div>\n\n\t\t\t\t<div className={styles.controlWrapper()}>\n\t\t\t\t\t{control({ readonly, id: generatedId, error })}\n\t\t\t\t\t<div className=\"flex flex-col gap-0.5\">\n\t\t\t\t\t\t{showTextDescription && <Description size=\"xs\">{description}</Description>}\n\t\t\t\t\t\t{error && (\n\t\t\t\t\t\t\t<Description size=\"xs\" className={styles.error()}>\n\t\t\t\t\t\t\t\t{error}\n\t\t\t\t\t\t\t</Description>\n\t\t\t\t\t\t)}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nField.displayName = \"Field\";\n"],"names":["CircleHelp","createLucideIcon","fieldStyles","tv","Field","React","title","description","descriptionPlacement","control","required","error","className","labelClassName","labelSlot","layout","readonly","ref","generatedId","useId","showTextDescription","showIconDescription","styles","jsxs","jsx","FieldLabel","Description"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,MAAMA,IAAaC,EAAiB,cAAc;AAAA,EAChD,CAAC,UAAU,EAAE,IAAI,MAAM,IAAI,MAAM,GAAG,MAAM,KAAK,UAAU;AAAA,EACzD,CAAC,QAAQ,EAAE,GAAG,wCAAwC,KAAK,SAAQ,CAAE;AAAA,EACrE,CAAC,QAAQ,EAAE,GAAG,cAAc,KAAK,SAAU,CAAA;AAC7C,CAAC,GCGKC,IAAcC,EAAG;AAAA,EACtB,OAAO;AAAA,IACN,SAAS;AAAA,IACT,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,EACR;AAAA,EACA,UAAU;AAAA,IACT,QAAQ;AAAA,MACP,YAAY;AAAA,QACX,SAAS;AAAA,QACT,cAAc;AAAA,MACf;AAAA,MACA,UAAU;AAAA,QACT,SAAS;AAAA,QACT,cAAc;AAAA,MACf;AAAA,MACA,YAAY;AAAA,QACX,SAAS;AAAA,QACT,cAAc;AAAA,MAAA;AAAA,IAEhB;AAAA,IACA,SAAS;AAAA,MACR,MAAM,EAAE,gBAAgB,UAAU;AAAA,IAAA;AAAA,EAEpC;AAAA,EACA,iBAAiB;AAAA,IAChB,QAAQ;AAAA,EAAA;AAEV,CAAC,GAoCYC,IAAQC,EAAM;AAAA,EAC1B,CACC;AAAA,IACC,OAAAC;AAAA,IACA,aAAAC;AAAA,IACA,sBAAAC,IAAuB;AAAA,IACvB,SAAAC;AAAA,IACA,UAAAC;AAAA,IACA,OAAAC;AAAA,IACA,WAAAC;AAAA,IACA,gBAAAC;AAAA,IACA,WAAAC;AAAA,IACA,QAAAC;AAAA,IACA,UAAAC;AAAA,KAEDC,MACI;AACJ,UAAMC,IAAcC,EAAM,GACpBC,IAAsBb,KAAeC,MAAyB,QAC9Da,IAAsBd,KAAeC,MAAyB,QAE9Dc,IAASpB,EAAY,EAAE,QAAAa,GAAQ,SAAS,CAAC,EAAEK,KAAuBT,IAAQ;AAG/E,WAAA,gBAAAY,EAAC,SAAI,KAAAN,GAAU,WAAWK,EAAO,QAAQ,EAAE,WAAAV,GAAW,GACrD,UAAA;AAAA,MAAC,gBAAAW,EAAA,OAAA,EAAI,WAAWD,EAAO,aAAa,EAAE,WAAWT,GAAgB,GAChE,UAAA;AAAA,QAAA,gBAAAW;AAAA,UAACC;AAAA,UAAA;AAAA,YACA,SAASlB;AAAA,YACT,MAAMc,IAAsBrB,IAAa;AAAA,YACzC,UAAU,CAACgB,KAAYN;AAAA,YACvB,SAASQ;AAAA,YAER,UAAAZ;AAAA,UAAA;AAAA,QACF;AAAA,QACCQ;AAAA,MAAA,GACF;AAAA,MAEC,gBAAAS,EAAA,OAAA,EAAI,WAAWD,EAAO,eACrB,GAAA,UAAA;AAAA,QAAAb,EAAQ,EAAE,UAAAO,GAAU,IAAIE,GAAa,OAAAP,GAAO;AAAA,QAC7C,gBAAAY,EAAC,OAAI,EAAA,WAAU,yBACb,UAAA;AAAA,UAAAH,KAAwB,gBAAAI,EAAAE,GAAA,EAAY,MAAK,MAAM,UAAYnB,GAAA;AAAA,UAC3DI,uBACCe,GAAY,EAAA,MAAK,MAAK,WAAWJ,EAAO,SACvC,UACFX,EAAA,CAAA;AAAA,QAAA,EAEF,CAAA;AAAA,MAAA,EACD,CAAA;AAAA,IAAA,GACD;AAAA,EAAA;AAGH;AAEAP,EAAM,cAAc;","x_google_ignoreList":[0]}
@@ -5,7 +5,7 @@ import { T as F } from "./index-BVqs-uqP.js";
5
5
  import { d as T, e as N, b as v, a as b } from "./FormHeader--F6b2aRk.js";
6
6
  import { B as h } from "./Button-Dg89xRSi.js";
7
7
  import { a as k } from "./CheckboxField-2zNFubvm.js";
8
- import { e as y } from "./useBreakpoints-D8wKOvil.js";
8
+ import { e as y } from "./useBreakpoints-DHvp74UL.js";
9
9
  const H = F({
10
10
  slots: {
11
11
  header: "flex items-start gap-4",
@@ -85,4 +85,4 @@ export {
85
85
  z as F,
86
86
  R as a
87
87
  };
88
- //# sourceMappingURL=FormFooterTemplate-ClTxqrIB.js.map
88
+ //# sourceMappingURL=FormFooterTemplate-Cfn5Nmge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormFooterTemplate-ClTxqrIB.js","sources":["../src/components/form/templates/header-template/FormHeaderTemplate.tsx","../src/components/form/templates/footer-template/FormFooterTemplate.tsx"],"sourcesContent":["import { FeatureIcon } from \"@/components/icon/feature-icon/FeatureIcon\";\nimport { LucideIcon } from \"lucide-react\";\nimport React, { HTMLAttributes, PropsWithChildren } from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { FormDescription, FormHeader, FormTitle } from \"../../components/form-header/FormHeader\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\n\nexport interface FormHeaderTemplateVariants {\n\talignment?: \"compact\" | \"left\" | \"center\";\n}\n\nconst formHeaderTemplateStyles = tv({\n\tslots: {\n\t\theader: \"flex items-start gap-4\",\n\t\tcontentWrapper: \"flex flex-col gap-px lg:gap-1.5\",\n\t\ticon: \"flex-shrink-0 rounded-lg ring-0\"\n\t},\n\tvariants: {\n\t\talignment: {\n\t\t\tcompact: {\n\t\t\t\theader: \"flex-row pr-9\"\n\t\t\t},\n\t\t\tleft: {\n\t\t\t\theader: \"flex-col gap-2 lg:gap-4\",\n\t\t\t\tcontentWrapper: \"gap-0.5 lg:gap-1\"\n\t\t\t},\n\t\t\tcenter: {\n\t\t\t\theader: \"flex-col items-center gap-2 text-center lg:gap-4\",\n\t\t\t\tcontentWrapper: \"gap-0.5 lg:gap-1\"\n\t\t\t}\n\t\t}\n\t} satisfies VariantsConfig<FormHeaderTemplateVariants>,\n\tdefaultVariants: {\n\t\talignment: \"compact\"\n\t}\n});\n\nexport type BaseHeaderTemplateProps = Omit<HTMLAttributes<HTMLDivElement>, \"title\"> &\n\tFormHeaderTemplateVariants & {\n\t\t/** Заголовок формы */\n\t\ttitle: React.ReactNode;\n\t\t/** Описание формы */\n\t\tdescription?: React.ReactNode;\n\t\t/** Иконка заголовка */\n\t\ticon?: LucideIcon;\n\t\t/** Кастомная иконка заголовка */\n\t\tcustomIcon?: React.ReactNode;\n\t};\n\nexport const BaseHeaderTemplate = React.forwardRef<HTMLDivElement, PropsWithChildren<BaseHeaderTemplateProps>>(\n\t({ className, icon: Icon, title, alignment, description, customIcon, ...props }, ref) => {\n\t\tconst { header, contentWrapper, icon } = formHeaderTemplateStyles({ alignment });\n\n\t\treturn (\n\t\t\t<FormHeader ref={ref} className={header({ class: className })} {...props}>\n\t\t\t\t{Icon && <FeatureIcon size=\"xl\" icon={Icon} className={icon()} />}\n\t\t\t\t{customIcon && customIcon}\n\t\t\t\t<div className={contentWrapper()}>\n\t\t\t\t\t{title}\n\t\t\t\t\t{description}\n\t\t\t\t</div>\n\t\t\t</FormHeader>\n\t\t);\n\t}\n);\n\n/**\n * Темплейт заголовка формы. Содержит иконку, заголовок и описание.\n * Имеет различные варианты расположения элементов\n */\nexport const FormHeaderTemplate = React.forwardRef<HTMLDivElement, PropsWithChildren<BaseHeaderTemplateProps>>(\n\t({ title, description, ...props }, ref) => {\n\t\treturn (\n\t\t\t<BaseHeaderTemplate\n\t\t\t\ttitle={<FormTitle>{title}</FormTitle>}\n\t\t\t\tdescription={<FormDescription>{description}</FormDescription>}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t}\n);\n\nFormHeaderTemplate.displayName = \"FormHeaderTemplate\";\n","import { Button, ButtonProps } from \"@/components/button/button/Button\";\nimport { CheckboxField, CheckboxFieldProps } from \"@/components/checkbox/checkbox-field/CheckboxField\";\nimport { useIsMobile } from \"@/hooks/useBreakpoints\";\nimport React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { FormFooter } from \"../../components/form-footer/FormFooter\";\n\nconst formFooterTemplateStyles = tv({\n\tslots: {\n\t\tcontainer: \"flex w-full flex-col gap-3 lg:flex-row\",\n\t\tstartBlock: \"flex items-center py-1 lg:py-2.5\",\n\t\tendBlock: \"ml-auto flex w-full flex-col gap-3 lg:w-auto lg:flex-row\"\n\t}\n});\n\nexport interface FormFooterTemplateProps {\n\t/** Дополнительные классы */\n\tclassName?: string;\n\t/** Текст для чекбокса */\n\tcheckboxLabel?: string;\n\t/** Пропсы для чекбокса */\n\tcheckboxProps?: CheckboxFieldProps;\n\t/** Основная кнопка */\n\tprimaryButton?: React.ReactNode;\n\t/** Пропсы для основной кнопки */\n\tprimaryButtonProps?: ButtonProps;\n\t/** Вторичная кнопка */\n\tsecondaryButton?: React.ReactNode;\n\t/** Пропсы для вторичной кнопки */\n\tsecondaryButtonProps?: ButtonProps;\n}\n\n/**\n * Темплейт футера формы. Содержит чекбокс и 2 кнопки, которыми можно управлять.\n * Адаптивен к размерам устройств\n */\nexport const FormFooterTemplate = React.forwardRef<HTMLDivElement, FormFooterTemplateProps>(\n\t(\n\t\t{\n\t\t\tclassName,\n\t\t\tprimaryButton,\n\t\t\tsecondaryButton,\n\t\t\tcheckboxLabel,\n\t\t\tcheckboxProps,\n\t\t\tprimaryButtonProps,\n\t\t\tsecondaryButtonProps\n\t\t},\n\t\tref\n\t) => {\n\t\tconst isMobile = useIsMobile();\n\t\tconst { container, startBlock, endBlock } = formFooterTemplateStyles();\n\n\t\tif (isMobile) {\n\t\t\tprimaryButtonProps = { ...primaryButtonProps, size: \"xl\" };\n\t\t\tsecondaryButtonProps = { ...secondaryButtonProps, size: \"xl\" };\n\t\t}\n\t\tconst primaryButtonElement = primaryButton && (\n\t\t\t<Button key=\"primary-button\" variant=\"primary\" {...primaryButtonProps}>\n\t\t\t\t{primaryButton}\n\t\t\t</Button>\n\t\t);\n\n\t\tconst secondaryButtonElement = secondaryButton && (\n\t\t\t<Button key=\"secondary-button\" variant=\"outline\" {...secondaryButtonProps}>\n\t\t\t\t{secondaryButton}\n\t\t\t</Button>\n\t\t);\n\n\t\treturn (\n\t\t\t<FormFooter className={className} ref={ref}>\n\t\t\t\t<div className={container()}>\n\t\t\t\t\t{checkboxLabel && (\n\t\t\t\t\t\t<div className={startBlock()}>\n\t\t\t\t\t\t\t<CheckboxField label={checkboxLabel} {...checkboxProps} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div className={endBlock()}>\n\t\t\t\t\t\t{isMobile\n\t\t\t\t\t\t\t? [primaryButtonElement, secondaryButtonElement]\n\t\t\t\t\t\t\t: [secondaryButtonElement, primaryButtonElement]}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</FormFooter>\n\t\t);\n\t}\n);\n\nFormFooterTemplate.displayName = \"FormFooterTemplate\";\n"],"names":["formHeaderTemplateStyles","tv","BaseHeaderTemplate","React","className","Icon","title","alignment","description","customIcon","props","ref","header","contentWrapper","icon","jsxs","FormHeader","jsx","FeatureIcon","FormHeaderTemplate","FormTitle","FormDescription","formFooterTemplateStyles","FormFooterTemplate","primaryButton","secondaryButton","checkboxLabel","checkboxProps","primaryButtonProps","secondaryButtonProps","isMobile","useIsMobile","container","startBlock","endBlock","primaryButtonElement","Button","secondaryButtonElement","FormFooter","CheckboxField"],"mappings":"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"}
1
+ {"version":3,"file":"FormFooterTemplate-Cfn5Nmge.js","sources":["../src/components/form/templates/header-template/FormHeaderTemplate.tsx","../src/components/form/templates/footer-template/FormFooterTemplate.tsx"],"sourcesContent":["import { FeatureIcon } from \"@/components/icon/feature-icon/FeatureIcon\";\nimport { LucideIcon } from \"lucide-react\";\nimport React, { HTMLAttributes, PropsWithChildren } from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { FormDescription, FormHeader, FormTitle } from \"../../components/form-header/FormHeader\";\nimport { VariantsConfig } from \"@/lib/utils/variants\";\n\nexport interface FormHeaderTemplateVariants {\n\talignment?: \"compact\" | \"left\" | \"center\";\n}\n\nconst formHeaderTemplateStyles = tv({\n\tslots: {\n\t\theader: \"flex items-start gap-4\",\n\t\tcontentWrapper: \"flex flex-col gap-px lg:gap-1.5\",\n\t\ticon: \"flex-shrink-0 rounded-lg ring-0\"\n\t},\n\tvariants: {\n\t\talignment: {\n\t\t\tcompact: {\n\t\t\t\theader: \"flex-row pr-9\"\n\t\t\t},\n\t\t\tleft: {\n\t\t\t\theader: \"flex-col gap-2 lg:gap-4\",\n\t\t\t\tcontentWrapper: \"gap-0.5 lg:gap-1\"\n\t\t\t},\n\t\t\tcenter: {\n\t\t\t\theader: \"flex-col items-center gap-2 text-center lg:gap-4\",\n\t\t\t\tcontentWrapper: \"gap-0.5 lg:gap-1\"\n\t\t\t}\n\t\t}\n\t} satisfies VariantsConfig<FormHeaderTemplateVariants>,\n\tdefaultVariants: {\n\t\talignment: \"compact\"\n\t}\n});\n\nexport type BaseHeaderTemplateProps = Omit<HTMLAttributes<HTMLDivElement>, \"title\"> &\n\tFormHeaderTemplateVariants & {\n\t\t/** Заголовок формы */\n\t\ttitle: React.ReactNode;\n\t\t/** Описание формы */\n\t\tdescription?: React.ReactNode;\n\t\t/** Иконка заголовка */\n\t\ticon?: LucideIcon;\n\t\t/** Кастомная иконка заголовка */\n\t\tcustomIcon?: React.ReactNode;\n\t};\n\nexport const BaseHeaderTemplate = React.forwardRef<HTMLDivElement, PropsWithChildren<BaseHeaderTemplateProps>>(\n\t({ className, icon: Icon, title, alignment, description, customIcon, ...props }, ref) => {\n\t\tconst { header, contentWrapper, icon } = formHeaderTemplateStyles({ alignment });\n\n\t\treturn (\n\t\t\t<FormHeader ref={ref} className={header({ class: className })} {...props}>\n\t\t\t\t{Icon && <FeatureIcon size=\"xl\" icon={Icon} className={icon()} />}\n\t\t\t\t{customIcon && customIcon}\n\t\t\t\t<div className={contentWrapper()}>\n\t\t\t\t\t{title}\n\t\t\t\t\t{description}\n\t\t\t\t</div>\n\t\t\t</FormHeader>\n\t\t);\n\t}\n);\n\n/**\n * Темплейт заголовка формы. Содержит иконку, заголовок и описание.\n * Имеет различные варианты расположения элементов\n */\nexport const FormHeaderTemplate = React.forwardRef<HTMLDivElement, PropsWithChildren<BaseHeaderTemplateProps>>(\n\t({ title, description, ...props }, ref) => {\n\t\treturn (\n\t\t\t<BaseHeaderTemplate\n\t\t\t\ttitle={<FormTitle>{title}</FormTitle>}\n\t\t\t\tdescription={<FormDescription>{description}</FormDescription>}\n\t\t\t\tref={ref}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t}\n);\n\nFormHeaderTemplate.displayName = \"FormHeaderTemplate\";\n","import { Button, ButtonProps } from \"@/components/button/button/Button\";\nimport { CheckboxField, CheckboxFieldProps } from \"@/components/checkbox/checkbox-field/CheckboxField\";\nimport { useIsMobile } from \"@/hooks/useBreakpoints\";\nimport React from \"react\";\nimport { tv } from \"tailwind-variants\";\nimport { FormFooter } from \"../../components/form-footer/FormFooter\";\n\nconst formFooterTemplateStyles = tv({\n\tslots: {\n\t\tcontainer: \"flex w-full flex-col gap-3 lg:flex-row\",\n\t\tstartBlock: \"flex items-center py-1 lg:py-2.5\",\n\t\tendBlock: \"ml-auto flex w-full flex-col gap-3 lg:w-auto lg:flex-row\"\n\t}\n});\n\nexport interface FormFooterTemplateProps {\n\t/** Дополнительные классы */\n\tclassName?: string;\n\t/** Текст для чекбокса */\n\tcheckboxLabel?: string;\n\t/** Пропсы для чекбокса */\n\tcheckboxProps?: CheckboxFieldProps;\n\t/** Основная кнопка */\n\tprimaryButton?: React.ReactNode;\n\t/** Пропсы для основной кнопки */\n\tprimaryButtonProps?: ButtonProps;\n\t/** Вторичная кнопка */\n\tsecondaryButton?: React.ReactNode;\n\t/** Пропсы для вторичной кнопки */\n\tsecondaryButtonProps?: ButtonProps;\n}\n\n/**\n * Темплейт футера формы. Содержит чекбокс и 2 кнопки, которыми можно управлять.\n * Адаптивен к размерам устройств\n */\nexport const FormFooterTemplate = React.forwardRef<HTMLDivElement, FormFooterTemplateProps>(\n\t(\n\t\t{\n\t\t\tclassName,\n\t\t\tprimaryButton,\n\t\t\tsecondaryButton,\n\t\t\tcheckboxLabel,\n\t\t\tcheckboxProps,\n\t\t\tprimaryButtonProps,\n\t\t\tsecondaryButtonProps\n\t\t},\n\t\tref\n\t) => {\n\t\tconst isMobile = useIsMobile();\n\t\tconst { container, startBlock, endBlock } = formFooterTemplateStyles();\n\n\t\tif (isMobile) {\n\t\t\tprimaryButtonProps = { ...primaryButtonProps, size: \"xl\" };\n\t\t\tsecondaryButtonProps = { ...secondaryButtonProps, size: \"xl\" };\n\t\t}\n\t\tconst primaryButtonElement = primaryButton && (\n\t\t\t<Button key=\"primary-button\" variant=\"primary\" {...primaryButtonProps}>\n\t\t\t\t{primaryButton}\n\t\t\t</Button>\n\t\t);\n\n\t\tconst secondaryButtonElement = secondaryButton && (\n\t\t\t<Button key=\"secondary-button\" variant=\"outline\" {...secondaryButtonProps}>\n\t\t\t\t{secondaryButton}\n\t\t\t</Button>\n\t\t);\n\n\t\treturn (\n\t\t\t<FormFooter className={className} ref={ref}>\n\t\t\t\t<div className={container()}>\n\t\t\t\t\t{checkboxLabel && (\n\t\t\t\t\t\t<div className={startBlock()}>\n\t\t\t\t\t\t\t<CheckboxField label={checkboxLabel} {...checkboxProps} />\n\t\t\t\t\t\t</div>\n\t\t\t\t\t)}\n\t\t\t\t\t<div className={endBlock()}>\n\t\t\t\t\t\t{isMobile\n\t\t\t\t\t\t\t? [primaryButtonElement, secondaryButtonElement]\n\t\t\t\t\t\t\t: [secondaryButtonElement, primaryButtonElement]}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</FormFooter>\n\t\t);\n\t}\n);\n\nFormFooterTemplate.displayName = \"FormFooterTemplate\";\n"],"names":["formHeaderTemplateStyles","tv","BaseHeaderTemplate","React","className","Icon","title","alignment","description","customIcon","props","ref","header","contentWrapper","icon","jsxs","FormHeader","jsx","FeatureIcon","FormHeaderTemplate","FormTitle","FormDescription","formFooterTemplateStyles","FormFooterTemplate","primaryButton","secondaryButton","checkboxLabel","checkboxProps","primaryButtonProps","secondaryButtonProps","isMobile","useIsMobile","container","startBlock","endBlock","primaryButtonElement","Button","secondaryButtonElement","FormFooter","CheckboxField"],"mappings":"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"}
@@ -5,7 +5,7 @@ import $ from "react";
5
5
  import { S as F } from "./index-BtQfgaSF.js";
6
6
  import { T as d } from "./index-BVqs-uqP.js";
7
7
  import { F as M } from "./FieldLabel-eyKmeWRn.js";
8
- import { F as k } from "./Field-COD9VbUX.js";
8
+ import { F as k } from "./Field-CP_-li9L.js";
9
9
  const L = d({
10
10
  base: "rounded-md border border-secondary-border bg-secondary-bg"
11
11
  }), Q = ({
@@ -124,4 +124,4 @@ export {
124
124
  U as g,
125
125
  l as u
126
126
  };
127
- //# sourceMappingURL=FormStack-B3UBh9oF.js.map
127
+ //# sourceMappingURL=FormStack-Cc_ELdWL.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormStack-B3UBh9oF.js","sources":["../src/components/form/Form.tsx","../src/components/form/components/form-field/FormField.tsx","../src/components/form/components/form-stack/FormStack.tsx"],"sourcesContent":["import * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport {\n\tController,\n\tFormProvider,\n\tuseFormContext,\n\ttype ControllerProps,\n\ttype FieldPath,\n\ttype FieldValues\n} from \"react-hook-form\";\nimport { tv } from \"tailwind-variants\";\nimport { FieldLabel } from \"../label/field-label/FieldLabel\";\n\nconst formStyle = tv({\n\tbase: \"rounded-md border border-secondary-border bg-secondary-bg\"\n});\n\n/**\n * Основной контейнер формы\n */\nconst Form = <T extends FieldValues>({\n\tclassName,\n\tasChild,\n\t...props\n}: React.ComponentProps<typeof FormProvider<T>> & {\n\t/** Дополнительные классы */\n\tclassName?: string;\n\t/** Использовать ли дочерний элемент как корневой */\n\tasChild?: boolean;\n}) => {\n\tconst Comp = asChild ? Slot : \"div\";\n\treturn (\n\t\t<Comp className={formStyle({ className })}>\n\t\t\t<FormProvider {...props} />\n\t\t</Comp>\n\t);\n};\n\ntype FormFieldContextValue<\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n\tname: TName;\n};\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);\n\n/**\n * Поле формы с валидацией\n */\n\nconst FormField = <\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n\t...props\n}: ControllerProps<TFieldValues, TName>) => {\n\treturn (\n\t\t<FormFieldContext.Provider value={{ name: props.name }}>\n\t\t\t<Controller {...props} />\n\t\t</FormFieldContext.Provider>\n\t);\n};\n\nconst useFormField = () => {\n\tconst fieldContext = React.useContext(FormFieldContext);\n\tconst itemContext = React.useContext(FormItemContext);\n\tconst { getFieldState, formState } = useFormContext();\n\n\tconst fieldState = getFieldState(fieldContext.name, formState);\n\n\tif (!fieldContext) {\n\t\tthrow new Error(\"useFormField should be used within <FormField>\");\n\t}\n\n\tconst { id } = itemContext;\n\n\treturn {\n\t\tid,\n\t\tname: fieldContext.name,\n\t\tformItemId: `${id}-form-item`,\n\t\tformDescriptionId: `${id}-form-item-description`,\n\t\tformMessageId: `${id}-form-item-message`,\n\t\t...fieldState\n\t};\n};\n\ntype FormItemContextValue = {\n\tid: string;\n};\n\nconst FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);\n\nconst formItemStyle = tv({\n\tbase: \"space-y-2\"\n});\n\n/**\n * Контейнер для элементов формы\n */\nconst FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, ...props }, ref) => {\n\t\tconst id = React.useId();\n\n\t\treturn (\n\t\t\t<FormItemContext.Provider value={{ id }}>\n\t\t\t\t<div ref={ref} className={formItemStyle({ className })} {...props} />\n\t\t\t</FormItemContext.Provider>\n\t\t);\n\t}\n);\nFormItem.displayName = \"FormItem\";\n\ninterface FormLabelProps extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n\t/** Обязательное ли поле */\n\trequired?: boolean;\n}\n\n/**\n * Лейбл для поля формы\n */\nconst FormLabel = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, FormLabelProps>(\n\t({ className, required, ...props }, ref) => {\n\t\tconst { formItemId } = useFormField();\n\n\t\treturn <FieldLabel required={required} ref={ref} className={className} htmlFor={formItemId} {...props} />;\n\t}\n);\nFormLabel.displayName = \"FormLabel\";\n\n/**\n * Контрол для поля формы\n */\nconst FormControl = React.forwardRef<React.ElementRef<typeof Slot>, React.ComponentPropsWithoutRef<typeof Slot>>(\n\t({ ...props }, ref) => {\n\t\tconst { error, formItemId, formDescriptionId, formMessageId } = useFormField();\n\n\t\treturn (\n\t\t\t<Slot\n\t\t\t\tref={ref}\n\t\t\t\tid={formItemId}\n\t\t\t\taria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}\n\t\t\t\taria-invalid={!!error}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t}\n);\nFormControl.displayName = \"FormControl\";\n\nconst formMessageStyle = tv({\n\tbase: \"text-[0.8rem] font-medium text-destructive\"\n});\n\n/**\n * Сообщение об ошибке\n */\nconst FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(\n\t({ className, children, ...props }, ref) => {\n\t\tconst { error, formMessageId } = useFormField();\n\t\tconst body = error ? String(error?.message ?? \"\") : children;\n\n\t\tif (!body) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn (\n\t\t\t<p ref={ref} id={formMessageId} className={formMessageStyle({ className })} {...props}>\n\t\t\t\t{body}\n\t\t\t</p>\n\t\t);\n\t}\n);\nFormMessage.displayName = \"FormMessage\";\n\nexport { useFormField, Form, FormItem, FormLabel, FormControl, FormMessage, FormField as FormFieldControl };\n","import * as React from \"react\";\nimport {\n\tuseFormContext,\n\ttype FieldPath,\n\ttype FieldValues,\n\ttype ControllerRenderProps,\n\ttype UseFormStateReturn,\n\ttype ControllerFieldState,\n\tPath\n} from \"react-hook-form\";\nimport { FormFieldControl, FormItem, FormControl } from \"../../Form\";\nimport { Field, FieldLayout } from \"@/components/field/Field\";\nimport { tv } from \"tailwind-variants\";\n\nconst formFieldStyles = tv({\n\tslots: {\n\t\tlabel: \"w-44\"\n\t}\n});\n\nexport type FormFieldControlRenderer<TFieldValues extends FieldValues = FieldValues> = (props: {\n\tfield: ControllerRenderProps<TFieldValues, Path<TFieldValues>>;\n\tfieldState: ControllerFieldState;\n\tformState: UseFormStateReturn<TFieldValues>;\n\treadonly?: boolean;\n}) => React.ReactNode;\n\nexport interface FormFieldProps<\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> {\n\t/** Имя поля формы */\n\tname: TName;\n\t/** Заголовок поля (лейбл) */\n\ttitle: string;\n\t/** Описание поля */\n\tdescription?: string;\n\t/** Функция рендеринга контрола */\n\tcontrol: FormFieldControlRenderer<TFieldValues>;\n\t/** Является ли поле обязательным */\n\trequired?: boolean;\n\t/** Дополнительные классы */\n\tclassName?: string;\n\t/** Классы для лейбла */\n\tlabelClassName?: string;\n\t/** Поле только для чтения */\n\treadonly?: boolean;\n\t/** Вариант расположения элементов поля */\n\tlayout?: FieldLayout;\n}\n\n/**\n * Компонент FormField объединяет несколько компонентов формы в один блок\n * для упрощения создания консистентных форм.\n *\n * ### Варианты раскладки (layout):\n *\n * - **responsive** (по умолчанию): адаптивная раскладка с mobile-first подходом.\n * На мобильных устройствах - вертикальный лейаут, на десктопе (от lg breakpoint) - горизонтальный.\n *\n * - **horizontal**: принудительно горизонтальная раскладка на всех экранах.\n * Лейбл располагается слева от поля ввода.\n *\n * - **vertical**: принудительно вертикальная раскладка на всех экранах.\n * Лейбл располагается над полем ввода.\n *\n * Компонент обеспечивает согласованное расположение элементов формы,\n * включая лейбл, поле ввода, подсказку и сообщение об ошибке.\n *\n * @example\n * <FormField\n * name=\"username\"\n * title=\"Имя пользователя\"\n * description=\"Ваше публичное имя пользователя\"\n * required\n * control={({ field }) => (\n * <TextInput\n * placeholder=\"Введите имя пользователя\"\n * startIcon={<Icon icon={User} />}\n * {...field}\n * />\n * )}\n * />\n */\n\nexport function FormField<\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n\tname,\n\ttitle,\n\tdescription,\n\tcontrol,\n\trequired,\n\tclassName,\n\tlabelClassName,\n\treadonly,\n\tlayout = \"responsive\"\n}: FormFieldProps<TFieldValues, TName>) {\n\tconst form = useFormContext<TFieldValues>();\n\tconst styles = formFieldStyles();\n\n\treturn (\n\t\t<FormFieldControl\n\t\t\tcontrol={form.control}\n\t\t\tname={name}\n\t\t\trender={({ field, fieldState, formState }) => {\n\t\t\t\treturn (\n\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t<Field\n\t\t\t\t\t\t\ttitle={title}\n\t\t\t\t\t\t\tdescription={description}\n\t\t\t\t\t\t\trequired={required}\n\t\t\t\t\t\t\terror={fieldState.error?.message}\n\t\t\t\t\t\t\tlabelClassName={styles.label({ className: labelClassName })}\n\t\t\t\t\t\t\tclassName={className}\n\t\t\t\t\t\t\treadonly={readonly}\n\t\t\t\t\t\t\tlayout={layout}\n\t\t\t\t\t\t\tcontrol={({ id, readonly }) => (\n\t\t\t\t\t\t\t\t<FormControl id={id}>{control({ field, fieldState, formState, readonly })}</FormControl>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</FormItem>\n\t\t\t\t);\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nconst formStackStyles = tv({\n\tbase: \"space-y-5 lg:space-y-4\"\n});\n\n/** Оболочка для группы полей формы с внутренними отступами */\nexport const FormStack = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, children, ...props }, ref) => {\n\t\treturn (\n\t\t\t<div ref={ref} className={formStackStyles({ className })} {...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nFormStack.displayName = \"FormStack\";\n"],"names":["formStyle","tv","Form","className","asChild","props","jsx","Slot","FormProvider","FormFieldContext","React","FormField","Controller","useFormField","fieldContext","itemContext","FormItemContext","getFieldState","formState","useFormContext","fieldState","id","formItemStyle","FormItem","ref","FormLabel","required","formItemId","FieldLabel","FormControl","error","formDescriptionId","formMessageId","formMessageStyle","FormMessage","children","body","formFieldStyles","name","title","description","control","labelClassName","readonly","layout","form","styles","FormFieldControl","field","Field","formStackStyles","FormStack"],"mappings":"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"}
1
+ {"version":3,"file":"FormStack-Cc_ELdWL.js","sources":["../src/components/form/Form.tsx","../src/components/form/components/form-field/FormField.tsx","../src/components/form/components/form-stack/FormStack.tsx"],"sourcesContent":["import * as React from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport {\n\tController,\n\tFormProvider,\n\tuseFormContext,\n\ttype ControllerProps,\n\ttype FieldPath,\n\ttype FieldValues\n} from \"react-hook-form\";\nimport { tv } from \"tailwind-variants\";\nimport { FieldLabel } from \"../label/field-label/FieldLabel\";\n\nconst formStyle = tv({\n\tbase: \"rounded-md border border-secondary-border bg-secondary-bg\"\n});\n\n/**\n * Основной контейнер формы\n */\nconst Form = <T extends FieldValues>({\n\tclassName,\n\tasChild,\n\t...props\n}: React.ComponentProps<typeof FormProvider<T>> & {\n\t/** Дополнительные классы */\n\tclassName?: string;\n\t/** Использовать ли дочерний элемент как корневой */\n\tasChild?: boolean;\n}) => {\n\tconst Comp = asChild ? Slot : \"div\";\n\treturn (\n\t\t<Comp className={formStyle({ className })}>\n\t\t\t<FormProvider {...props} />\n\t\t</Comp>\n\t);\n};\n\ntype FormFieldContextValue<\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = {\n\tname: TName;\n};\n\nconst FormFieldContext = React.createContext<FormFieldContextValue>({} as FormFieldContextValue);\n\n/**\n * Поле формы с валидацией\n */\n\nconst FormField = <\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n\t...props\n}: ControllerProps<TFieldValues, TName>) => {\n\treturn (\n\t\t<FormFieldContext.Provider value={{ name: props.name }}>\n\t\t\t<Controller {...props} />\n\t\t</FormFieldContext.Provider>\n\t);\n};\n\nconst useFormField = () => {\n\tconst fieldContext = React.useContext(FormFieldContext);\n\tconst itemContext = React.useContext(FormItemContext);\n\tconst { getFieldState, formState } = useFormContext();\n\n\tconst fieldState = getFieldState(fieldContext.name, formState);\n\n\tif (!fieldContext) {\n\t\tthrow new Error(\"useFormField should be used within <FormField>\");\n\t}\n\n\tconst { id } = itemContext;\n\n\treturn {\n\t\tid,\n\t\tname: fieldContext.name,\n\t\tformItemId: `${id}-form-item`,\n\t\tformDescriptionId: `${id}-form-item-description`,\n\t\tformMessageId: `${id}-form-item-message`,\n\t\t...fieldState\n\t};\n};\n\ntype FormItemContextValue = {\n\tid: string;\n};\n\nconst FormItemContext = React.createContext<FormItemContextValue>({} as FormItemContextValue);\n\nconst formItemStyle = tv({\n\tbase: \"space-y-2\"\n});\n\n/**\n * Контейнер для элементов формы\n */\nconst FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, ...props }, ref) => {\n\t\tconst id = React.useId();\n\n\t\treturn (\n\t\t\t<FormItemContext.Provider value={{ id }}>\n\t\t\t\t<div ref={ref} className={formItemStyle({ className })} {...props} />\n\t\t\t</FormItemContext.Provider>\n\t\t);\n\t}\n);\nFormItem.displayName = \"FormItem\";\n\ninterface FormLabelProps extends React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> {\n\t/** Обязательное ли поле */\n\trequired?: boolean;\n}\n\n/**\n * Лейбл для поля формы\n */\nconst FormLabel = React.forwardRef<React.ElementRef<typeof LabelPrimitive.Root>, FormLabelProps>(\n\t({ className, required, ...props }, ref) => {\n\t\tconst { formItemId } = useFormField();\n\n\t\treturn <FieldLabel required={required} ref={ref} className={className} htmlFor={formItemId} {...props} />;\n\t}\n);\nFormLabel.displayName = \"FormLabel\";\n\n/**\n * Контрол для поля формы\n */\nconst FormControl = React.forwardRef<React.ElementRef<typeof Slot>, React.ComponentPropsWithoutRef<typeof Slot>>(\n\t({ ...props }, ref) => {\n\t\tconst { error, formItemId, formDescriptionId, formMessageId } = useFormField();\n\n\t\treturn (\n\t\t\t<Slot\n\t\t\t\tref={ref}\n\t\t\t\tid={formItemId}\n\t\t\t\taria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}\n\t\t\t\taria-invalid={!!error}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t);\n\t}\n);\nFormControl.displayName = \"FormControl\";\n\nconst formMessageStyle = tv({\n\tbase: \"text-[0.8rem] font-medium text-destructive\"\n});\n\n/**\n * Сообщение об ошибке\n */\nconst FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(\n\t({ className, children, ...props }, ref) => {\n\t\tconst { error, formMessageId } = useFormField();\n\t\tconst body = error ? String(error?.message ?? \"\") : children;\n\n\t\tif (!body) {\n\t\t\treturn null;\n\t\t}\n\n\t\treturn (\n\t\t\t<p ref={ref} id={formMessageId} className={formMessageStyle({ className })} {...props}>\n\t\t\t\t{body}\n\t\t\t</p>\n\t\t);\n\t}\n);\nFormMessage.displayName = \"FormMessage\";\n\nexport { useFormField, Form, FormItem, FormLabel, FormControl, FormMessage, FormField as FormFieldControl };\n","import * as React from \"react\";\nimport {\n\tuseFormContext,\n\ttype FieldPath,\n\ttype FieldValues,\n\ttype ControllerRenderProps,\n\ttype UseFormStateReturn,\n\ttype ControllerFieldState,\n\tPath\n} from \"react-hook-form\";\nimport { FormFieldControl, FormItem, FormControl } from \"../../Form\";\nimport { Field, FieldLayout } from \"@/components/field/Field\";\nimport { tv } from \"tailwind-variants\";\n\nconst formFieldStyles = tv({\n\tslots: {\n\t\tlabel: \"w-44\"\n\t}\n});\n\nexport type FormFieldControlRenderer<TFieldValues extends FieldValues = FieldValues> = (props: {\n\tfield: ControllerRenderProps<TFieldValues, Path<TFieldValues>>;\n\tfieldState: ControllerFieldState;\n\tformState: UseFormStateReturn<TFieldValues>;\n\treadonly?: boolean;\n}) => React.ReactNode;\n\nexport interface FormFieldProps<\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> {\n\t/** Имя поля формы */\n\tname: TName;\n\t/** Заголовок поля (лейбл) */\n\ttitle: string;\n\t/** Описание поля */\n\tdescription?: string;\n\t/** Функция рендеринга контрола */\n\tcontrol: FormFieldControlRenderer<TFieldValues>;\n\t/** Является ли поле обязательным */\n\trequired?: boolean;\n\t/** Дополнительные классы */\n\tclassName?: string;\n\t/** Классы для лейбла */\n\tlabelClassName?: string;\n\t/** Поле только для чтения */\n\treadonly?: boolean;\n\t/** Вариант расположения элементов поля */\n\tlayout?: FieldLayout;\n}\n\n/**\n * Компонент FormField объединяет несколько компонентов формы в один блок\n * для упрощения создания консистентных форм.\n *\n * ### Варианты раскладки (layout):\n *\n * - **responsive** (по умолчанию): адаптивная раскладка с mobile-first подходом.\n * На мобильных устройствах - вертикальный лейаут, на десктопе (от lg breakpoint) - горизонтальный.\n *\n * - **horizontal**: принудительно горизонтальная раскладка на всех экранах.\n * Лейбл располагается слева от поля ввода.\n *\n * - **vertical**: принудительно вертикальная раскладка на всех экранах.\n * Лейбл располагается над полем ввода.\n *\n * Компонент обеспечивает согласованное расположение элементов формы,\n * включая лейбл, поле ввода, подсказку и сообщение об ошибке.\n *\n * @example\n * <FormField\n * name=\"username\"\n * title=\"Имя пользователя\"\n * description=\"Ваше публичное имя пользователя\"\n * required\n * control={({ field }) => (\n * <TextInput\n * placeholder=\"Введите имя пользователя\"\n * startIcon={<Icon icon={User} />}\n * {...field}\n * />\n * )}\n * />\n */\n\nexport function FormField<\n\tTFieldValues extends FieldValues = FieldValues,\n\tTName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n>({\n\tname,\n\ttitle,\n\tdescription,\n\tcontrol,\n\trequired,\n\tclassName,\n\tlabelClassName,\n\treadonly,\n\tlayout = \"responsive\"\n}: FormFieldProps<TFieldValues, TName>) {\n\tconst form = useFormContext<TFieldValues>();\n\tconst styles = formFieldStyles();\n\n\treturn (\n\t\t<FormFieldControl\n\t\t\tcontrol={form.control}\n\t\t\tname={name}\n\t\t\trender={({ field, fieldState, formState }) => {\n\t\t\t\treturn (\n\t\t\t\t\t<FormItem>\n\t\t\t\t\t\t<Field\n\t\t\t\t\t\t\ttitle={title}\n\t\t\t\t\t\t\tdescription={description}\n\t\t\t\t\t\t\trequired={required}\n\t\t\t\t\t\t\terror={fieldState.error?.message}\n\t\t\t\t\t\t\tlabelClassName={styles.label({ className: labelClassName })}\n\t\t\t\t\t\t\tclassName={className}\n\t\t\t\t\t\t\treadonly={readonly}\n\t\t\t\t\t\t\tlayout={layout}\n\t\t\t\t\t\t\tcontrol={({ id, readonly }) => (\n\t\t\t\t\t\t\t\t<FormControl id={id}>{control({ field, fieldState, formState, readonly })}</FormControl>\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>\n\t\t\t\t\t</FormItem>\n\t\t\t\t);\n\t\t\t}}\n\t\t/>\n\t);\n}\n","import React from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nconst formStackStyles = tv({\n\tbase: \"space-y-5 lg:space-y-4\"\n});\n\n/** Оболочка для группы полей формы с внутренними отступами */\nexport const FormStack = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n\t({ className, children, ...props }, ref) => {\n\t\treturn (\n\t\t\t<div ref={ref} className={formStackStyles({ className })} {...props}>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t);\n\t}\n);\n\nFormStack.displayName = \"FormStack\";\n"],"names":["formStyle","tv","Form","className","asChild","props","jsx","Slot","FormProvider","FormFieldContext","React","FormField","Controller","useFormField","fieldContext","itemContext","FormItemContext","getFieldState","formState","useFormContext","fieldState","id","formItemStyle","FormItem","ref","FormLabel","required","formItemId","FieldLabel","FormControl","error","formDescriptionId","formMessageId","formMessageStyle","FormMessage","children","body","formFieldStyles","name","title","description","control","labelClassName","readonly","layout","form","styles","FormFieldControl","field","Field","formStackStyles","FormStack"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { useState as p, useCallback as g, useMemo as h } from "react";
2
2
  import { jsxs as m, jsx as c, Fragment as b } from "react/jsx-runtime";
3
3
  import { d as C, a as S, c as T, b as v } from "./Tag-DdHXTyKF.js";
4
- import { e as y } from "./useBreakpoints-D8wKOvil.js";
4
+ import { e as y } from "./useBreakpoints-DHvp74UL.js";
5
5
  import { T as w } from "./index-BVqs-uqP.js";
6
6
  function D({ value: t, defaultValue: r, onChange: l }) {
7
7
  const [n, i] = p(r), e = t !== void 0, s = e ? t : n, u = g(
@@ -53,4 +53,4 @@ export {
53
53
  N as S,
54
54
  D as u
55
55
  };
56
- //# sourceMappingURL=SearchSelectTag-DFCX9zT1.js.map
56
+ //# sourceMappingURL=SearchSelectTag-CA7Ie3Nx.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SearchSelectTag-DFCX9zT1.js","sources":["../src/hooks/useControllableState.ts","../src/components/search-select/components/SearchSelectTag.tsx"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\ntype UseControllableStateParams<T> = {\n\t/** Controlled значение */\n\tvalue?: T;\n\t/** Значение по умолчанию для uncontrolled режима */\n\tdefaultValue?: T;\n\t/** Callback при изменении значения */\n\tonChange?: (value: T) => void;\n};\n\n/**\n * Универсальный хук для управления controlled/uncontrolled состоянием.\n */\nexport function useControllableState<T>({ value, defaultValue, onChange }: UseControllableStateParams<T>) {\n\tconst [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n\n\tconst isControlled = value !== undefined;\n\tconst actualValue = isControlled ? value : uncontrolledValue;\n\n\tconst setValue = useCallback(\n\t\t(nextValue: T | ((prevValue: T) => T)) => {\n\t\t\tconst resolvedValue =\n\t\t\t\ttypeof nextValue === \"function\" ? (nextValue as (prevValue: T) => T)(actualValue as T) : nextValue;\n\n\t\t\tif (!isControlled) {\n\t\t\t\tsetUncontrolledValue(resolvedValue);\n\t\t\t}\n\n\t\t\tonChange?.(resolvedValue);\n\t\t},\n\t\t[actualValue, isControlled, onChange]\n\t);\n\n\treturn [actualValue, setValue] as const;\n}\n","import { TagButton, TagClose, TagDivider, TagWrapper } from \"@/components/tag/Tag\";\nimport { useIsMobile } from \"@/hooks/useBreakpoints\";\nimport { PropsWithChildren, useMemo } from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nconst searchSelectTagStyles = tv({\n\tbase: \"rounded-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary\",\n\tvariants: {\n\t\tselected: {\n\t\t\ttrue: \"group-focus-within/search-select-trigger:shadow-focus\"\n\t\t}\n\t}\n});\n\nexport interface SearchSelectTagProps {\n\tonLabelClick: (e: React.MouseEvent<HTMLElement>) => void;\n\tonClose: (e: React.MouseEvent<HTMLElement>) => void;\n\tonKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void;\n\treadonly?: boolean;\n\tisFocused?: boolean;\n\ttabIndex?: number;\n}\n\nexport const SearchSelectTag = (props: PropsWithChildren<SearchSelectTagProps>) => {\n\tconst {\n\t\tchildren,\n\t\tonLabelClick,\n\t\tonClose,\n\t\tonKeyDown,\n\t\treadonly = false,\n\t\tisFocused: selected = false,\n\t\ttabIndex\n\t} = props;\n\tconst hasClose = Boolean(onClose);\n\tconst isMobile = useIsMobile();\n\tconst size = useMemo(() => (isMobile ? \"lg\" : \"md\"), [isMobile]);\n\tconst styles = searchSelectTagStyles({ selected });\n\n\treturn (\n\t\t<TagWrapper size={size} className={styles} tabIndex={tabIndex} onKeyDown={onKeyDown}>\n\t\t\t<TagButton\n\t\t\t\tclassName=\"!shadow-none\"\n\t\t\t\tposition={hasClose && !readonly ? \"left\" : undefined}\n\t\t\t\tsize={size}\n\t\t\t\tonClick={onLabelClick}\n\t\t\t\tasChild\n\t\t\t>\n\t\t\t\t<span>{children}</span>\n\t\t\t</TagButton>\n\n\t\t\t{!readonly && (\n\t\t\t\t<>\n\t\t\t\t\t<TagDivider />\n\t\t\t\t\t<TagClose className=\"!shadow-none\" size={size} onClick={onClose} tag=\"span\" />\n\t\t\t\t</>\n\t\t\t)}\n\t\t</TagWrapper>\n\t);\n};\n\nSearchSelectTag.displayName = \"SearchSelectTag\";\n"],"names":["useControllableState","value","defaultValue","onChange","uncontrolledValue","setUncontrolledValue","useState","isControlled","actualValue","setValue","useCallback","nextValue","resolvedValue","searchSelectTagStyles","tv","SearchSelectTag","props","children","onLabelClick","onClose","onKeyDown","readonly","selected","tabIndex","hasClose","isMobile","useIsMobile","size","useMemo","styles","TagWrapper","jsx","TagButton","jsxs","Fragment","TagDivider","TagClose"],"mappings":";;;;;AAcO,SAASA,EAAwB,EAAE,OAAAC,GAAO,cAAAC,GAAc,UAAAC,KAA2C;AACzG,QAAM,CAACC,GAAmBC,CAAoB,IAAIC,EAASJ,CAAY,GAEjEK,IAAeN,MAAU,QACzBO,IAAcD,IAAeN,IAAQG,GAErCK,IAAWC;AAAA,IAChB,CAACC,MAAyC;AACzC,YAAMC,IACL,OAAOD,KAAc,aAAcA,EAAkCH,CAAgB,IAAIG;AAE1F,MAAKJ,KACJF,EAAqBO,CAAa,GAGnCT,IAAWS,CAAa;AAAA,IACzB;AAAA,IACA,CAACJ,GAAaD,GAAcJ,CAAQ;AAAA,EACrC;AAEO,SAAA,CAACK,GAAaC,CAAQ;AAC9B;AC9BA,MAAMI,IAAwBC,EAAG;AAAA,EAChC,MAAM;AAAA,EACN,UAAU;AAAA,IACT,UAAU;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACP;AAEF,CAAC,GAWYC,IAAkB,CAACC,MAAmD;AAC5E,QAAA;AAAA,IACL,UAAAC;AAAA,IACA,cAAAC;AAAA,IACA,SAAAC;AAAA,IACA,WAAAC;AAAA,IACA,UAAAC,IAAW;AAAA,IACX,WAAWC,IAAW;AAAA,IACtB,UAAAC;AAAA,EAAA,IACGP,GACEQ,IAAW,EAAQL,GACnBM,IAAWC,EAAY,GACvBC,IAAOC,EAAQ,MAAOH,IAAW,OAAO,MAAO,CAACA,CAAQ,CAAC,GACzDI,IAAShB,EAAsB,EAAE,UAAAS,GAAU;AAEjD,2BACEQ,GAAW,EAAA,MAAAH,GAAY,WAAWE,GAAQ,UAAAN,GAAoB,WAAAH,GAC9D,UAAA;AAAA,IAAA,gBAAAW;AAAA,MAACC;AAAA,MAAA;AAAA,QACA,WAAU;AAAA,QACV,UAAUR,KAAY,CAACH,IAAW,SAAS;AAAA,QAC3C,MAAAM;AAAA,QACA,SAAST;AAAA,QACT,SAAO;AAAA,QAEP,UAAA,gBAAAa,EAAC,UAAM,UAAAd,EAAS,CAAA;AAAA,MAAA;AAAA,IACjB;AAAA,IAEC,CAACI,KAEA,gBAAAY,EAAAC,GAAA,EAAA,UAAA;AAAA,MAAA,gBAAAH,EAACI,GAAW,EAAA;AAAA,MACZ,gBAAAJ,EAACK,KAAS,WAAU,gBAAe,MAAAT,GAAY,SAASR,GAAS,KAAI,OAAO,CAAA;AAAA,IAAA,EAC7E,CAAA;AAAA,EAAA,GAEF;AAEF;AAEAJ,EAAgB,cAAc;"}
1
+ {"version":3,"file":"SearchSelectTag-CA7Ie3Nx.js","sources":["../src/hooks/useControllableState.ts","../src/components/search-select/components/SearchSelectTag.tsx"],"sourcesContent":["import { useCallback, useState } from \"react\";\n\ntype UseControllableStateParams<T> = {\n\t/** Controlled значение */\n\tvalue?: T;\n\t/** Значение по умолчанию для uncontrolled режима */\n\tdefaultValue?: T;\n\t/** Callback при изменении значения */\n\tonChange?: (value: T) => void;\n};\n\n/**\n * Универсальный хук для управления controlled/uncontrolled состоянием.\n */\nexport function useControllableState<T>({ value, defaultValue, onChange }: UseControllableStateParams<T>) {\n\tconst [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n\n\tconst isControlled = value !== undefined;\n\tconst actualValue = isControlled ? value : uncontrolledValue;\n\n\tconst setValue = useCallback(\n\t\t(nextValue: T | ((prevValue: T) => T)) => {\n\t\t\tconst resolvedValue =\n\t\t\t\ttypeof nextValue === \"function\" ? (nextValue as (prevValue: T) => T)(actualValue as T) : nextValue;\n\n\t\t\tif (!isControlled) {\n\t\t\t\tsetUncontrolledValue(resolvedValue);\n\t\t\t}\n\n\t\t\tonChange?.(resolvedValue);\n\t\t},\n\t\t[actualValue, isControlled, onChange]\n\t);\n\n\treturn [actualValue, setValue] as const;\n}\n","import { TagButton, TagClose, TagDivider, TagWrapper } from \"@/components/tag/Tag\";\nimport { useIsMobile } from \"@/hooks/useBreakpoints\";\nimport { PropsWithChildren, useMemo } from \"react\";\nimport { tv } from \"tailwind-variants\";\n\nconst searchSelectTagStyles = tv({\n\tbase: \"rounded-sm focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary\",\n\tvariants: {\n\t\tselected: {\n\t\t\ttrue: \"group-focus-within/search-select-trigger:shadow-focus\"\n\t\t}\n\t}\n});\n\nexport interface SearchSelectTagProps {\n\tonLabelClick: (e: React.MouseEvent<HTMLElement>) => void;\n\tonClose: (e: React.MouseEvent<HTMLElement>) => void;\n\tonKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void;\n\treadonly?: boolean;\n\tisFocused?: boolean;\n\ttabIndex?: number;\n}\n\nexport const SearchSelectTag = (props: PropsWithChildren<SearchSelectTagProps>) => {\n\tconst {\n\t\tchildren,\n\t\tonLabelClick,\n\t\tonClose,\n\t\tonKeyDown,\n\t\treadonly = false,\n\t\tisFocused: selected = false,\n\t\ttabIndex\n\t} = props;\n\tconst hasClose = Boolean(onClose);\n\tconst isMobile = useIsMobile();\n\tconst size = useMemo(() => (isMobile ? \"lg\" : \"md\"), [isMobile]);\n\tconst styles = searchSelectTagStyles({ selected });\n\n\treturn (\n\t\t<TagWrapper size={size} className={styles} tabIndex={tabIndex} onKeyDown={onKeyDown}>\n\t\t\t<TagButton\n\t\t\t\tclassName=\"!shadow-none\"\n\t\t\t\tposition={hasClose && !readonly ? \"left\" : undefined}\n\t\t\t\tsize={size}\n\t\t\t\tonClick={onLabelClick}\n\t\t\t\tasChild\n\t\t\t>\n\t\t\t\t<span>{children}</span>\n\t\t\t</TagButton>\n\n\t\t\t{!readonly && (\n\t\t\t\t<>\n\t\t\t\t\t<TagDivider />\n\t\t\t\t\t<TagClose className=\"!shadow-none\" size={size} onClick={onClose} tag=\"span\" />\n\t\t\t\t</>\n\t\t\t)}\n\t\t</TagWrapper>\n\t);\n};\n\nSearchSelectTag.displayName = \"SearchSelectTag\";\n"],"names":["useControllableState","value","defaultValue","onChange","uncontrolledValue","setUncontrolledValue","useState","isControlled","actualValue","setValue","useCallback","nextValue","resolvedValue","searchSelectTagStyles","tv","SearchSelectTag","props","children","onLabelClick","onClose","onKeyDown","readonly","selected","tabIndex","hasClose","isMobile","useIsMobile","size","useMemo","styles","TagWrapper","jsx","TagButton","jsxs","Fragment","TagDivider","TagClose"],"mappings":";;;;;AAcO,SAASA,EAAwB,EAAE,OAAAC,GAAO,cAAAC,GAAc,UAAAC,KAA2C;AACzG,QAAM,CAACC,GAAmBC,CAAoB,IAAIC,EAASJ,CAAY,GAEjEK,IAAeN,MAAU,QACzBO,IAAcD,IAAeN,IAAQG,GAErCK,IAAWC;AAAA,IAChB,CAACC,MAAyC;AACzC,YAAMC,IACL,OAAOD,KAAc,aAAcA,EAAkCH,CAAgB,IAAIG;AAE1F,MAAKJ,KACJF,EAAqBO,CAAa,GAGnCT,IAAWS,CAAa;AAAA,IACzB;AAAA,IACA,CAACJ,GAAaD,GAAcJ,CAAQ;AAAA,EACrC;AAEO,SAAA,CAACK,GAAaC,CAAQ;AAC9B;AC9BA,MAAMI,IAAwBC,EAAG;AAAA,EAChC,MAAM;AAAA,EACN,UAAU;AAAA,IACT,UAAU;AAAA,MACT,MAAM;AAAA,IAAA;AAAA,EACP;AAEF,CAAC,GAWYC,IAAkB,CAACC,MAAmD;AAC5E,QAAA;AAAA,IACL,UAAAC;AAAA,IACA,cAAAC;AAAA,IACA,SAAAC;AAAA,IACA,WAAAC;AAAA,IACA,UAAAC,IAAW;AAAA,IACX,WAAWC,IAAW;AAAA,IACtB,UAAAC;AAAA,EAAA,IACGP,GACEQ,IAAW,EAAQL,GACnBM,IAAWC,EAAY,GACvBC,IAAOC,EAAQ,MAAOH,IAAW,OAAO,MAAO,CAACA,CAAQ,CAAC,GACzDI,IAAShB,EAAsB,EAAE,UAAAS,GAAU;AAEjD,2BACEQ,GAAW,EAAA,MAAAH,GAAY,WAAWE,GAAQ,UAAAN,GAAoB,WAAAH,GAC9D,UAAA;AAAA,IAAA,gBAAAW;AAAA,MAACC;AAAA,MAAA;AAAA,QACA,WAAU;AAAA,QACV,UAAUR,KAAY,CAACH,IAAW,SAAS;AAAA,QAC3C,MAAAM;AAAA,QACA,SAAST;AAAA,QACT,SAAO;AAAA,QAEP,UAAA,gBAAAa,EAAC,UAAM,UAAAd,EAAS,CAAA;AAAA,MAAA;AAAA,IACjB;AAAA,IAEC,CAACI,KAEA,gBAAAY,EAAAC,GAAA,EAAA,UAAA;AAAA,MAAA,gBAAAH,EAACI,GAAW,EAAA;AAAA,MACZ,gBAAAJ,EAACK,KAAS,WAAU,gBAAe,MAAAT,GAAY,SAASR,GAAS,KAAI,OAAO,CAAA;AAAA,IAAA,EAC7E,CAAA;AAAA,EAAA,GAEF;AAEF;AAEAJ,EAAgB,cAAc;"}
@@ -0,0 +1,65 @@
1
+ import { T as l } from "./index-BVqs-uqP.js";
2
+ import { jsx as i } from "react/jsx-runtime";
3
+ import * as n from "react";
4
+ const w = l({
5
+ base: "relative cursor-cell select-none",
6
+ variants: {
7
+ state: {
8
+ readonly: "bg-secondary-bg-hover text-muted",
9
+ fillSource: "bg-primary-bg-hover",
10
+ modified: "bg-status-warning-bg-hover",
11
+ editing: "bg-status-warning-bg-hover shadow-focus"
12
+ }
13
+ }
14
+ }), u = l({
15
+ base: "w-full bg-transparent outline-none",
16
+ variants: {
17
+ multiline: {
18
+ true: "select-text whitespace-pre-wrap break-words"
19
+ }
20
+ }
21
+ }), f = (t, o) => ({
22
+ top: Math.min(t.row, o.row),
23
+ bottom: Math.max(t.row, o.row),
24
+ left: Math.min(t.col, o.col),
25
+ right: Math.max(t.col, o.col)
26
+ }), c = (t, o) => !!t && o.row >= t.top && o.row <= t.bottom && o.col >= t.left && o.col <= t.right, b = {
27
+ selection: { color: "hsl(var(--primary-accent))", width: 2 },
28
+ preview: { color: "hsl(var(--primary-border) / 0.75)", width: 1 }
29
+ }, g = (t, o, a = b.selection) => {
30
+ if (!t || !c(t, o)) return "";
31
+ const { color: r, width: s } = a, e = [];
32
+ return o.row === t.top && e.push(`inset 0 ${s}px 0 0 ${r}`), o.row === t.bottom && e.push(`inset 0 -${s}px 0 0 ${r}`), o.col === t.left && e.push(`inset ${s}px 0 0 0 ${r}`), o.col === t.right && e.push(`inset -${s}px 0 0 0 ${r}`), e.join(", ");
33
+ }, x = (...t) => {
34
+ const o = t.filter(Boolean);
35
+ return o.length ? { boxShadow: o.join(", ") } : {};
36
+ }, p = l({
37
+ // Смещение в половину размера: ручка садится ровно на угол ячейки, а не рядом с ним.
38
+ base: [
39
+ "absolute -bottom-[5px] -right-[5px] z-10 size-2.5 cursor-crosshair rounded-full",
40
+ "border border-secondary-bg bg-primary-accent"
41
+ ]
42
+ }), d = n.forwardRef(
43
+ ({ className: t, ...o }, a) => /* @__PURE__ */ i(
44
+ "span",
45
+ {
46
+ ref: a,
47
+ role: "button",
48
+ "aria-label": "Протянуть значения",
49
+ className: p({ className: t }),
50
+ ...o
51
+ }
52
+ )
53
+ );
54
+ d.displayName = "TableFillHandle";
55
+ export {
56
+ b as C,
57
+ d as T,
58
+ u as a,
59
+ f as b,
60
+ w as c,
61
+ g as d,
62
+ x as e,
63
+ c as i
64
+ };
65
+ //# sourceMappingURL=TableFillHandle-C_yvCTSl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TableFillHandle-C_yvCTSl.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-none\",\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":"TextOverflowTooltip-B1I5qwAT.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 */\nexport const isElementOverflowing = (element: HTMLElement): boolean => {\n\treturn element.scrollWidth > element.offsetWidth || element.scrollHeight > element.offsetHeight;\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":";;;;AAKa,MAAAA,IAAuB,CAACC,MAC7BA,EAAQ,cAAcA,EAAQ,eAAeA,EAAQ,eAAeA,EAAQ,cCHvEC,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-B1I5qwAT.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;"}
@@ -3,7 +3,7 @@ var z = (t, o, n) => o in t ? $(t, o, { enumerable: !0, configurable: !0, writab
3
3
  var P = (t, o, n) => z(t, typeof o != "symbol" ? o + "" : o, n);
4
4
  import { jsx as a, jsxs as x } from "react/jsx-runtime";
5
5
  import S, { useMemo as N, useState as O, useCallback as B } from "react";
6
- import { a as D, F as L, g as R } from "../../FormStack-B3UBh9oF.js";
6
+ import { a as D, F as L, g as R } from "../../FormStack-Cc_ELdWL.js";
7
7
  import { s as G } from "../../zod-BMNoK3aM.js";
8
8
  import { e as V } from "../../index.esm-CXA6i4d7.js";
9
9
  import { z as v } from "../../vendors/zod.js";
@@ -8,5 +8,9 @@ export interface AlertVariants {
8
8
  export type AlertProps = React.HTMLAttributes<HTMLDivElement> & AlertVariants;
9
9
  /**
10
10
  * Компонент Alert для отображения уведомлений и сообщений
11
+ *
12
+ * Является container query контейнером: при ширине меньше `@sm` (384px) кнопка
13
+ * переносится под заголовок и описание. Минимальная ширина — 320px (`min-w-80`);
14
+ * снимается через `className="min-w-0"`.
11
15
  */
12
16
  export declare const Alert: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & AlertVariants & React.RefAttributes<HTMLDivElement>>;
@@ -35,4 +35,5 @@ export default meta;
35
35
  type Story = StoryObj<typeof Alert>;
36
36
  export declare const Default: Story;
37
37
  export declare const Playground: StoryObj<PlaygroundArgs>;
38
+ export declare const NarrowContainer: Story;
38
39
  export declare const Showcase: Story;
@@ -10,7 +10,7 @@ import { o as te } from "../Overlay-CVt011mY.js";
10
10
  import { B as N } from "../Button-Dg89xRSi.js";
11
11
  import { A as ae, u as f } from "../AlertContext-CxjW1LVL.js";
12
12
  import { I as oe } from "../Icon-DH3ev9GK.js";
13
- import { e as w } from "../useBreakpoints-D8wKOvil.js";
13
+ import { e as w } from "../useBreakpoints-DHvp74UL.js";
14
14
  var h = "AlertDialog", [re, ke] = G(h, [
15
15
  b
16
16
  ]), c = b(), R = (e) => {
@@ -1,11 +1,11 @@
1
- import { A as k, a as v, b as C } from "../AlertIcon-5B6AgZpe.js";
1
+ import { A as R, a as k, b as v } from "../AlertIcon-BphnEYvV.js";
2
2
  import { jsx as o } from "react/jsx-runtime";
3
- import n from "react";
4
- import { T as l } from "../index-BVqs-uqP.js";
3
+ import l from "react";
4
+ import { T as n } from "../index-BVqs-uqP.js";
5
5
  import { S as c } from "../index-BtQfgaSF.js";
6
6
  import { u } from "../AlertContext-CxjW1LVL.js";
7
7
  import { B as p } from "../Button-Dg89xRSi.js";
8
- const x = l({
8
+ const x = n({
9
9
  base: "col-start-2 line-clamp-1 min-h-4 text-sm font-medium tracking-tight text-primary-fg",
10
10
  variants: {
11
11
  status: {
@@ -23,27 +23,27 @@ const x = l({
23
23
  defaultVariants: {
24
24
  focus: "low"
25
25
  }
26
- }), d = n.forwardRef(
27
- ({ className: t, status: s, focus: r, asChild: e = !1, ...a }, i) => {
28
- const { status: f, focus: m } = u({ status: s, focus: r });
29
- return /* @__PURE__ */ o(e ? c : "h5", { ref: i, className: x({ status: f, className: t, focus: m }), ...a });
26
+ }), d = l.forwardRef(
27
+ ({ className: t, status: s, focus: e, asChild: r = !1, ...a }, f) => {
28
+ const { status: m, focus: i } = u({ status: s, focus: e });
29
+ return /* @__PURE__ */ o(r ? c : "h5", { ref: f, className: x({ status: m, className: t, focus: i }), ...a });
30
30
  }
31
31
  );
32
32
  d.displayName = "AlertTitle";
33
- const g = l({
34
- base: "col-start-3 ml-3 h-5 self-end rounded-none px-0 py-0.5 text-xs"
35
- }), A = n.forwardRef(
36
- ({ className: t, status: s, ...r }, e) => {
33
+ const g = n({
34
+ base: "@sm:col-start-3 @sm:ml-3 @sm:justify-self-auto @sm:self-end col-start-2 h-5 justify-self-end rounded-none px-0 py-0.5 text-xs"
35
+ }), y = l.forwardRef(
36
+ ({ className: t, status: s, ...e }, r) => {
37
37
  const { status: a } = u({ status: s });
38
- return /* @__PURE__ */ o(p, { ref: e, status: a, variant: "link", className: g({ className: t }), ...r });
38
+ return /* @__PURE__ */ o(p, { ref: r, status: a, variant: "link", className: g({ className: t }), ...e });
39
39
  }
40
40
  );
41
- A.displayName = "AlertButton";
41
+ y.displayName = "AlertButton";
42
42
  export {
43
- k as Alert,
44
- A as AlertButton,
45
- v as AlertDescription,
46
- C as AlertIcon,
43
+ R as Alert,
44
+ y as AlertButton,
45
+ k as AlertDescription,
46
+ v as AlertIcon,
47
47
  d as AlertTitle,
48
48
  u as useAlert
49
49
  };