@smwb/ui-react 2.8.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (243) hide show
  1. package/AI_LESS_OVERRIDES.md +84 -21
  2. package/AI_THEMING.md +72 -28
  3. package/README.md +654 -0
  4. package/dist/assets/styles/less/components/appBar/appBar.entry.css +1 -1
  5. package/dist/assets/styles/less/components/badge/badge.entry.css +1 -1
  6. package/dist/assets/styles/less/components/button/button.entry.css +1 -1
  7. package/dist/assets/styles/less/components/checkbox/checkbox.entry.css +1 -1
  8. package/dist/assets/styles/less/components/chip/chip.entry.css +1 -1
  9. package/dist/assets/styles/less/components/commandPalette/commandPalette.entry.css +1 -0
  10. package/dist/assets/styles/less/components/composer/composer.entry.css +1 -0
  11. package/dist/assets/styles/less/components/dagView/dagView.entry.css +1 -0
  12. package/dist/assets/styles/less/components/diffStat/diffStat.entry.css +1 -0
  13. package/dist/assets/styles/less/components/kbd/kbd.entry.css +1 -0
  14. package/dist/assets/styles/less/components/list/list.entry.css +1 -1
  15. package/dist/assets/styles/less/components/qrCode/qrCode.entry.css +1 -0
  16. package/dist/assets/styles/less/components/radioButton/radioButton.entry.css +1 -1
  17. package/dist/assets/styles/less/components/selectField/selectField.entry.css +1 -1
  18. package/dist/assets/styles/less/components/sidebar/sidebar.entry.css +1 -1
  19. package/dist/assets/styles/less/components/statusDot/statusDot.entry.css +1 -0
  20. package/dist/assets/styles/less/components/swimlanes/swimlanes.entry.css +1 -0
  21. package/dist/assets/styles/less/components/tabGroups/tabGroups.entry.css +1 -0
  22. package/dist/assets/styles/less/components/tabs/tab/tab.entry.css +1 -1
  23. package/dist/assets/styles/less/components/tabs/tabPanel/tabPanel.entry.css +1 -0
  24. package/dist/assets/styles/less/components/tabs/tabs.entry.css +1 -1
  25. package/dist/assets/styles/less/components/textField/textField.entry.css +1 -1
  26. package/dist/assets/styles/less/components/toggle/toggle.entry.css +1 -1
  27. package/dist/assets/styles/less/components/treeView/treeView.entry.css +1 -1
  28. package/dist/assets/styles/less/tokens.entry.css +1 -1
  29. package/dist/components/dataDisplay/badge/badge.d.ts +2 -1
  30. package/dist/components/dataDisplay/badge/badge.js.map +1 -1
  31. package/dist/components/dataDisplay/chat/chat.d.ts +43 -1
  32. package/dist/components/dataDisplay/chat/chat.js +179 -150
  33. package/dist/components/dataDisplay/chat/chat.js.map +1 -1
  34. package/dist/components/dataDisplay/chat/chatComposer.d.ts +17 -0
  35. package/dist/components/dataDisplay/chat/chatComposer.js +31 -29
  36. package/dist/components/dataDisplay/chat/chatComposer.js.map +1 -1
  37. package/dist/components/dataDisplay/chat/index.d.ts +1 -1
  38. package/dist/components/dataDisplay/chat/utils.d.ts +14 -0
  39. package/dist/components/dataDisplay/chat/utils.js.map +1 -1
  40. package/dist/components/dataDisplay/dagView/dagLayout.d.ts +74 -0
  41. package/dist/components/dataDisplay/dagView/dagLayout.js +289 -0
  42. package/dist/components/dataDisplay/dagView/dagLayout.js.map +1 -0
  43. package/dist/components/dataDisplay/dagView/dagView.d.ts +157 -0
  44. package/dist/components/dataDisplay/dagView/dagView.js +543 -0
  45. package/dist/components/dataDisplay/dagView/dagView.js.map +1 -0
  46. package/dist/components/dataDisplay/dagView/index.d.ts +4 -0
  47. package/dist/components/dataDisplay/dagView/panZoom.d.ts +75 -0
  48. package/dist/components/dataDisplay/dagView/panZoom.js +171 -0
  49. package/dist/components/dataDisplay/dagView/panZoom.js.map +1 -0
  50. package/dist/components/dataDisplay/diffStat/diffStat.d.ts +54 -0
  51. package/dist/components/dataDisplay/diffStat/diffStat.js +63 -0
  52. package/dist/components/dataDisplay/diffStat/diffStat.js.map +1 -0
  53. package/dist/components/dataDisplay/diffStat/index.d.ts +2 -0
  54. package/dist/components/dataDisplay/kbd/index.d.ts +4 -0
  55. package/dist/components/dataDisplay/kbd/kbd.d.ts +40 -0
  56. package/dist/components/dataDisplay/kbd/kbd.js +27 -0
  57. package/dist/components/dataDisplay/kbd/kbd.js.map +1 -0
  58. package/dist/components/dataDisplay/kbd/kbdKeys.d.ts +18 -0
  59. package/dist/components/dataDisplay/kbd/kbdKeys.js +72 -0
  60. package/dist/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
  61. package/dist/components/dataDisplay/list/listItem.d.ts +34 -0
  62. package/dist/components/dataDisplay/list/listItem.js +47 -24
  63. package/dist/components/dataDisplay/list/listItem.js.map +1 -1
  64. package/dist/components/dataDisplay/qrCode/index.d.ts +2 -0
  65. package/dist/components/dataDisplay/qrCode/qrCode.d.ts +28 -0
  66. package/dist/components/dataDisplay/qrCode/qrCode.js +78 -0
  67. package/dist/components/dataDisplay/qrCode/qrCode.js.map +1 -0
  68. package/dist/components/dataDisplay/qrCode/qrCodePath.d.ts +7 -0
  69. package/dist/components/dataDisplay/qrCode/qrCodePath.js +20 -0
  70. package/dist/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
  71. package/dist/components/dataDisplay/statusDot/index.d.ts +2 -0
  72. package/dist/components/dataDisplay/statusDot/statusDot.d.ts +35 -0
  73. package/dist/components/dataDisplay/statusDot/statusDot.js +30 -0
  74. package/dist/components/dataDisplay/statusDot/statusDot.js.map +1 -0
  75. package/dist/components/dataDisplay/swimlanes/index.d.ts +2 -0
  76. package/dist/components/dataDisplay/swimlanes/swimlanes.d.ts +53 -0
  77. package/dist/components/dataDisplay/swimlanes/swimlanes.js +357 -0
  78. package/dist/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
  79. package/dist/components/dataDisplay/treeView/treeView.d.ts +17 -1
  80. package/dist/components/dataDisplay/treeView/treeView.js +113 -92
  81. package/dist/components/dataDisplay/treeView/treeView.js.map +1 -1
  82. package/dist/components/feedBack/modal/modal.js +84 -63
  83. package/dist/components/feedBack/modal/modal.js.map +1 -1
  84. package/dist/components/inputs/button/button.d.ts +13 -1
  85. package/dist/components/inputs/button/button.js +57 -51
  86. package/dist/components/inputs/button/button.js.map +1 -1
  87. package/dist/components/inputs/composer/composer.d.ts +149 -0
  88. package/dist/components/inputs/composer/composer.js +219 -0
  89. package/dist/components/inputs/composer/composer.js.map +1 -0
  90. package/dist/components/inputs/composer/composerFiles.d.ts +26 -0
  91. package/dist/components/inputs/composer/composerFiles.js +19 -0
  92. package/dist/components/inputs/composer/composerFiles.js.map +1 -0
  93. package/dist/components/inputs/composer/composerKeys.d.ts +29 -0
  94. package/dist/components/inputs/composer/composerKeys.js +7 -0
  95. package/dist/components/inputs/composer/composerKeys.js.map +1 -0
  96. package/dist/components/inputs/composer/index.d.ts +3 -0
  97. package/dist/components/layout/sheet/sheet.d.ts +12 -0
  98. package/dist/components/layout/sheet/sheet.js +152 -137
  99. package/dist/components/layout/sheet/sheet.js.map +1 -1
  100. package/dist/components/layout/tabGroups/index.d.ts +4 -0
  101. package/dist/components/layout/tabGroups/tabGroups.d.ts +94 -0
  102. package/dist/components/layout/tabGroups/tabGroups.js +783 -0
  103. package/dist/components/layout/tabGroups/tabGroups.js.map +1 -0
  104. package/dist/components/layout/tabGroups/tabGroupsFocus.d.ts +55 -0
  105. package/dist/components/layout/tabGroups/tabGroupsFocus.js +199 -0
  106. package/dist/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
  107. package/dist/components/layout/tabGroups/tabGroupsLayout.d.ts +250 -0
  108. package/dist/components/layout/tabGroups/tabGroupsLayout.js +497 -0
  109. package/dist/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
  110. package/dist/components/navigation/appBar/appBar.d.ts +22 -0
  111. package/dist/components/navigation/appBar/appBar.js +31 -26
  112. package/dist/components/navigation/appBar/appBar.js.map +1 -1
  113. package/dist/components/navigation/commandPalette/commandPalette.d.ts +111 -0
  114. package/dist/components/navigation/commandPalette/commandPalette.js +337 -0
  115. package/dist/components/navigation/commandPalette/commandPalette.js.map +1 -0
  116. package/dist/components/navigation/commandPalette/commandPaletteFilter.d.ts +11 -0
  117. package/dist/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
  118. package/dist/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
  119. package/dist/components/navigation/commandPalette/commandPaletteNavigation.d.ts +13 -0
  120. package/dist/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
  121. package/dist/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
  122. package/dist/components/navigation/commandPalette/commandPaletteTypes.d.ts +39 -0
  123. package/dist/components/navigation/commandPalette/index.d.ts +4 -0
  124. package/dist/components/navigation/sidebar/sidebar.d.ts +10 -0
  125. package/dist/components/navigation/sidebar/sidebar.js +61 -59
  126. package/dist/components/navigation/sidebar/sidebar.js.map +1 -1
  127. package/dist/components/navigation/tabs/index.d.ts +3 -1
  128. package/dist/components/navigation/tabs/tab/tab.d.ts +88 -1
  129. package/dist/components/navigation/tabs/tab/tab.js +121 -42
  130. package/dist/components/navigation/tabs/tab/tab.js.map +1 -1
  131. package/dist/components/navigation/tabs/tabPanel/tabPanel.d.ts +19 -0
  132. package/dist/components/navigation/tabs/tabPanel/tabPanel.js +27 -0
  133. package/dist/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
  134. package/dist/components/navigation/tabs/tabs.d.ts +79 -6
  135. package/dist/components/navigation/tabs/tabs.js +369 -145
  136. package/dist/components/navigation/tabs/tabs.js.map +1 -1
  137. package/dist/components/navigation/tabs/tabs.utils.d.ts +20 -0
  138. package/dist/components/navigation/tabs/tabs.utils.js +11 -0
  139. package/dist/components/navigation/tabs/tabs.utils.js.map +1 -0
  140. package/dist/components/navigation/tabs/tabsContext.d.ts +11 -0
  141. package/dist/components/navigation/tabs/tabsContext.js +6 -0
  142. package/dist/components/navigation/tabs/tabsContext.js.map +1 -0
  143. package/dist/headless/components/dataDisplay/badge/badge.js.map +1 -1
  144. package/dist/headless/components/dataDisplay/chat/chat.js +179 -150
  145. package/dist/headless/components/dataDisplay/chat/chat.js.map +1 -1
  146. package/dist/headless/components/dataDisplay/chat/chatComposer.js +31 -29
  147. package/dist/headless/components/dataDisplay/chat/chatComposer.js.map +1 -1
  148. package/dist/headless/components/dataDisplay/chat/utils.js.map +1 -1
  149. package/dist/headless/components/dataDisplay/dagView/dagLayout.js +289 -0
  150. package/dist/headless/components/dataDisplay/dagView/dagLayout.js.map +1 -0
  151. package/dist/headless/components/dataDisplay/dagView/dagView.js +541 -0
  152. package/dist/headless/components/dataDisplay/dagView/dagView.js.map +1 -0
  153. package/dist/headless/components/dataDisplay/dagView/panZoom.js +171 -0
  154. package/dist/headless/components/dataDisplay/dagView/panZoom.js.map +1 -0
  155. package/dist/headless/components/dataDisplay/diffStat/diffStat.js +61 -0
  156. package/dist/headless/components/dataDisplay/diffStat/diffStat.js.map +1 -0
  157. package/dist/headless/components/dataDisplay/kbd/kbd.js +25 -0
  158. package/dist/headless/components/dataDisplay/kbd/kbd.js.map +1 -0
  159. package/dist/headless/components/dataDisplay/kbd/kbdKeys.js +72 -0
  160. package/dist/headless/components/dataDisplay/kbd/kbdKeys.js.map +1 -0
  161. package/dist/headless/components/dataDisplay/list/listItem.js +47 -24
  162. package/dist/headless/components/dataDisplay/list/listItem.js.map +1 -1
  163. package/dist/headless/components/dataDisplay/qrCode/qrCode.js +76 -0
  164. package/dist/headless/components/dataDisplay/qrCode/qrCode.js.map +1 -0
  165. package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js +20 -0
  166. package/dist/headless/components/dataDisplay/qrCode/qrCodePath.js.map +1 -0
  167. package/dist/headless/components/dataDisplay/statusDot/statusDot.js +28 -0
  168. package/dist/headless/components/dataDisplay/statusDot/statusDot.js.map +1 -0
  169. package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js +355 -0
  170. package/dist/headless/components/dataDisplay/swimlanes/swimlanes.js.map +1 -0
  171. package/dist/headless/components/dataDisplay/treeView/treeView.js +113 -92
  172. package/dist/headless/components/dataDisplay/treeView/treeView.js.map +1 -1
  173. package/dist/headless/components/feedBack/modal/modal.js +85 -64
  174. package/dist/headless/components/feedBack/modal/modal.js.map +1 -1
  175. package/dist/headless/components/inputs/button/button.js +56 -50
  176. package/dist/headless/components/inputs/button/button.js.map +1 -1
  177. package/dist/headless/components/inputs/composer/composer.js +217 -0
  178. package/dist/headless/components/inputs/composer/composer.js.map +1 -0
  179. package/dist/headless/components/inputs/composer/composerFiles.js +19 -0
  180. package/dist/headless/components/inputs/composer/composerFiles.js.map +1 -0
  181. package/dist/headless/components/inputs/composer/composerKeys.js +7 -0
  182. package/dist/headless/components/inputs/composer/composerKeys.js.map +1 -0
  183. package/dist/headless/components/layout/sheet/sheet.js +160 -145
  184. package/dist/headless/components/layout/sheet/sheet.js.map +1 -1
  185. package/dist/headless/components/layout/tabGroups/tabGroups.js +781 -0
  186. package/dist/headless/components/layout/tabGroups/tabGroups.js.map +1 -0
  187. package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js +199 -0
  188. package/dist/headless/components/layout/tabGroups/tabGroupsFocus.js.map +1 -0
  189. package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js +497 -0
  190. package/dist/headless/components/layout/tabGroups/tabGroupsLayout.js.map +1 -0
  191. package/dist/headless/components/navigation/appBar/appBar.js +35 -30
  192. package/dist/headless/components/navigation/appBar/appBar.js.map +1 -1
  193. package/dist/headless/components/navigation/commandPalette/commandPalette.js +335 -0
  194. package/dist/headless/components/navigation/commandPalette/commandPalette.js.map +1 -0
  195. package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js +16 -0
  196. package/dist/headless/components/navigation/commandPalette/commandPaletteFilter.js.map +1 -0
  197. package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js +38 -0
  198. package/dist/headless/components/navigation/commandPalette/commandPaletteNavigation.js.map +1 -0
  199. package/dist/headless/components/navigation/sidebar/sidebar.js +56 -54
  200. package/dist/headless/components/navigation/sidebar/sidebar.js.map +1 -1
  201. package/dist/headless/components/navigation/tabs/tab/tab.js +121 -42
  202. package/dist/headless/components/navigation/tabs/tab/tab.js.map +1 -1
  203. package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js +25 -0
  204. package/dist/headless/components/navigation/tabs/tabPanel/tabPanel.js.map +1 -0
  205. package/dist/headless/components/navigation/tabs/tabs.js +369 -145
  206. package/dist/headless/components/navigation/tabs/tabs.js.map +1 -1
  207. package/dist/headless/components/navigation/tabs/tabs.utils.js +11 -0
  208. package/dist/headless/components/navigation/tabs/tabs.utils.js.map +1 -0
  209. package/dist/headless/components/navigation/tabs/tabsContext.js +6 -0
  210. package/dist/headless/components/navigation/tabs/tabsContext.js.map +1 -0
  211. package/dist/headless/hooks/useFocusTrap.js +24 -21
  212. package/dist/headless/hooks/useFocusTrap.js.map +1 -1
  213. package/dist/headless/hooks/useKeyboardShortcut.js +19 -0
  214. package/dist/headless/hooks/useKeyboardShortcut.js.map +1 -0
  215. package/dist/headless/index.js +360 -316
  216. package/dist/headless/index.js.map +1 -1
  217. package/dist/headless/utils/keyboardShortcut.js +49 -0
  218. package/dist/headless/utils/keyboardShortcut.js.map +1 -0
  219. package/dist/headless/utils/linkAttrs.js +13 -0
  220. package/dist/headless/utils/linkAttrs.js.map +1 -0
  221. package/dist/headless/utils/restoreFocus.js +10 -0
  222. package/dist/headless/utils/restoreFocus.js.map +1 -0
  223. package/dist/hooks/useFocusTrap.d.ts +6 -1
  224. package/dist/hooks/useFocusTrap.js +24 -21
  225. package/dist/hooks/useFocusTrap.js.map +1 -1
  226. package/dist/hooks/useKeyboardShortcut.d.ts +30 -0
  227. package/dist/hooks/useKeyboardShortcut.js +19 -0
  228. package/dist/hooks/useKeyboardShortcut.js.map +1 -0
  229. package/dist/index.cjs +3 -2
  230. package/dist/index.cjs.map +1 -1
  231. package/dist/index.d.ts +24 -3
  232. package/dist/index.js +360 -316
  233. package/dist/index.js.map +1 -1
  234. package/dist/utils/keyboardShortcut.d.ts +12 -0
  235. package/dist/utils/keyboardShortcut.js +49 -0
  236. package/dist/utils/keyboardShortcut.js.map +1 -0
  237. package/dist/utils/linkAttrs.d.ts +13 -0
  238. package/dist/utils/linkAttrs.js +13 -0
  239. package/dist/utils/linkAttrs.js.map +1 -0
  240. package/dist/utils/restoreFocus.d.ts +8 -0
  241. package/dist/utils/restoreFocus.js +10 -0
  242. package/dist/utils/restoreFocus.js.map +1 -0
  243. package/package.json +5 -3
@@ -1 +1 @@
1
- {"version":3,"file":"modal.js","sources":["../../../../../src/components/feedBack/modal/modal.tsx"],"sourcesContent":["import React, { forwardRef, PropsWithChildren, useEffect, useRef, useState } from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\nimport { createPortal } from \"react-dom\";\nimport cn from \"clsx\";\nimport { useSafeLayoutEffect } from \"../../../hooks/useSafeLayoutEffect\";\nimport { useForkRef } from \"../../../hooks/useForkRef\";\nimport { isTopOverlayLayer } from \"../../../utils/overlayLayer\";\n\nexport interface ModalProps {\n size?: \"small\" | \"medium\" | \"large\" | \"fullscreen\";\n closeOnOutsideClick?: boolean;\n onClose?: () => void;\n open: boolean;\n animation?: \"fade\" | \"scale\" | \"drop\";\n className?: string;\n backdrop?: \"blured\" | \"dark\" | \"transparent\" | \"darkBlured\";\n asForm?: boolean;\n disableAppearAnimation?: boolean;\n /** ARIA role of the dialog. */\n role?: \"dialog\" | \"alertdialog\";\n /** Close the modal when Escape is pressed. */\n closeOnEsc?: boolean;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n}\n\nconst ModalBase = forwardRef<HTMLDivElement, PropsWithChildren<ModalProps>>(function Modal(\n {\n children,\n onClose,\n open,\n className,\n animation = \"fade\",\n backdrop = \"dark\",\n size = \"large\",\n closeOnOutsideClick = true,\n asForm = false,\n disableAppearAnimation = false,\n role = \"dialog\",\n closeOnEsc = true,\n ...rest\n },\n ref\n) {\n const [domRoot, setDomRoot] = useState<HTMLElement>();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n const forkedContentRef = useForkRef<HTMLDivElement>(ref, contentRef);\n\n useSafeLayoutEffect(() => {\n setDomRoot(document.body);\n }, []);\n\n useEffect(() => {\n if (!open || !closeOnEsc || !onClose) {\n return;\n }\n const onKeyDown = (event: KeyboardEvent) => {\n // Only the topmost overlay layer reacts to Escape, and not to one handled inside\n // it, e.g. by a menu closing on it.\n if (event.key === \"Escape\" && !event.defaultPrevented && isTopOverlayLayer(nodeRef.current)) {\n onClose();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [open, closeOnEsc, onClose]);\n\n if (!domRoot) {\n return <></>;\n }\n\n const Component = (asForm ? \"form\" : \"div\") as \"div\";\n\n return createPortal(\n <CSSTransition\n timeout={{\n appear: 225,\n enter: 225,\n exit: 150,\n }}\n in={open}\n classNames={{\n appear: \"smwb-modal__overlay-appear\",\n appearActive: \"smwb-modal__overlay-appear-active\",\n appearDone: \"smwb-modal__overlay-appear-done\",\n enter: \"smwb-modal__overlay-enter\",\n enterActive: \"smwb-modal__overlay-enter-active\",\n enterDone: \"smwb-modal__overlay-enter-done\",\n exit: \"smwb-modal__overlay-exit\",\n exitActive: \"smwb-modal__overlay-exit-active\",\n }}\n appear={!disableAppearAnimation}\n mountOnEnter\n unmountOnExit\n nodeRef={nodeRef}\n >\n <div\n ref={nodeRef}\n data-smwb-overlay-layer=\"\"\n className={cn(\"smwb-modal__overlay\", `smwb-${backdrop}`, `smwb-${size}`)}\n onClick={closeOnOutsideClick && onClose ? onClose : undefined}\n >\n <Component\n ref={forkedContentRef}\n className={cn(\"smwb-modal\", `smwb-${size}`, `smwb-${animation}`, className)}\n onClick={(e) => e.stopPropagation()}\n role={role}\n aria-modal=\"true\"\n {...rest}\n >\n {children}\n </Component>\n </div>\n </CSSTransition>,\n domRoot\n );\n});\n\nexport interface HeaderProps {\n className?: string;\n}\n\nexport function Header({ className, children }: PropsWithChildren<HeaderProps>) {\n return <div className={cn(\"smwb-modal__header\", className)}>{children}</div>;\n}\n\nexport interface ContentProps {\n className?: string;\n}\n\nexport function Content({ className, children }: PropsWithChildren<ContentProps>) {\n return <div className={cn(\"smwb-modal__content\", className)}>{children}</div>;\n}\n\nexport interface FooterProps {\n className?: string;\n}\n\nexport function Footer({ className, children }: PropsWithChildren<FooterProps>) {\n return <div className={cn(\"smwb-modal__footer\", className)}>{children}</div>;\n}\n\nexport const Modal = Object.assign(ModalBase, {\n Footer,\n Header,\n Content,\n});\n\nexport default Modal;\n"],"names":["ModalBase","forwardRef","children","onClose","open","className","animation","backdrop","size","closeOnOutsideClick","asForm","disableAppearAnimation","role","closeOnEsc","rest","ref","domRoot","setDomRoot","useState","nodeRef","useRef","contentRef","forkedContentRef","useForkRef","useSafeLayoutEffect","useEffect","onKeyDown","event","isTopOverlayLayer","jsx","Fragment","Component","createPortal","CSSTransition","cn","e","Header","Content","Footer","Modal"],"mappings":"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"}
1
+ {"version":3,"file":"modal.js","sources":["../../../../../src/components/feedBack/modal/modal.tsx"],"sourcesContent":["import React, {\n forwardRef,\n PropsWithChildren,\n useCallback,\n useEffect,\n useInsertionEffect,\n useRef,\n useState,\n} from \"react\";\nimport { CSSTransition } from \"react-transition-group\";\nimport { createPortal } from \"react-dom\";\nimport cn from \"clsx\";\nimport { useFocusTrap } from \"../../../hooks/useFocusTrap\";\nimport { useSafeLayoutEffect } from \"../../../hooks/useSafeLayoutEffect\";\nimport { useForkRef } from \"../../../hooks/useForkRef\";\nimport { isTopOverlayLayer } from \"../../../utils/overlayLayer\";\nimport { restoreFocus } from \"../../../utils/restoreFocus\";\n\nexport interface ModalProps {\n size?: \"small\" | \"medium\" | \"large\" | \"fullscreen\";\n closeOnOutsideClick?: boolean;\n onClose?: () => void;\n open: boolean;\n animation?: \"fade\" | \"scale\" | \"drop\";\n className?: string;\n backdrop?: \"blured\" | \"dark\" | \"transparent\" | \"darkBlured\";\n asForm?: boolean;\n disableAppearAnimation?: boolean;\n /** ARIA role of the dialog. */\n role?: \"dialog\" | \"alertdialog\";\n /** Close the modal when Escape is pressed. */\n closeOnEsc?: boolean;\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n}\n\n/**\n * Whether `overlay` is the last open Modal overlay; a dialog stacked above it owns Tab. Fading-out\n * ones do not count. Not `isTopOverlayLayer`: menus, select dropdowns and pickers are overlay\n * layers too, and a select dropdown open inside a Modal must not switch the Modal's trap off.\n */\nfunction isTopModal(overlay: Element | null | undefined): boolean {\n if (!overlay || typeof document === \"undefined\") return true;\n const open = document.querySelectorAll(\".smwb-modal__overlay:not(.smwb-modal__overlay-exit)\");\n return open[open.length - 1] === overlay;\n}\n\n/**\n * A modal dialog: portaled to `<body>`, animated, closed by Escape or a backdrop click.\n *\n * While open it traps Tab/Shift+Tab inside the dialog and moves the focus into it (the first tab\n * stop, else the dialog itself), unless a child has already focused itself. On close, and on\n * unmount while open, the focus goes back to the element that had it when the dialog opened —\n * unless the app has moved the focus elsewhere by then.\n * Of stacked dialogs only the topmost one handles Tab.\n */\nconst ModalBase = forwardRef<HTMLDivElement, PropsWithChildren<ModalProps>>(function Modal(\n {\n children,\n onClose,\n open,\n className,\n animation = \"fade\",\n backdrop = \"dark\",\n size = \"large\",\n closeOnOutsideClick = true,\n asForm = false,\n disableAppearAnimation = false,\n role = \"dialog\",\n closeOnEsc = true,\n ...rest\n },\n ref\n) {\n const [domRoot, setDomRoot] = useState<HTMLElement>();\n\n const nodeRef = useRef<HTMLDivElement>(null);\n const contentRef = useRef<HTMLDivElement>(null);\n // The dialog element as state too: the content is portaled and appears a commit after `open`, and\n // the trap only re-runs when `active` changes, so a plain ref that fills in later would never arm it.\n const [contentEl, setContentEl] = useState<HTMLDivElement | null>(null);\n const forkedContentRef = useForkRef<HTMLDivElement>(ref, contentRef, setContentEl);\n\n useSafeLayoutEffect(() => {\n setDomRoot(document.body);\n }, []);\n\n // The opener is captured in an insertion effect, which runs in the mutation phase of the open\n // commit: before React focuses an `autoFocus` child (that happens in the layout phase, ahead of\n // any layout effect of this component), before the children's passive effects (a CommandPalette\n // focusing its input) and before the trap moves the focus into the dialog.\n const openerRef = useRef<Element | null>(null);\n useInsertionEffect(() => {\n if (!open) return;\n openerRef.current = contentRef.current?.contains(document.activeElement) ? null : document.activeElement;\n }, [open]);\n\n // The element focused when the dialog opens gets focus back when it closes or unmounts while open,\n // unless the app has moved focus out of the dialog by then (see restoreFocus). The return runs in a\n // passive cleanup, not in a layout one: React gives the focus back to whatever was focused when the\n // commit started (resetAfterCommit -> restoreSelection), and a closing dialog is still in the\n // document during its fade-out, so restoring inside that commit is undone. The palette relied on a\n // setTimeout(0) for the same reason.\n useEffect(() => {\n if (!open) return;\n const opener = openerRef.current;\n return () => {\n // The dialog is read here, not captured above: mounted with `open` it appears only a commit\n // after this effect runs, so a capture would hold null and skip the return. On unmount the ref\n // is already null, which is the \"root is gone\" case restoreFocus handles.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n restoreFocus(opener, contentRef.current);\n };\n }, [open]);\n\n const isTopmost = useCallback(() => isTopModal(nodeRef.current), []);\n useFocusTrap(contentRef, { active: open && contentEl !== null, restoreFocus: false, isTopmost });\n\n useEffect(() => {\n if (!open || !closeOnEsc || !onClose) {\n return;\n }\n const onKeyDown = (event: KeyboardEvent) => {\n // Only the topmost overlay layer reacts to Escape, and not to one handled inside\n // it, e.g. by a menu closing on it.\n if (event.key === \"Escape\" && !event.defaultPrevented && isTopOverlayLayer(nodeRef.current)) {\n onClose();\n }\n };\n document.addEventListener(\"keydown\", onKeyDown);\n\n return () => document.removeEventListener(\"keydown\", onKeyDown);\n }, [open, closeOnEsc, onClose]);\n\n if (!domRoot) {\n return <></>;\n }\n\n const Component = (asForm ? \"form\" : \"div\") as \"div\";\n\n return createPortal(\n <CSSTransition\n timeout={{\n appear: 225,\n enter: 225,\n exit: 150,\n }}\n in={open}\n classNames={{\n appear: \"smwb-modal__overlay-appear\",\n appearActive: \"smwb-modal__overlay-appear-active\",\n appearDone: \"smwb-modal__overlay-appear-done\",\n enter: \"smwb-modal__overlay-enter\",\n enterActive: \"smwb-modal__overlay-enter-active\",\n enterDone: \"smwb-modal__overlay-enter-done\",\n exit: \"smwb-modal__overlay-exit\",\n exitActive: \"smwb-modal__overlay-exit-active\",\n }}\n appear={!disableAppearAnimation}\n mountOnEnter\n unmountOnExit\n nodeRef={nodeRef}\n >\n <div\n ref={nodeRef}\n data-smwb-overlay-layer=\"\"\n className={cn(\"smwb-modal__overlay\", `smwb-${backdrop}`, `smwb-${size}`)}\n onClick={closeOnOutsideClick && onClose ? onClose : undefined}\n >\n <Component\n ref={forkedContentRef}\n className={cn(\"smwb-modal\", `smwb-${size}`, `smwb-${animation}`, className)}\n onClick={(e) => e.stopPropagation()}\n tabIndex={-1}\n role={role}\n aria-modal=\"true\"\n {...rest}\n >\n {children}\n </Component>\n </div>\n </CSSTransition>,\n domRoot\n );\n});\n\nexport interface HeaderProps {\n className?: string;\n}\n\nexport function Header({ className, children }: PropsWithChildren<HeaderProps>) {\n return <div className={cn(\"smwb-modal__header\", className)}>{children}</div>;\n}\n\nexport interface ContentProps {\n className?: string;\n}\n\nexport function Content({ className, children }: PropsWithChildren<ContentProps>) {\n return <div className={cn(\"smwb-modal__content\", className)}>{children}</div>;\n}\n\nexport interface FooterProps {\n className?: string;\n}\n\nexport function Footer({ className, children }: PropsWithChildren<FooterProps>) {\n return <div className={cn(\"smwb-modal__footer\", className)}>{children}</div>;\n}\n\nexport const Modal = Object.assign(ModalBase, {\n Footer,\n Header,\n Content,\n});\n\nexport default Modal;\n"],"names":["isTopModal","overlay","open","ModalBase","forwardRef","children","onClose","className","animation","backdrop","size","closeOnOutsideClick","asForm","disableAppearAnimation","role","closeOnEsc","rest","ref","domRoot","setDomRoot","useState","nodeRef","useRef","contentRef","contentEl","setContentEl","forkedContentRef","useForkRef","useSafeLayoutEffect","openerRef","useInsertionEffect","_a","useEffect","opener","restoreFocus","isTopmost","useCallback","useFocusTrap","onKeyDown","event","isTopOverlayLayer","jsx","Fragment","Component","createPortal","CSSTransition","cn","e","Header","Content","Footer","Modal"],"mappings":"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"}
@@ -1,78 +1,84 @@
1
- import { jsx as N, jsxs as $ } from "react/jsx-runtime";
2
- import g from "react";
1
+ import { jsx as k, jsxs as y } from "react/jsx-runtime";
2
+ import x from "react";
3
3
  import W from "clsx";
4
- import { Ripple as q } from "../../base/ripple/ripple.js";
5
- import { Icon as v } from "../../base/icon/icon.js";
6
- const L = g.forwardRef(
7
- function(j, m) {
8
- var y;
4
+ import { Ripple as _ } from "../../base/ripple/ripple.js";
5
+ import { resolveLinkRel as q, resolveLinkTarget as A } from "../../../utils/linkAttrs.js";
6
+ import { Icon as F } from "../../base/icon/icon.js";
7
+ const T = x.forwardRef(
8
+ function(N, c) {
9
9
  const {
10
10
  label: n,
11
- variant: k = "contained",
12
- icon: e,
13
- iconProps: B = {},
14
- href: a,
11
+ variant: $ = "contained",
12
+ icon: o,
13
+ iconProps: j = {},
14
+ href: m,
15
+ target: v,
16
+ rel: B,
15
17
  className: D,
16
18
  disabled: r,
17
- children: p,
19
+ children: a,
18
20
  onMouseDown: i,
19
21
  // The button sets this on its root too; its own handler calls the caller's first.
20
22
  onPointerDown: s,
21
23
  fullWidth: E,
22
- rippleCenter: _,
24
+ rippleCenter: L,
23
25
  disableRipple: z,
24
26
  size: C = "medium",
25
27
  colorTheme: M = "primary",
26
28
  color: l,
27
- "data-testid": t,
28
- ...c
29
- } = j, b = l != null ? l : M, f = g.useRef(null), u = (o) => {
30
- i == null || i(o);
31
- }, d = (o) => {
32
- var x;
33
- s == null || s(o), r || (x = f.current) == null || x.onRipple(o);
29
+ "data-testid": e,
30
+ ...p
31
+ } = N, f = l != null ? l : M, u = x.useRef(null), b = (t) => {
32
+ i == null || i(t);
33
+ }, d = (t) => {
34
+ var g;
35
+ s == null || s(t), r || (g = u.current) == null || g.onRipple(t);
34
36
  }, w = W(
35
37
  "smwb-button",
36
- `smwb-${k}`,
38
+ `smwb-${$}`,
37
39
  `smwb-${C}`,
38
- b === "primary" ? "smwb-primary" : `smwb-button_color-${b}`,
40
+ f === "primary" ? "smwb-primary" : `smwb-button_color-${f}`,
39
41
  D,
40
42
  {
41
43
  "smwb-disabled": r,
42
44
  "smwb-full-width": E
43
45
  }
44
- ), R = !z && /* @__PURE__ */ N(q, { actionRef: f, center: _ }), h = typeof e == "string" ? /* @__PURE__ */ N(v, { ...B, name: e }) : e;
45
- return a ? /* @__PURE__ */ $(
46
- "a",
47
- {
48
- "data-testid": t != null ? t : "button-link",
49
- ref: m,
50
- className: w,
51
- href: a,
52
- target: "_blank",
53
- onMouseDown: u,
54
- onPointerDown: d,
55
- ...c,
56
- rel: (y = c.rel) != null ? y : "noreferrer",
57
- children: [
58
- e && h,
59
- n || p,
60
- R
61
- ]
62
- }
63
- ) : /* @__PURE__ */ $(
46
+ ), R = !z && /* @__PURE__ */ k(_, { actionRef: u, center: L }), h = typeof o == "string" ? /* @__PURE__ */ k(F, { ...j, name: o }) : o;
47
+ if (m) {
48
+ const t = A(v);
49
+ return /* @__PURE__ */ y(
50
+ "a",
51
+ {
52
+ "data-testid": e != null ? e : "button-link",
53
+ ref: c,
54
+ className: w,
55
+ href: m,
56
+ target: t,
57
+ rel: q(B, t),
58
+ onMouseDown: b,
59
+ onPointerDown: d,
60
+ ...p,
61
+ children: [
62
+ o && h,
63
+ n || a,
64
+ R
65
+ ]
66
+ }
67
+ );
68
+ }
69
+ return /* @__PURE__ */ y(
64
70
  "button",
65
71
  {
66
- "data-testid": t != null ? t : "button",
67
- ref: m,
72
+ "data-testid": e != null ? e : "button",
73
+ ref: c,
68
74
  className: w,
69
- onMouseDown: u,
75
+ onMouseDown: b,
70
76
  onPointerDown: d,
71
77
  disabled: !!r,
72
- ...c,
78
+ ...p,
73
79
  children: [
74
- e && h,
75
- n || p,
80
+ o && h,
81
+ n || a,
76
82
  R
77
83
  ]
78
84
  }
@@ -80,7 +86,7 @@ const L = g.forwardRef(
80
86
  }
81
87
  );
82
88
  export {
83
- L as Button,
84
- L as default
89
+ T as Button,
90
+ T as default
85
91
  };
86
92
  //# sourceMappingURL=button.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"button.js","sources":["../../../../../src/components/inputs/button/button.tsx"],"sourcesContent":["import React, { PropsWithChildren } from \"react\";\nimport cn from \"clsx\";\nimport { Ripple, RippleActionsRef } from \"../../base/ripple/ripple\";\nimport { Icon, IconProps } from \"../../base/icon\";\n\nexport interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement> {\n /**\n * Текст на кнопке.\n */\n label?: string;\n\n /**\n * Вариант стилизации кнопки.\n */\n variant?: \"contained\" | \"text\" | \"outlined\";\n\n /**\n * Размер кнопки.\n */\n size?: \"small\" | \"medium\" | \"large\";\n\n /**\n * Иконка, которая может быть ReactNode (например, <Icon/>) или строкой (url, base64, и т.д.).\n */\n icon?: React.ReactNode | string;\n\n /**\n * Пропсы для иконки (исключая 'name', если в IconProps оно обязательно).\n */\n iconProps?: Omit<IconProps, \"name\">;\n\n /**\n * @deprecated используйте `color`. Оставлено для обратной совместимости.\n */\n colorTheme?: \"primary\";\n\n /**\n * Семантический цвет кнопки. Резолвится через токены `--smui-*Color*`.\n */\n color?: \"primary\" | \"secondary\" | \"error\" | \"success\" | \"warning\" | \"info\";\n\n /**\n * Ссылка. Если задана, компонент может рендериться как <a>.\n */\n href?: string;\n\n /**\n * Отключённое состояние.\n */\n disabled?: boolean;\n\n /**\n * Тип кнопки.\n */\n type?: \"button\" | \"submit\" | \"reset\";\n\n /**\n * Растягивать кнопку по всей ширине контейнера.\n */\n fullWidth?: boolean;\n\n /**\n * Позиция риппл-эффекта по центру.\n */\n rippleCenter?: boolean;\n\n /**\n * Отключить риппл-эффект.\n */\n disableRipple?: boolean;\n\n /** Test id of the root; `button`, or `button-link` for a link, unless given. */\n \"data-testid\"?: string;\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement, PropsWithChildren<ButtonProps>>(\n function Button(props, ref) {\n const {\n label,\n variant = \"contained\",\n icon,\n iconProps = {},\n href,\n className,\n disabled,\n children,\n onMouseDown: onMouseDownProp,\n // The button sets this on its root too; its own handler calls the caller's first.\n onPointerDown: onPointerDownProp,\n fullWidth,\n rippleCenter,\n disableRipple,\n\n size = \"medium\",\n colorTheme = \"primary\",\n color: colorProp,\n \"data-testid\": dataTestId,\n ...rest\n } = props;\n const color = colorProp ?? colorTheme;\n const rippleRef = React.useRef<RippleActionsRef>(null);\n\n const onMouseDown = (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {\n onMouseDownProp?.(event);\n };\n\n // Ripple on pointerdown so it fires for touch and pen, not just mouse.\n const onPointerDown = (event: React.PointerEvent<HTMLButtonElement | HTMLAnchorElement>) => {\n onPointerDownProp?.(event);\n if (!disabled) {\n rippleRef.current?.onRipple(event);\n }\n };\n\n const classes = cn(\n \"smwb-button\",\n `smwb-${variant}`,\n `smwb-${size}`,\n color === \"primary\" ? \"smwb-primary\" : `smwb-button_color-${color}`,\n className,\n {\n \"smwb-disabled\": disabled,\n \"smwb-full-width\": fullWidth,\n }\n );\n\n const rippleElement = !disableRipple && <Ripple actionRef={rippleRef} center={rippleCenter} />;\n const iconElement = typeof icon === \"string\" ? <Icon {...iconProps} name={icon} /> : icon;\n\n if (href) {\n return (\n <a\n data-testid={dataTestId ?? \"button-link\"}\n ref={ref as React.LegacyRef<HTMLAnchorElement>}\n className={classes}\n href={href}\n target=\"_blank\"\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n {...rest}\n // A default: the caller's rel wins, and an explicit undefined keeps it.\n rel={rest.rel ?? \"noreferrer\"}\n >\n {icon && iconElement}\n {label ? label : children}\n {rippleElement}\n </a>\n );\n }\n\n return (\n <button\n data-testid={dataTestId ?? \"button\"}\n ref={ref as React.LegacyRef<HTMLButtonElement>}\n className={classes}\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n disabled={!!disabled}\n {...rest}\n >\n {icon && iconElement}\n {label ? label : children}\n {rippleElement}\n </button>\n );\n }\n);\nexport default Button;\n"],"names":["Button","React","props","ref","label","variant","icon","iconProps","href","className","disabled","children","onMouseDownProp","onPointerDownProp","fullWidth","rippleCenter","disableRipple","size","colorTheme","colorProp","dataTestId","rest","color","rippleRef","onMouseDown","event","onPointerDown","_a","classes","cn","rippleElement","jsx","Ripple","iconElement","Icon","jsxs"],"mappings":";;;;;AA2EO,MAAMA,IAASC,EAAM;AAAA,EAC1B,SAAgBC,GAAOC,GAAK;;AAC1B,UAAM;AAAA,MACJ,OAAAC;AAAA,MACA,SAAAC,IAAU;AAAA,MACV,MAAAC;AAAA,MACA,WAAAC,IAAY,CAAA;AAAA,MACZ,MAAAC;AAAA,MACA,WAAAC;AAAA,MACA,UAAAC;AAAA,MACA,UAAAC;AAAA,MACA,aAAaC;AAAA;AAAA,MAEb,eAAeC;AAAA,MACf,WAAAC;AAAA,MACA,cAAAC;AAAA,MACA,eAAAC;AAAA,MAEA,MAAAC,IAAO;AAAA,MACP,YAAAC,IAAa;AAAA,MACb,OAAOC;AAAA,MACP,eAAeC;AAAA,MACf,GAAGC;AAAA,IAAA,IACDnB,GACEoB,IAAQH,KAAA,OAAAA,IAAaD,GACrBK,IAAYtB,EAAM,OAAyB,IAAI,GAE/CuB,IAAc,CAACC,MAAmE;AACtF,MAAAb,KAAA,QAAAA,EAAkBa;AAAA,IACpB,GAGMC,IAAgB,CAACD,MAAqE;;AAC1F,MAAAZ,KAAA,QAAAA,EAAoBY,IACff,MACHiB,IAAAJ,EAAU,YAAV,QAAAI,EAAmB,SAASF;AAAA,IAEhC,GAEMG,IAAUC;AAAA,MACd;AAAA,MACA,QAAQxB,CAAO;AAAA,MACf,QAAQY,CAAI;AAAA,MACZK,MAAU,YAAY,iBAAiB,qBAAqBA,CAAK;AAAA,MACjEb;AAAA,MACA;AAAA,QACE,iBAAiBC;AAAA,QACjB,mBAAmBI;AAAA,MAAA;AAAA,IACrB,GAGIgB,IAAgB,CAACd,KAAiB,gBAAAe,EAACC,KAAO,WAAWT,GAAW,QAAQR,GAAc,GACtFkB,IAAc,OAAO3B,KAAS,WAAW,gBAAAyB,EAACG,KAAM,GAAG3B,GAAW,MAAMD,EAAA,CAAM,IAAKA;AAErF,WAAIE,IAEA,gBAAA2B;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,eAAaf,KAAA,OAAAA,IAAc;AAAA,QAC3B,KAAAjB;AAAA,QACA,WAAWyB;AAAA,QACX,MAAApB;AAAA,QACA,QAAO;AAAA,QACP,aAAAgB;AAAA,QACA,eAAAE;AAAA,QACC,GAAGL;AAAA,QAEJ,MAAKM,IAAAN,EAAK,QAAL,OAAAM,IAAY;AAAA,QAEhB,UAAA;AAAA,UAAArB,KAAQ2B;AAAA,UACR7B,KAAgBO;AAAA,UAChBmB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA,IAML,gBAAAK;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,eAAaf,KAAA,OAAAA,IAAc;AAAA,QAC3B,KAAAjB;AAAA,QACA,WAAWyB;AAAA,QACX,aAAAJ;AAAA,QACA,eAAAE;AAAA,QACA,UAAU,CAAC,CAAChB;AAAA,QACX,GAAGW;AAAA,QAEH,UAAA;AAAA,UAAAf,KAAQ2B;AAAA,UACR7B,KAAgBO;AAAA,UAChBmB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;"}
1
+ {"version":3,"file":"button.js","sources":["../../../../../src/components/inputs/button/button.tsx"],"sourcesContent":["import React, { PropsWithChildren } from \"react\";\nimport cn from \"clsx\";\nimport { Ripple, RippleActionsRef } from \"../../base/ripple/ripple\";\nimport { Icon, IconProps } from \"../../base/icon\";\nimport { resolveLinkRel, resolveLinkTarget } from \"../../../utils/linkAttrs\";\n\nexport interface ButtonProps extends React.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement> {\n /**\n * Текст на кнопке.\n */\n label?: string;\n\n /**\n * Вариант стилизации кнопки.\n */\n variant?: \"contained\" | \"text\" | \"outlined\";\n\n /**\n * Размер кнопки.\n */\n size?: \"small\" | \"medium\" | \"large\";\n\n /**\n * Иконка, которая может быть ReactNode (например, <Icon/>) или строкой (url, base64, и т.д.).\n */\n icon?: React.ReactNode | string;\n\n /**\n * Пропсы для иконки (исключая 'name', если в IconProps оно обязательно).\n */\n iconProps?: Omit<IconProps, \"name\">;\n\n /**\n * @deprecated используйте `color`. Оставлено для обратной совместимости.\n */\n colorTheme?: \"primary\";\n\n /**\n * Семантический цвет кнопки. Резолвится через токены `--smui-*Color*`.\n */\n color?: \"primary\" | \"secondary\" | \"error\" | \"success\" | \"warning\" | \"info\";\n\n /**\n * Ссылка. Если задана, компонент рендерится как <a>.\n */\n href?: string;\n\n /**\n * Where a link (with `href`) opens. By default `\"_blank\"`: a new tab. `null` leaves the `target`\n * attribute out, so the link opens in place, like an internal one; an empty string does the same, and\n * any other string is used as is.\n */\n target?: string | null;\n\n /**\n * The `rel` of a link (with `href`). By default `\"noreferrer\"` for a link that opens another tab or\n * window, and none for one that opens in place. Your own value replaces the default, so add `noreferrer` yourself\n * if you still want it; an empty string drops the attribute.\n */\n rel?: string;\n\n /**\n * Отключённое состояние.\n */\n disabled?: boolean;\n\n /**\n * Тип кнопки.\n */\n type?: \"button\" | \"submit\" | \"reset\";\n\n /**\n * Растягивать кнопку по всей ширине контейнера.\n */\n fullWidth?: boolean;\n\n /**\n * Позиция риппл-эффекта по центру.\n */\n rippleCenter?: boolean;\n\n /**\n * Отключить риппл-эффект.\n */\n disableRipple?: boolean;\n\n /** Test id of the root; `button`, or `button-link` for a link, unless given. */\n \"data-testid\"?: string;\n}\n\nexport const Button = React.forwardRef<HTMLButtonElement | HTMLAnchorElement, PropsWithChildren<ButtonProps>>(\n function Button(props, ref) {\n const {\n label,\n variant = \"contained\",\n icon,\n iconProps = {},\n href,\n target,\n rel,\n className,\n disabled,\n children,\n onMouseDown: onMouseDownProp,\n // The button sets this on its root too; its own handler calls the caller's first.\n onPointerDown: onPointerDownProp,\n fullWidth,\n rippleCenter,\n disableRipple,\n\n size = \"medium\",\n colorTheme = \"primary\",\n color: colorProp,\n \"data-testid\": dataTestId,\n ...rest\n } = props;\n const color = colorProp ?? colorTheme;\n const rippleRef = React.useRef<RippleActionsRef>(null);\n\n const onMouseDown = (event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {\n onMouseDownProp?.(event);\n };\n\n // Ripple on pointerdown so it fires for touch and pen, not just mouse.\n const onPointerDown = (event: React.PointerEvent<HTMLButtonElement | HTMLAnchorElement>) => {\n onPointerDownProp?.(event);\n if (!disabled) {\n rippleRef.current?.onRipple(event);\n }\n };\n\n const classes = cn(\n \"smwb-button\",\n `smwb-${variant}`,\n `smwb-${size}`,\n color === \"primary\" ? \"smwb-primary\" : `smwb-button_color-${color}`,\n className,\n {\n \"smwb-disabled\": disabled,\n \"smwb-full-width\": fullWidth,\n }\n );\n\n const rippleElement = !disableRipple && <Ripple actionRef={rippleRef} center={rippleCenter} />;\n const iconElement = typeof icon === \"string\" ? <Icon {...iconProps} name={icon} /> : icon;\n\n if (href) {\n const linkTarget = resolveLinkTarget(target);\n return (\n <a\n data-testid={dataTestId ?? \"button-link\"}\n ref={ref as React.LegacyRef<HTMLAnchorElement>}\n className={classes}\n href={href}\n target={linkTarget}\n rel={resolveLinkRel(rel, linkTarget)}\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n {...rest}\n >\n {icon && iconElement}\n {label ? label : children}\n {rippleElement}\n </a>\n );\n }\n\n return (\n <button\n data-testid={dataTestId ?? \"button\"}\n ref={ref as React.LegacyRef<HTMLButtonElement>}\n className={classes}\n onMouseDown={onMouseDown}\n onPointerDown={onPointerDown}\n disabled={!!disabled}\n {...rest}\n >\n {icon && iconElement}\n {label ? label : children}\n {rippleElement}\n </button>\n );\n }\n);\nexport default Button;\n"],"names":["Button","React","props","ref","label","variant","icon","iconProps","href","target","rel","className","disabled","children","onMouseDownProp","onPointerDownProp","fullWidth","rippleCenter","disableRipple","size","colorTheme","colorProp","dataTestId","rest","color","rippleRef","onMouseDown","event","onPointerDown","_a","classes","cn","rippleElement","jsx","Ripple","iconElement","Icon","linkTarget","resolveLinkTarget","jsxs","resolveLinkRel"],"mappings":";;;;;;AA0FO,MAAMA,IAASC,EAAM;AAAA,EAC1B,SAAgBC,GAAOC,GAAK;AAC1B,UAAM;AAAA,MACJ,OAAAC;AAAA,MACA,SAAAC,IAAU;AAAA,MACV,MAAAC;AAAA,MACA,WAAAC,IAAY,CAAA;AAAA,MACZ,MAAAC;AAAA,MACA,QAAAC;AAAA,MACA,KAAAC;AAAA,MACA,WAAAC;AAAA,MACA,UAAAC;AAAA,MACA,UAAAC;AAAA,MACA,aAAaC;AAAA;AAAA,MAEb,eAAeC;AAAA,MACf,WAAAC;AAAA,MACA,cAAAC;AAAA,MACA,eAAAC;AAAA,MAEA,MAAAC,IAAO;AAAA,MACP,YAAAC,IAAa;AAAA,MACb,OAAOC;AAAA,MACP,eAAeC;AAAA,MACf,GAAGC;AAAA,IAAA,IACDrB,GACEsB,IAAQH,KAAA,OAAAA,IAAaD,GACrBK,IAAYxB,EAAM,OAAyB,IAAI,GAE/CyB,IAAc,CAACC,MAAmE;AACtF,MAAAb,KAAA,QAAAA,EAAkBa;AAAA,IACpB,GAGMC,IAAgB,CAACD,MAAqE;;AAC1F,MAAAZ,KAAA,QAAAA,EAAoBY,IACff,MACHiB,IAAAJ,EAAU,YAAV,QAAAI,EAAmB,SAASF;AAAA,IAEhC,GAEMG,IAAUC;AAAA,MACd;AAAA,MACA,QAAQ1B,CAAO;AAAA,MACf,QAAQc,CAAI;AAAA,MACZK,MAAU,YAAY,iBAAiB,qBAAqBA,CAAK;AAAA,MACjEb;AAAA,MACA;AAAA,QACE,iBAAiBC;AAAA,QACjB,mBAAmBI;AAAA,MAAA;AAAA,IACrB,GAGIgB,IAAgB,CAACd,KAAiB,gBAAAe,EAACC,KAAO,WAAWT,GAAW,QAAQR,GAAc,GACtFkB,IAAc,OAAO7B,KAAS,WAAW,gBAAA2B,EAACG,KAAM,GAAG7B,GAAW,MAAMD,EAAA,CAAM,IAAKA;AAErF,QAAIE,GAAM;AACR,YAAM6B,IAAaC,EAAkB7B,CAAM;AAC3C,aACE,gBAAA8B;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,eAAajB,KAAA,OAAAA,IAAc;AAAA,UAC3B,KAAAnB;AAAA,UACA,WAAW2B;AAAA,UACX,MAAAtB;AAAA,UACA,QAAQ6B;AAAA,UACR,KAAKG,EAAe9B,GAAK2B,CAAU;AAAA,UACnC,aAAAX;AAAA,UACA,eAAAE;AAAA,UACC,GAAGL;AAAA,UAEH,UAAA;AAAA,YAAAjB,KAAQ6B;AAAA,YACR/B,KAAgBS;AAAA,YAChBmB;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,IAGP;AAEA,WACE,gBAAAO;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,eAAajB,KAAA,OAAAA,IAAc;AAAA,QAC3B,KAAAnB;AAAA,QACA,WAAW2B;AAAA,QACX,aAAAJ;AAAA,QACA,eAAAE;AAAA,QACA,UAAU,CAAC,CAAChB;AAAA,QACX,GAAGW;AAAA,QAEH,UAAA;AAAA,UAAAjB,KAAQ6B;AAAA,UACR/B,KAAgBS;AAAA,UAChBmB;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAGP;AACF;"}
@@ -0,0 +1,217 @@
1
+ import { jsxs as De, jsx as t } from "react/jsx-runtime";
2
+ import A, { useState as Ce } from "react";
3
+ import L from "clsx";
4
+ import { Icon as H } from "../../base/icon/icon.js";
5
+ import { useControllableState as xe } from "../../../hooks/useControllableState.js";
6
+ import { useDropzone as Ke } from "../../../hooks/useDropzone.js";
7
+ import { useId as Ne } from "../../../hooks/useId.js";
8
+ import { filterAttachedFiles as Le, isFileDrag as V } from "./composerFiles.js";
9
+ import { resolveComposerKeyAction as Ae } from "./composerKeys.js";
10
+ const ke = (o) => o >= 0 ? `${o} characters left` : `${-o} characters over the limit`;
11
+ function Te(o) {
12
+ o.preventDefault();
13
+ }
14
+ function b(o) {
15
+ return Array.isArray(o) ? o.some(b) : A.isValidElement(o) && o.type === A.Fragment ? b(o.props.children) : o != null && typeof o != "boolean" && o !== "";
16
+ }
17
+ const He = A.forwardRef(function(q, G) {
18
+ const {
19
+ value: J,
20
+ defaultValue: f,
21
+ onValueChange: Q,
22
+ onSend: h,
23
+ sendKey: U = "modEnter",
24
+ clearOnSend: W = !0,
25
+ busy: r = !1,
26
+ onStop: y,
27
+ placeholder: X,
28
+ maxLength: a,
29
+ counter: g,
30
+ counterAnnouncement: Y = ke,
31
+ minRows: w = 1,
32
+ maxRows: Z = 8,
33
+ layout: ee = "stacked",
34
+ toolbar: k,
35
+ attachments: T,
36
+ onAttach: i,
37
+ accept: S,
38
+ multiple: F = !0,
39
+ maxFiles: oe,
40
+ dropTarget: te = !0,
41
+ disabled: n = !1,
42
+ readOnly: R = !1,
43
+ autoFocus: ae,
44
+ name: re,
45
+ id: se,
46
+ "aria-label": ne,
47
+ "aria-labelledby": ie,
48
+ "aria-describedby": ce,
49
+ onKeyDown: _,
50
+ onFocus: v,
51
+ onBlur: D,
52
+ inputRef: le,
53
+ sendLabel: me = "Send",
54
+ stopLabel: de = "Stop",
55
+ attachLabel: pe = "Attach file",
56
+ className: ue,
57
+ "data-testid": C,
58
+ onDragOver: c,
59
+ onDragLeave: l,
60
+ onDrop: m,
61
+ ...be
62
+ } = q, [s, $] = xe({
63
+ value: J,
64
+ defaultValue: f != null ? f : "",
65
+ onChange: Q
66
+ }), [fe, M] = Ce(!1), O = Ne(se, "smwb-composer"), z = `${O}-counter`, d = Ke({
67
+ accept: S,
68
+ multiple: F,
69
+ disabled: n,
70
+ // `maxFiles` is not passed on: the cut has to come after `accept`, see `filterAttachedFiles`.
71
+ onDrop: (e) => {
72
+ const N = Le(e, { accept: S, multiple: F, maxFiles: oe });
73
+ N.length > 0 && (i == null || i(N));
74
+ }
75
+ }), x = d.getRootProps(), B = d.getInputProps(), K = i !== void 0, I = K && te, p = g != null ? g : a !== void 0, u = a !== void 0 && s.length > a, P = !!h && s.trim() !== "" && !n && !R && !r && !u;
76
+ let j = "";
77
+ if (p && a !== void 0) {
78
+ const e = a - s.length;
79
+ e <= Math.max(10, Math.ceil(a * 0.1)) && (j = Y(e, a));
80
+ }
81
+ const E = () => {
82
+ !P || !h || (h(s.trim()), W && $(""));
83
+ }, he = (e) => {
84
+ _ == null || _(e), !(e.defaultPrevented || Ae(
85
+ {
86
+ key: e.key,
87
+ shiftKey: e.shiftKey,
88
+ ctrlKey: e.ctrlKey,
89
+ metaKey: e.metaKey,
90
+ altKey: e.altKey,
91
+ isComposing: e.nativeEvent.isComposing,
92
+ keyCode: e.keyCode
93
+ },
94
+ U
95
+ ) === "native") && (e.preventDefault(), E());
96
+ }, ye = (e) => {
97
+ if (!(e.detail > 1)) {
98
+ if (r) {
99
+ n || y == null || y();
100
+ return;
101
+ }
102
+ E();
103
+ }
104
+ }, ge = I ? { onDragOver: (e) => {
105
+ c == null || c(e), V(e.dataTransfer) && x.onDragOver(e);
106
+ }, onDragLeave: (e) => {
107
+ l == null || l(e), !(e.relatedTarget instanceof Node && e.currentTarget.contains(e.relatedTarget)) && x.onDragLeave();
108
+ }, onDrop: (e) => {
109
+ m == null || m(e), V(e.dataTransfer) && x.onDrop(e);
110
+ } } : { onDragOver: c, onDragLeave: l, onDrop: m }, we = I && d.isDragActive, _e = {
111
+ "--smwb-composer-min-rows": w,
112
+ "--smwb-composer-max-rows": Math.max(Z, w)
113
+ }, ve = [ce, p ? z : void 0].filter(Boolean).join(" ") || void 0;
114
+ return /* @__PURE__ */ De(
115
+ "div",
116
+ {
117
+ ...be,
118
+ ...ge,
119
+ ref: G,
120
+ className: L(
121
+ "smwb-composer",
122
+ `smwb-composer_${ee}`,
123
+ fe && "smwb-composer_focused",
124
+ r && "smwb-composer_busy",
125
+ n && "smwb-composer_disabled",
126
+ we && "smwb-composer_drag-active",
127
+ u && "smwb-composer_over-limit",
128
+ ue
129
+ ),
130
+ "data-testid": C != null ? C : "composer",
131
+ children: [
132
+ b(T) ? /* @__PURE__ */ t("div", { className: "smwb-composer__attachments", "data-testid": "composer-attachments", children: T }) : null,
133
+ /* @__PURE__ */ t("div", { className: "smwb-composer__field", "data-value": s, style: _e, children: /* @__PURE__ */ t(
134
+ "textarea",
135
+ {
136
+ ref: le,
137
+ className: "smwb-composer__input",
138
+ id: O,
139
+ name: re,
140
+ rows: w,
141
+ placeholder: X,
142
+ maxLength: a,
143
+ disabled: n,
144
+ readOnly: R,
145
+ autoFocus: ae,
146
+ "aria-label": ne,
147
+ "aria-labelledby": ie,
148
+ "aria-describedby": ve,
149
+ "aria-invalid": u || void 0,
150
+ value: s,
151
+ onChange: (e) => $(e.target.value),
152
+ onKeyDown: he,
153
+ onFocus: (e) => {
154
+ v == null || v(e), M(!0);
155
+ },
156
+ onBlur: (e) => {
157
+ D == null || D(e), M(!1);
158
+ },
159
+ "data-testid": "composer-input"
160
+ }
161
+ ) }),
162
+ K ? /* @__PURE__ */ t(
163
+ "button",
164
+ {
165
+ type: "button",
166
+ className: "smwb-composer__icon-button smwb-composer__attach",
167
+ "aria-label": pe,
168
+ disabled: n,
169
+ onClick: d.open,
170
+ "data-testid": "composer-attach",
171
+ children: /* @__PURE__ */ t(H, { name: "attach_file", size: 20 })
172
+ }
173
+ ) : null,
174
+ b(k) ? /* @__PURE__ */ t("div", { className: "smwb-composer__toolbar", "data-testid": "composer-toolbar", children: k }) : null,
175
+ p ? /* @__PURE__ */ t(
176
+ "span",
177
+ {
178
+ id: z,
179
+ className: L("smwb-composer__counter", u && "smwb-composer__counter_error"),
180
+ "data-testid": "composer-counter",
181
+ children: a !== void 0 ? `${s.length} / ${a}` : s.length
182
+ }
183
+ ) : null,
184
+ /* @__PURE__ */ t(
185
+ "button",
186
+ {
187
+ type: "button",
188
+ className: L("smwb-composer__icon-button", "smwb-composer__action", r && "smwb-composer__action_stop"),
189
+ "aria-label": r ? de : me,
190
+ "aria-disabled": !r && !P ? !0 : void 0,
191
+ disabled: n,
192
+ "data-action": r ? "stop" : "send",
193
+ onMouseDown: Te,
194
+ onClick: ye,
195
+ "data-testid": "composer-action",
196
+ children: /* @__PURE__ */ t(H, { name: r ? "stop" : "send", size: 20 })
197
+ }
198
+ ),
199
+ p ? /* @__PURE__ */ t("span", { className: "smwb-composer__status", role: "status", "data-testid": "composer-status", children: j }) : null,
200
+ K ? /* @__PURE__ */ t(
201
+ "input",
202
+ {
203
+ ...B,
204
+ onChange: (e) => {
205
+ B.onChange(e), e.currentTarget.value = "";
206
+ },
207
+ "data-testid": "composer-file-input"
208
+ }
209
+ ) : null
210
+ ]
211
+ }
212
+ );
213
+ });
214
+ export {
215
+ He as Composer
216
+ };
217
+ //# sourceMappingURL=composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer.js","sources":["../../../../../src/components/inputs/composer/composer.tsx"],"sourcesContent":["import React, { useState } from \"react\";\nimport cn from \"clsx\";\nimport Icon from \"../../base/icon/icon\";\nimport { useControllableState } from \"../../../hooks/useControllableState\";\nimport { useDropzone } from \"../../../hooks/useDropzone\";\nimport type { DropzoneAccept } from \"../../../hooks/useDropzone\";\nimport { useId } from \"../../../hooks/useId\";\nimport { filterAttachedFiles, isFileDrag } from \"./composerFiles\";\nimport { resolveComposerKeyAction } from \"./composerKeys\";\nimport type { ComposerSendKey } from \"./composerKeys\";\n\n/** Where the toolbar and the action sit: under the field (`stacked`) or in one row with it (`inline`). */\nexport type ComposerLayout = \"stacked\" | \"inline\";\n\nexport interface ComposerProps extends Omit<\n React.HTMLAttributes<HTMLDivElement>,\n \"onChange\" | \"defaultValue\" | \"onKeyDown\" | \"onFocus\" | \"onBlur\" | \"children\"\n> {\n /**\n * Controlled text. The composer is controlled while this is not `undefined` (checked on every render); a parent\n * that ignores `onValueChange` keeps the field showing this value.\n */\n value?: string;\n /** Initial text while uncontrolled. Defaults to an empty string. */\n defaultValue?: string;\n /** Called on every text change: typing, a newline, and the clear after a send. Called in both modes. */\n onValueChange?: (value: string) => void;\n /**\n * Called with the trimmed text when the user sends it: the send key (see `sendKey`) or a click on the action\n * button. Nothing is called while sending is not allowed: no `onSend`, an empty or whitespace-only text, `disabled`,\n * `readOnly`, `busy`, or a text over `maxLength`. Async work is shown with `busy`; the return value is ignored.\n */\n onSend?: (text: string) => void;\n /**\n * Which Enter sends. `\"modEnter\"` (default): Ctrl/⌘+Enter sends and Enter inserts a newline. `\"enter\"`: Enter sends,\n * Shift+Enter inserts a newline, Ctrl/⌘+Enter sends too. An Enter that commits an IME composition never sends.\n */\n sendKey?: ComposerSendKey;\n /**\n * Clear the text after `onSend`: the composer's own state while uncontrolled, `onValueChange(\"\")` while controlled.\n * Defaults to `true`.\n */\n clearOnSend?: boolean;\n /**\n * The agent is working: the action button turns into Stop and calls `onStop`, and the keys and the button do not\n * send. The text stays editable. The composer never changes `busy` itself, the parent owns it.\n */\n busy?: boolean;\n /**\n * Called when Stop is pressed (click, Enter or Space on the button) while `busy` and not `disabled`. Without it the\n * Stop button does nothing, so pass it whenever `busy` can be set.\n */\n onStop?: () => void;\n /** Placeholder of the textarea. It is not a name for the field, set `aria-label` or `aria-labelledby` as well. */\n placeholder?: string;\n /**\n * Hard limit on the text (the native `maxlength` of the textarea, counted in UTF-16 units, so an emoji is 2).\n * Turns the counter on.\n */\n maxLength?: number;\n /** Show the counter (`n / maxLength`, or `n` without `maxLength`). Defaults to `true` when `maxLength` is set. */\n counter?: boolean;\n /**\n * Text for the polite status region that announces how many characters are left. It is spoken only near the limit\n * (within the larger of 10 characters and 10% of `maxLength`) and when the text is over it, with a negative\n * `remaining`. Defaults to \"N characters left\" / \"N characters over the limit\".\n */\n counterAnnouncement?: (remaining: number, maxLength: number) => string;\n /** Height of the empty field in rows, and the `rows` of the textarea. Defaults to `1`. */\n minRows?: number;\n /** Rows the field grows to before it scrolls. Clamped to at least `minRows`. Defaults to `8`. */\n maxRows?: number;\n /**\n * `\"stacked\"` (default): the field on top, a bar under it with the attach button, the toolbar, the counter and the\n * action. `\"inline\"`: the attach button, the field, the counter and the action in one row, the toolbar (if any)\n * in a row under it.\n */\n layout?: ComposerLayout;\n /**\n * Slot under the field for chips and selectors (agent, model, mode, …). Drawn in every state. It is a plain `div`,\n * not `role=\"toolbar\"`: the content brings its own keyboard handling and disabled state.\n */\n toolbar?: React.ReactNode;\n /**\n * Slot above the field for the app's file chips. The composer keeps no file state: the app lists what `onAttach`\n * gave it here.\n */\n attachments?: React.ReactNode;\n /**\n * Turns on the attach button, the hidden file input and the drop target (the whole composer). Called with the files\n * of a pick or a drop that are left after `accept`, `multiple` and `maxFiles`, never with an empty list. Only a drag\n * of files is taken: dragged text or a link still goes into the field.\n */\n onAttach?: (files: File[]) => void;\n /**\n * Accepted file types, as a record of mime type to extensions or a raw `accept` string (`image/*`, `.pdf`, an exact\n * mime type). It sets the picker's filter, and the files of a pick or a drop that do not match are left out.\n */\n accept?: DropzoneAccept;\n /** Allow several files per pick or drop. When `false` the picker takes one and a drop keeps the first. Defaults to `true`. */\n multiple?: boolean;\n /** Files beyond this number are dropped from a pick or a drop (counted after `accept`). */\n maxFiles?: number;\n /**\n * Whether `onAttach` also makes the composer a drop target for files. Set `false` when a parent already takes drops\n * (a chat panel): the attach button and the picker stay, and a drop on the composer bubbles to the parent untouched.\n * Defaults to `true`.\n */\n dropTarget?: boolean;\n /**\n * Disables the textarea, the attach button, the action button and the drop target. Toolbar content is the app's to\n * disable.\n */\n disabled?: boolean;\n /** The textarea is `readonly`: sending is unavailable, Stop still works. */\n readOnly?: boolean;\n /** Focus the textarea on mount. */\n autoFocus?: boolean;\n /** Name of the textarea. */\n name?: string;\n /** Id of the textarea (the root keeps no id). Generated when not given. */\n id?: string;\n /** Accessible name of the textarea. Set this or `aria-labelledby`: a placeholder is not a name. */\n \"aria-label\"?: string;\n /** Id(s) of the element(s) that name the textarea. */\n \"aria-labelledby\"?: string;\n /** Id(s) that describe the textarea. They come first, the counter's id is appended. */\n \"aria-describedby\"?: string;\n /** Key handler of the textarea. It runs before the composer's own; if it calls `preventDefault()`, the composer does nothing for that key. */\n onKeyDown?: React.KeyboardEventHandler<HTMLTextAreaElement>;\n /** Focus handler of the textarea. */\n onFocus?: React.FocusEventHandler<HTMLTextAreaElement>;\n /** Blur handler of the textarea. */\n onBlur?: React.FocusEventHandler<HTMLTextAreaElement>;\n /** Ref of the textarea (the root takes the component's own `ref`). */\n inputRef?: React.Ref<HTMLTextAreaElement>;\n /** Accessible name of the action button while it sends. Defaults to \"Send\". */\n sendLabel?: string;\n /** Accessible name of the action button while `busy`. Defaults to \"Stop\". */\n stopLabel?: string;\n /** Accessible name of the attach button. Defaults to \"Attach file\". */\n attachLabel?: string;\n /**\n * Class name(s) for the root `<div>`. `style`, `ref`, `data-*` attributes and every other HTML attribute or event\n * handler go to the root too; the root's drag handlers run after yours.\n */\n className?: string;\n /** Test id of the root `<div>`. Defaults to `composer`; the parts inside have their own (`composer-input`, `composer-action`, …). */\n \"data-testid\"?: string;\n}\n\nconst defaultCounterAnnouncement = (remaining: number): string =>\n remaining >= 0 ? `${remaining} characters left` : `${-remaining} characters over the limit`;\n\nfunction stopMouseDown(event: React.MouseEvent<HTMLElement>): void {\n // Keeps the focus in the textarea when the action button is clicked with a mouse.\n event.preventDefault();\n}\n\n// Whether a slot draws anything: null, false, \"\" and empty arrays or fragments do not.\nfunction isDrawn(node: React.ReactNode): boolean {\n if (Array.isArray(node)) return node.some(isDrawn);\n if (React.isValidElement<{ children?: React.ReactNode }>(node) && node.type === React.Fragment) {\n return isDrawn(node.props.children);\n }\n return node != null && typeof node !== \"boolean\" && node !== \"\";\n}\n\n/**\n * A task input: a multi-line field that grows from `minRows` to `maxRows`, a `toolbar` slot under it for chip\n * selectors, a send button that becomes Stop while `busy`, keyboard send (Ctrl/⌘+Enter by default), an optional\n * attach button and drop target, and a character counter.\n *\n * ```tsx\n * <Composer aria-label=\"Task for the agent\" onSend={(text) => run(text)} busy={running} onStop={cancel} />\n * ```\n */\nexport const Composer = React.forwardRef<HTMLDivElement, ComposerProps>(function Composer(props, ref) {\n const {\n value,\n defaultValue,\n onValueChange,\n onSend,\n sendKey = \"modEnter\",\n clearOnSend = true,\n busy = false,\n onStop,\n placeholder,\n maxLength,\n counter,\n counterAnnouncement = defaultCounterAnnouncement,\n minRows = 1,\n maxRows = 8,\n layout = \"stacked\",\n toolbar,\n attachments,\n onAttach,\n accept,\n multiple = true,\n maxFiles,\n dropTarget = true,\n disabled = false,\n readOnly = false,\n autoFocus,\n name,\n id,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n onKeyDown,\n onFocus,\n onBlur,\n inputRef,\n sendLabel = \"Send\",\n stopLabel = \"Stop\",\n attachLabel = \"Attach file\",\n className,\n \"data-testid\": testId,\n onDragOver,\n onDragLeave,\n onDrop,\n ...rest\n } = props;\n\n const [text, setText] = useControllableState<string>({\n value,\n defaultValue: defaultValue ?? \"\",\n onChange: onValueChange,\n });\n const [focused, setFocused] = useState(false);\n const textareaId = useId(id, \"smwb-composer\");\n const counterId = `${textareaId}-counter`;\n\n const dropzone = useDropzone({\n accept,\n multiple,\n disabled,\n // `maxFiles` is not passed on: the cut has to come after `accept`, see `filterAttachedFiles`.\n onDrop: (files) => {\n const attached = filterAttachedFiles(files, { accept, multiple, maxFiles });\n if (attached.length > 0) onAttach?.(attached);\n },\n });\n const dropHandlers = dropzone.getRootProps();\n const inputProps = dropzone.getInputProps();\n\n const attachable = onAttach !== undefined;\n // `dropTarget={false}` keeps the attach button and the picker but hands drops to a parent that owns the target.\n const dropping = attachable && dropTarget;\n\n const showCounter = counter ?? maxLength !== undefined;\n const overLimit = maxLength !== undefined && text.length > maxLength;\n const canSend = !!onSend && text.trim() !== \"\" && !disabled && !readOnly && !busy && !overLimit;\n\n let status = \"\";\n if (showCounter && maxLength !== undefined) {\n const remaining = maxLength - text.length;\n if (remaining <= Math.max(10, Math.ceil(maxLength * 0.1))) status = counterAnnouncement(remaining, maxLength);\n }\n\n const send = () => {\n if (!canSend || !onSend) return;\n onSend(text.trim());\n if (clearOnSend) setText(\"\");\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented) return;\n\n const action = resolveComposerKeyAction(\n {\n key: event.key,\n shiftKey: event.shiftKey,\n ctrlKey: event.ctrlKey,\n metaKey: event.metaKey,\n altKey: event.altKey,\n isComposing: event.nativeEvent.isComposing,\n keyCode: event.keyCode,\n },\n sendKey\n );\n if (action === \"native\") return;\n\n event.preventDefault();\n send();\n };\n\n const handleActionClick = (event: React.MouseEvent<HTMLButtonElement>) => {\n // The second click of a double-click lands on the node the first one turned into the other action (Send into\n // Stop once the parent sets `busy`). It is not a new press: keyboard activation has `detail` 0, a click 1.\n if (event.detail > 1) return;\n if (busy) {\n if (!disabled) onStop?.();\n return;\n }\n send();\n };\n\n const rootDragOver = (event: React.DragEvent<HTMLDivElement>) => {\n onDragOver?.(event);\n // Only a drag of files is the dropzone's. Text or a link keeps its default: the textarea inserts it.\n if (isFileDrag(event.dataTransfer)) dropHandlers.onDragOver(event);\n };\n const rootDragLeave = (event: React.DragEvent<HTMLDivElement>) => {\n onDragLeave?.(event);\n // A leave onto a descendant is not a leave: it would flicker the drag-active state over the toolbar chips.\n if (event.relatedTarget instanceof Node && event.currentTarget.contains(event.relatedTarget)) return;\n dropHandlers.onDragLeave();\n };\n const rootDrop = (event: React.DragEvent<HTMLDivElement>) => {\n onDrop?.(event);\n if (isFileDrag(event.dataTransfer)) dropHandlers.onDrop(event);\n };\n const dragHandlers = dropping\n ? { onDragOver: rootDragOver, onDragLeave: rootDragLeave, onDrop: rootDrop }\n : { onDragOver, onDragLeave, onDrop };\n\n const dragActive = dropping && dropzone.isDragActive;\n const fieldStyle = {\n \"--smwb-composer-min-rows\": minRows,\n \"--smwb-composer-max-rows\": Math.max(maxRows, minRows),\n } as React.CSSProperties;\n const describedBy = [ariaDescribedBy, showCounter ? counterId : undefined].filter(Boolean).join(\" \") || undefined;\n\n return (\n <div\n {...rest}\n {...dragHandlers}\n ref={ref}\n className={cn(\n \"smwb-composer\",\n `smwb-composer_${layout}`,\n focused && \"smwb-composer_focused\",\n busy && \"smwb-composer_busy\",\n disabled && \"smwb-composer_disabled\",\n dragActive && \"smwb-composer_drag-active\",\n overLimit && \"smwb-composer_over-limit\",\n className\n )}\n data-testid={testId ?? \"composer\"}\n >\n {isDrawn(attachments) ? (\n <div className=\"smwb-composer__attachments\" data-testid=\"composer-attachments\">\n {attachments}\n </div>\n ) : null}\n <div className=\"smwb-composer__field\" data-value={text} style={fieldStyle}>\n <textarea\n ref={inputRef}\n className=\"smwb-composer__input\"\n id={textareaId}\n name={name}\n rows={minRows}\n placeholder={placeholder}\n maxLength={maxLength}\n disabled={disabled}\n readOnly={readOnly}\n autoFocus={autoFocus}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={describedBy}\n aria-invalid={overLimit || undefined}\n value={text}\n onChange={(event) => setText(event.target.value)}\n onKeyDown={handleKeyDown}\n onFocus={(event) => {\n onFocus?.(event);\n setFocused(true);\n }}\n onBlur={(event) => {\n onBlur?.(event);\n setFocused(false);\n }}\n data-testid=\"composer-input\"\n />\n </div>\n {attachable ? (\n <button\n type=\"button\"\n className=\"smwb-composer__icon-button smwb-composer__attach\"\n aria-label={attachLabel}\n disabled={disabled}\n onClick={dropzone.open}\n data-testid=\"composer-attach\"\n >\n <Icon name=\"attach_file\" size={20} />\n </button>\n ) : null}\n {isDrawn(toolbar) ? (\n <div className=\"smwb-composer__toolbar\" data-testid=\"composer-toolbar\">\n {toolbar}\n </div>\n ) : null}\n {showCounter ? (\n <span\n id={counterId}\n className={cn(\"smwb-composer__counter\", overLimit && \"smwb-composer__counter_error\")}\n data-testid=\"composer-counter\"\n >\n {maxLength !== undefined ? `${text.length} / ${maxLength}` : text.length}\n </span>\n ) : null}\n <button\n type=\"button\"\n className={cn(\"smwb-composer__icon-button\", \"smwb-composer__action\", busy && \"smwb-composer__action_stop\")}\n aria-label={busy ? stopLabel : sendLabel}\n aria-disabled={!busy && !canSend ? true : undefined}\n disabled={disabled}\n data-action={busy ? \"stop\" : \"send\"}\n onMouseDown={stopMouseDown}\n onClick={handleActionClick}\n data-testid=\"composer-action\"\n >\n <Icon name={busy ? \"stop\" : \"send\"} size={20} />\n </button>\n {showCounter ? (\n <span className=\"smwb-composer__status\" role=\"status\" data-testid=\"composer-status\">\n {status}\n </span>\n ) : null}\n {attachable ? (\n <input\n {...inputProps}\n onChange={(event) => {\n inputProps.onChange(event);\n // Lets the same file be picked again.\n event.currentTarget.value = \"\";\n }}\n data-testid=\"composer-file-input\"\n />\n ) : null}\n </div>\n );\n});\n\nexport default Composer;\n"],"names":["defaultCounterAnnouncement","remaining","stopMouseDown","event","isDrawn","node","React","Composer","props","ref","value","defaultValue","onValueChange","onSend","sendKey","clearOnSend","busy","onStop","placeholder","maxLength","counter","counterAnnouncement","minRows","maxRows","layout","toolbar","attachments","onAttach","accept","multiple","maxFiles","dropTarget","disabled","readOnly","autoFocus","name","id","ariaLabel","ariaLabelledBy","ariaDescribedBy","onKeyDown","onFocus","onBlur","inputRef","sendLabel","stopLabel","attachLabel","className","testId","onDragOver","onDragLeave","onDrop","rest","text","setText","useControllableState","focused","setFocused","useState","textareaId","useId","counterId","dropzone","useDropzone","files","attached","filterAttachedFiles","dropHandlers","inputProps","attachable","dropping","showCounter","overLimit","canSend","status","send","handleKeyDown","resolveComposerKeyAction","handleActionClick","dragHandlers","isFileDrag","dragActive","fieldStyle","describedBy","jsxs","cn","jsx","Icon"],"mappings":";;;;;;;;;AAuJA,MAAMA,KAA6B,CAACC,MAClCA,KAAa,IAAI,GAAGA,CAAS,qBAAqB,GAAG,CAACA,CAAS;AAEjE,SAASC,GAAcC,GAA4C;AAEjE,EAAAA,EAAM,eAAA;AACR;AAGA,SAASC,EAAQC,GAAgC;AAC/C,SAAI,MAAM,QAAQA,CAAI,IAAUA,EAAK,KAAKD,CAAO,IAC7CE,EAAM,eAA+CD,CAAI,KAAKA,EAAK,SAASC,EAAM,WAC7EF,EAAQC,EAAK,MAAM,QAAQ,IAE7BA,KAAQ,QAAQ,OAAOA,KAAS,aAAaA,MAAS;AAC/D;AAWO,MAAME,KAAWD,EAAM,WAA0C,SAAkBE,GAAOC,GAAK;AACpG,QAAM;AAAA,IACJ,OAAAC;AAAA,IACA,cAAAC;AAAA,IACA,eAAAC;AAAA,IACA,QAAAC;AAAA,IACA,SAAAC,IAAU;AAAA,IACV,aAAAC,IAAc;AAAA,IACd,MAAAC,IAAO;AAAA,IACP,QAAAC;AAAA,IACA,aAAAC;AAAA,IACA,WAAAC;AAAA,IACA,SAAAC;AAAA,IACA,qBAAAC,IAAsBrB;AAAA,IACtB,SAAAsB,IAAU;AAAA,IACV,SAAAC,IAAU;AAAA,IACV,QAAAC,KAAS;AAAA,IACT,SAAAC;AAAA,IACA,aAAAC;AAAA,IACA,UAAAC;AAAA,IACA,QAAAC;AAAA,IACA,UAAAC,IAAW;AAAA,IACX,UAAAC;AAAA,IACA,YAAAC,KAAa;AAAA,IACb,UAAAC,IAAW;AAAA,IACX,UAAAC,IAAW;AAAA,IACX,WAAAC;AAAA,IACA,MAAAC;AAAA,IACA,IAAAC;AAAA,IACA,cAAcC;AAAA,IACd,mBAAmBC;AAAA,IACnB,oBAAoBC;AAAA,IACpB,WAAAC;AAAA,IACA,SAAAC;AAAA,IACA,QAAAC;AAAA,IACA,UAAAC;AAAA,IACA,WAAAC,KAAY;AAAA,IACZ,WAAAC,KAAY;AAAA,IACZ,aAAAC,KAAc;AAAA,IACd,WAAAC;AAAA,IACA,eAAeC;AAAA,IACf,YAAAC;AAAA,IACA,aAAAC;AAAA,IACA,QAAAC;AAAA,IACA,GAAGC;AAAA,EAAA,IACD5C,GAEE,CAAC6C,GAAMC,CAAO,IAAIC,GAA6B;AAAA,IACnD,OAAA7C;AAAA,IACA,cAAcC,KAAA,OAAAA,IAAgB;AAAA,IAC9B,UAAUC;AAAA,EAAA,CACX,GACK,CAAC4C,IAASC,CAAU,IAAIC,GAAS,EAAK,GACtCC,IAAaC,GAAMxB,IAAI,eAAe,GACtCyB,IAAY,GAAGF,CAAU,YAEzBG,IAAWC,GAAY;AAAA,IAC3B,QAAAnC;AAAA,IACA,UAAAC;AAAA,IACA,UAAAG;AAAA;AAAA,IAEA,QAAQ,CAACgC,MAAU;AACjB,YAAMC,IAAWC,GAAoBF,GAAO,EAAE,QAAApC,GAAQ,UAAAC,GAAU,UAAAC,IAAU;AAC1E,MAAImC,EAAS,SAAS,MAAGtC,KAAA,QAAAA,EAAWsC;AAAA,IACtC;AAAA,EAAA,CACD,GACKE,IAAeL,EAAS,aAAA,GACxBM,IAAaN,EAAS,cAAA,GAEtBO,IAAa1C,MAAa,QAE1B2C,IAAWD,KAActC,IAEzBwC,IAAcnD,KAAA,OAAAA,IAAWD,MAAc,QACvCqD,IAAYrD,MAAc,UAAakC,EAAK,SAASlC,GACrDsD,IAAU,CAAC,CAAC5D,KAAUwC,EAAK,KAAA,MAAW,MAAM,CAACrB,KAAY,CAACC,KAAY,CAACjB,KAAQ,CAACwD;AAEtF,MAAIE,IAAS;AACb,MAAIH,KAAepD,MAAc,QAAW;AAC1C,UAAMlB,IAAYkB,IAAYkC,EAAK;AACnC,IAAIpD,KAAa,KAAK,IAAI,IAAI,KAAK,KAAKkB,IAAY,GAAG,CAAC,MAAGuD,IAASrD,EAAoBpB,GAAWkB,CAAS;AAAA,EAC9G;AAEA,QAAMwD,IAAO,MAAM;AACjB,IAAI,CAACF,KAAW,CAAC5D,MACjBA,EAAOwC,EAAK,MAAM,GACdtC,OAAqB,EAAE;AAAA,EAC7B,GAEM6D,KAAgB,CAACzE,MAAoD;AAgBzE,IAfAqC,KAAA,QAAAA,EAAYrC,IACR,EAAAA,EAAM,oBAEK0E;AAAA,MACb;AAAA,QACE,KAAK1E,EAAM;AAAA,QACX,UAAUA,EAAM;AAAA,QAChB,SAASA,EAAM;AAAA,QACf,SAASA,EAAM;AAAA,QACf,QAAQA,EAAM;AAAA,QACd,aAAaA,EAAM,YAAY;AAAA,QAC/B,SAASA,EAAM;AAAA,MAAA;AAAA,MAEjBW;AAAA,IAAA,MAEa,cAEfX,EAAM,eAAA,GACNwE,EAAA;AAAA,EACF,GAEMG,KAAoB,CAAC3E,MAA+C;AAGxE,QAAI,EAAAA,EAAM,SAAS,IACnB;AAAA,UAAIa,GAAM;AACR,QAAKgB,KAAUf,KAAA,QAAAA;AACf;AAAA,MACF;AACA,MAAA0D,EAAA;AAAA;AAAA,EACF,GAiBMI,KAAeT,IACjB,EAAE,YAhBe,CAACnE,MAA2C;AAC/D,IAAA8C,KAAA,QAAAA,EAAa9C,IAET6E,EAAW7E,EAAM,YAAY,KAAGgE,EAAa,WAAWhE,CAAK;AAAA,EACnE,GAYgC,aAXV,CAACA,MAA2C;AAGhE,IAFA+C,KAAA,QAAAA,EAAc/C,IAEV,EAAAA,EAAM,yBAAyB,QAAQA,EAAM,cAAc,SAASA,EAAM,aAAa,MAC3FgE,EAAa,YAAA;AAAA,EACf,GAM4D,QAL3C,CAAChE,MAA2C;AAC3D,IAAAgD,KAAA,QAAAA,EAAShD,IACL6E,EAAW7E,EAAM,YAAY,KAAGgE,EAAa,OAAOhE,CAAK;AAAA,EAC/D,EAEoE,IAChE,EAAE,YAAA8C,GAAY,aAAAC,GAAa,QAAAC,EAAA,GAEzB8B,KAAaX,KAAYR,EAAS,cAClCoB,KAAa;AAAA,IACjB,4BAA4B5D;AAAA,IAC5B,4BAA4B,KAAK,IAAIC,GAASD,CAAO;AAAA,EAAA,GAEjD6D,KAAc,CAAC5C,IAAiBgC,IAAcV,IAAY,MAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,KAAK;AAExG,SACE,gBAAAuB;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAGhC;AAAA,MACH,GAAG2B;AAAA,MACJ,KAAAtE;AAAA,MACA,WAAW4E;AAAA,QACT;AAAA,QACA,iBAAiB7D,EAAM;AAAA,QACvBgC,MAAW;AAAA,QACXxC,KAAQ;AAAA,QACRgB,KAAY;AAAA,QACZiD,MAAc;AAAA,QACdT,KAAa;AAAA,QACbzB;AAAA,MAAA;AAAA,MAEF,eAAaC,KAAA,OAAAA,IAAU;AAAA,MAEtB,UAAA;AAAA,QAAA5C,EAAQsB,CAAW,IAClB,gBAAA4D,EAAC,OAAA,EAAI,WAAU,8BAA6B,eAAY,wBACrD,UAAA5D,EAAA,CACH,IACE;AAAA,0BACH,OAAA,EAAI,WAAU,wBAAuB,cAAY2B,GAAM,OAAO6B,IAC7D,UAAA,gBAAAI;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,KAAK3C;AAAA,YACL,WAAU;AAAA,YACV,IAAIgB;AAAA,YACJ,MAAAxB;AAAA,YACA,MAAMb;AAAA,YACN,aAAAJ;AAAA,YACA,WAAAC;AAAA,YACA,UAAAa;AAAA,YACA,UAAAC;AAAA,YACA,WAAAC;AAAA,YACA,cAAYG;AAAA,YACZ,mBAAiBC;AAAA,YACjB,oBAAkB6C;AAAA,YAClB,gBAAcX,KAAa;AAAA,YAC3B,OAAOnB;AAAA,YACP,UAAU,CAAClD,MAAUmD,EAAQnD,EAAM,OAAO,KAAK;AAAA,YAC/C,WAAWyE;AAAA,YACX,SAAS,CAACzE,MAAU;AAClB,cAAAsC,KAAA,QAAAA,EAAUtC,IACVsD,EAAW,EAAI;AAAA,YACjB;AAAA,YACA,QAAQ,CAACtD,MAAU;AACjB,cAAAuC,KAAA,QAAAA,EAASvC,IACTsD,EAAW,EAAK;AAAA,YAClB;AAAA,YACA,eAAY;AAAA,UAAA;AAAA,QAAA,GAEhB;AAAA,QACCY,IACC,gBAAAiB;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAU;AAAA,YACV,cAAYxC;AAAA,YACZ,UAAAd;AAAA,YACA,SAAS8B,EAAS;AAAA,YAClB,eAAY;AAAA,YAEZ,UAAA,gBAAAwB,EAACC,GAAA,EAAK,MAAK,eAAc,MAAM,GAAA,CAAI;AAAA,UAAA;AAAA,QAAA,IAEnC;AAAA,QACHnF,EAAQqB,CAAO,IACd,gBAAA6D,EAAC,OAAA,EAAI,WAAU,0BAAyB,eAAY,oBACjD,UAAA7D,EAAA,CACH,IACE;AAAA,QACH8C,IACC,gBAAAe;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,IAAIzB;AAAA,YACJ,WAAWwB,EAAG,0BAA0Bb,KAAa,8BAA8B;AAAA,YACnF,eAAY;AAAA,YAEX,UAAArD,MAAc,SAAY,GAAGkC,EAAK,MAAM,MAAMlC,CAAS,KAAKkC,EAAK;AAAA,UAAA;AAAA,QAAA,IAElE;AAAA,QACJ,gBAAAiC;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,WAAWD,EAAG,8BAA8B,yBAAyBrE,KAAQ,4BAA4B;AAAA,YACzG,cAAYA,IAAO6B,KAAYD;AAAA,YAC/B,iBAAe,CAAC5B,KAAQ,CAACyD,IAAU,KAAO;AAAA,YAC1C,UAAAzC;AAAA,YACA,eAAahB,IAAO,SAAS;AAAA,YAC7B,aAAad;AAAA,YACb,SAAS4E;AAAA,YACT,eAAY;AAAA,YAEZ,4BAACS,GAAA,EAAK,MAAMvE,IAAO,SAAS,QAAQ,MAAM,GAAA,CAAI;AAAA,UAAA;AAAA,QAAA;AAAA,QAE/CuD,IACC,gBAAAe,EAAC,QAAA,EAAK,WAAU,yBAAwB,MAAK,UAAS,eAAY,mBAC/D,UAAAZ,EAAA,CACH,IACE;AAAA,QACHL,IACC,gBAAAiB;AAAA,UAAC;AAAA,UAAA;AAAA,YACE,GAAGlB;AAAA,YACJ,UAAU,CAACjE,MAAU;AACnB,cAAAiE,EAAW,SAASjE,CAAK,GAEzBA,EAAM,cAAc,QAAQ;AAAA,YAC9B;AAAA,YACA,eAAY;AAAA,UAAA;AAAA,QAAA,IAEZ;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV,CAAC;"}
@@ -0,0 +1,19 @@
1
+ function f(t) {
2
+ var e, r, s;
3
+ return t ? Array.from((e = t.types) != null ? e : []).includes("Files") ? !0 : ((s = (r = t.files) == null ? void 0 : r.length) != null ? s : 0) > 0 : !1;
4
+ }
5
+ function u(t) {
6
+ return t ? (typeof t == "string" ? t.split(",") : Object.entries(t).flatMap(([r, s]) => [r, ...s])).map((r) => r.trim().toLowerCase()).filter(Boolean) : [];
7
+ }
8
+ function a(t, e) {
9
+ return e === "*/*" ? !0 : e.startsWith(".") ? t.name.toLowerCase().endsWith(e) : e.endsWith("/*") ? t.type.toLowerCase().startsWith(e.slice(0, -1)) : t.type.toLowerCase() === e;
10
+ }
11
+ function o(t, e) {
12
+ const r = u(e.accept), s = r.length === 0 ? t : t.filter((n) => r.some((l) => a(n, l))), i = e.multiple === !1 ? 1 : e.maxFiles && e.maxFiles > 0 ? e.maxFiles : void 0;
13
+ return i === void 0 ? s : s.slice(0, i);
14
+ }
15
+ export {
16
+ o as filterAttachedFiles,
17
+ f as isFileDrag
18
+ };
19
+ //# sourceMappingURL=composerFiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composerFiles.js","sources":["../../../../../src/components/inputs/composer/composerFiles.ts"],"sourcesContent":["/** Accepted file types as `Composer` takes them: a record of mime type to extensions, or a raw `accept` string. */\nexport type ComposerAccept = Record<string, string[]> | string;\n\n/** The part of a `DataTransfer` the drag guard reads. */\nexport interface ComposerDragData {\n types?: ArrayLike<string> | null | undefined;\n files?: ArrayLike<unknown> | null | undefined;\n}\n\n/** The options that decide which of the picked or dropped files `Composer` passes on. */\nexport interface ComposerFileOptions {\n accept?: ComposerAccept | undefined;\n multiple?: boolean | undefined;\n maxFiles?: number | undefined;\n}\n\n/**\n * Whether a drag carries files. A text or link drag does not and stays with the browser (the textarea inserts it).\n * `dragover` exposes only `types`, and Firefox gives a `DOMStringList` there, hence `Array.from`; a `drop` has the\n * file list as well.\n */\nexport function isFileDrag(data: ComposerDragData | null | undefined): boolean {\n if (!data) return false;\n if (Array.from(data.types ?? []).includes(\"Files\")) return true;\n return (data.files?.length ?? 0) > 0;\n}\n\nfunction acceptTokens(accept: ComposerAccept | undefined): string[] {\n if (!accept) return [];\n const tokens =\n typeof accept === \"string\" ? accept.split(\",\") : Object.entries(accept).flatMap(([mime, exts]) => [mime, ...exts]);\n return tokens.map((token) => token.trim().toLowerCase()).filter(Boolean);\n}\n\n// The same three forms as the `accept` attribute: `.ext`, `type/*` and an exact mime type.\nfunction matchesToken(file: File, token: string): boolean {\n if (token === \"*/*\") return true;\n if (token.startsWith(\".\")) return file.name.toLowerCase().endsWith(token);\n if (token.endsWith(\"/*\")) return file.type.toLowerCase().startsWith(token.slice(0, -1));\n return file.type.toLowerCase() === token;\n}\n\n/**\n * The files of a pick or a drop that `Composer` passes to `onAttach`: those that match `accept` (a drop is not\n * filtered by the browser, and the picker's \"All files\" choice lifts its filter), cut to one file when `multiple` is\n * `false`, then to `maxFiles`. The cut comes last, so the files it drops are the ones past the limit, not the ones\n * `accept` would have refused anyway.\n */\nexport function filterAttachedFiles(files: File[], options: ComposerFileOptions): File[] {\n const tokens = acceptTokens(options.accept);\n const accepted =\n tokens.length === 0 ? files : files.filter((file) => tokens.some((token) => matchesToken(file, token)));\n const limit =\n options.multiple === false ? 1 : options.maxFiles && options.maxFiles > 0 ? options.maxFiles : undefined;\n return limit === undefined ? accepted : accepted.slice(0, limit);\n}\n"],"names":["isFileDrag","data","_a","_b","_c","acceptTokens","accept","mime","exts","token","matchesToken","file","filterAttachedFiles","files","options","tokens","accepted","limit"],"mappings":"AAqBO,SAASA,EAAWC,GAAoD;AAAxE,MAAAC,GAAAC,GAAAC;AACL,SAAKH,IACD,MAAM,MAAKC,IAAAD,EAAK,UAAL,OAAAC,IAAc,CAAA,CAAE,EAAE,SAAS,OAAO,IAAU,OACnDE,KAAAD,IAAAF,EAAK,UAAL,gBAAAE,EAAY,WAAZ,OAAAC,IAAsB,KAAK,IAFjB;AAGpB;AAEA,SAASC,EAAaC,GAA8C;AAClE,SAAKA,KAEH,OAAOA,KAAW,WAAWA,EAAO,MAAM,GAAG,IAAI,OAAO,QAAQA,CAAM,EAAE,QAAQ,CAAC,CAACC,GAAMC,CAAI,MAAM,CAACD,GAAM,GAAGC,CAAI,CAAC,GACrG,IAAI,CAACC,MAAUA,EAAM,KAAA,EAAO,YAAA,CAAa,EAAE,OAAO,OAAO,IAHnD,CAAA;AAItB;AAGA,SAASC,EAAaC,GAAYF,GAAwB;AACxD,SAAIA,MAAU,QAAc,KACxBA,EAAM,WAAW,GAAG,IAAUE,EAAK,KAAK,YAAA,EAAc,SAASF,CAAK,IACpEA,EAAM,SAAS,IAAI,IAAUE,EAAK,KAAK,YAAA,EAAc,WAAWF,EAAM,MAAM,GAAG,EAAE,CAAC,IAC/EE,EAAK,KAAK,YAAA,MAAkBF;AACrC;AAQO,SAASG,EAAoBC,GAAeC,GAAsC;AACvF,QAAMC,IAASV,EAAaS,EAAQ,MAAM,GACpCE,IACJD,EAAO,WAAW,IAAIF,IAAQA,EAAM,OAAO,CAACF,MAASI,EAAO,KAAK,CAACN,MAAUC,EAAaC,GAAMF,CAAK,CAAC,CAAC,GAClGQ,IACJH,EAAQ,aAAa,KAAQ,IAAIA,EAAQ,YAAYA,EAAQ,WAAW,IAAIA,EAAQ,WAAW;AACjG,SAAOG,MAAU,SAAYD,IAAWA,EAAS,MAAM,GAAGC,CAAK;AACjE;"}
@@ -0,0 +1,7 @@
1
+ function i(r, e) {
2
+ return r.isComposing || r.keyCode === 229 || r.key !== "Enter" || r.altKey || r.shiftKey ? "native" : r.ctrlKey || r.metaKey || e === "enter" ? "send" : "native";
3
+ }
4
+ export {
5
+ i as resolveComposerKeyAction
6
+ };
7
+ //# sourceMappingURL=composerKeys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composerKeys.js","sources":["../../../../../src/components/inputs/composer/composerKeys.ts"],"sourcesContent":["/** Which Enter sends in a `Composer`: `\"modEnter\"` is Ctrl/⌘+Enter, `\"enter\"` is a plain Enter. */\nexport type ComposerSendKey = \"modEnter\" | \"enter\";\n\n/**\n * What the composer does with a key press in its textarea:\n * - `\"send\"`: prevent the default and send, if sending is allowed;\n * - `\"native\"`: leave the key to the browser (a newline, IME commit, …).\n */\nexport type ComposerKeyAction = \"send\" | \"native\";\n\n/** The part of a keyboard event the key map reads. */\nexport interface ComposerKeyEvent {\n key: string;\n shiftKey: boolean;\n ctrlKey: boolean;\n metaKey: boolean;\n altKey: boolean;\n /** Set by Chromium and Firefox while an IME composition is open. */\n isComposing?: boolean | undefined;\n /** Safari reports the commit Enter of a composition as keyCode 229 with `isComposing` false. */\n keyCode?: number | undefined;\n}\n\n/**\n * The composer's keyboard map (Escape and every other key stay native).\n *\n * - IME composition: always native, so an Enter that commits a CJK candidate is not a send.\n * - Ctrl/⌘+Enter (no Shift, no Alt): send in both modes.\n * - Enter alone: send with `sendKey=\"enter\"`, a native newline with `\"modEnter\"`.\n * - Shift+Enter and every other combination: native.\n */\nexport function resolveComposerKeyAction(event: ComposerKeyEvent, sendKey: ComposerSendKey): ComposerKeyAction {\n if (event.isComposing || event.keyCode === 229) return \"native\";\n if (event.key !== \"Enter\") return \"native\";\n if (event.altKey || event.shiftKey) return \"native\";\n\n if (event.ctrlKey || event.metaKey) return \"send\";\n return sendKey === \"enter\" ? \"send\" : \"native\";\n}\n"],"names":["resolveComposerKeyAction","event","sendKey"],"mappings":"AA+BO,SAASA,EAAyBC,GAAyBC,GAA6C;AAG7G,SAFID,EAAM,eAAeA,EAAM,YAAY,OACvCA,EAAM,QAAQ,WACdA,EAAM,UAAUA,EAAM,WAAiB,WAEvCA,EAAM,WAAWA,EAAM,WACpBC,MAAY,UADwB,SACL;AACxC;"}