@teamofsilicons/silicon-ui 0.0.0-stage → 0.2.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 (354) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +81 -2
  3. package/check.mjs +236 -0
  4. package/components/accordion/accordion.d.ts +13 -0
  5. package/components/accordion/accordion.js +35 -0
  6. package/components/accordion/accordion.module.css +15 -0
  7. package/components/action-button/action-button.d.ts +11 -0
  8. package/components/action-button/action-button.js +57 -0
  9. package/components/action-button/action-button.module.css +15 -0
  10. package/components/activity-heatmap/activity-heatmap.d.ts +37 -0
  11. package/components/activity-heatmap/activity-heatmap.js +303 -0
  12. package/components/activity-heatmap/activity-heatmap.module.css +83 -0
  13. package/components/alert/alert.d.ts +13 -0
  14. package/components/alert/alert.js +79 -0
  15. package/components/alert/alert.module.css +15 -0
  16. package/components/animated-counter/animated-counter.d.ts +13 -0
  17. package/components/animated-counter/animated-counter.js +73 -0
  18. package/components/animated-counter/animated-counter.module.css +12 -0
  19. package/components/announcement-bar/announcement-bar.d.ts +53 -0
  20. package/components/announcement-bar/announcement-bar.js +187 -0
  21. package/components/announcement-bar/announcement-bar.module.css +60 -0
  22. package/components/avatar/avatar.d.ts +8 -0
  23. package/components/avatar/avatar.js +18 -0
  24. package/components/avatar/avatar.module.css +60 -0
  25. package/components/avatar-group/avatar-group.d.ts +13 -0
  26. package/components/avatar-group/avatar-group.js +24 -0
  27. package/components/avatar-group/avatar-group.module.css +27 -0
  28. package/components/badge/badge.d.ts +10 -0
  29. package/components/badge/badge.js +66 -0
  30. package/components/badge/badge.module.css +52 -0
  31. package/components/bar-chart/bar-chart.d.ts +32 -0
  32. package/components/bar-chart/bar-chart.js +327 -0
  33. package/components/bar-chart/bar-chart.module.css +49 -0
  34. package/components/billing-toggle/billing-toggle.d.ts +35 -0
  35. package/components/billing-toggle/billing-toggle.js +83 -0
  36. package/components/billing-toggle/billing-toggle.module.css +139 -0
  37. package/components/bottom-sheet/bottom-sheet.d.ts +27 -0
  38. package/components/bottom-sheet/bottom-sheet.js +386 -0
  39. package/components/bottom-sheet/bottom-sheet.module.css +69 -0
  40. package/components/breadcrumb/breadcrumb.d.ts +13 -0
  41. package/components/breadcrumb/breadcrumb.js +19 -0
  42. package/components/breadcrumb/breadcrumb.module.css +12 -0
  43. package/components/brush-chart/brush-chart.d.ts +45 -0
  44. package/components/brush-chart/brush-chart.js +426 -0
  45. package/components/brush-chart/brush-chart.module.css +69 -0
  46. package/components/button/button.d.ts +10 -0
  47. package/components/button/button.js +97 -0
  48. package/components/button/button.module.css +39 -0
  49. package/components/button-group/button-group.d.ts +59 -0
  50. package/components/button-group/button-group.js +280 -0
  51. package/components/button-group/button-group.module.css +87 -0
  52. package/components/button-link/button-link.d.ts +24 -0
  53. package/components/button-link/button-link.js +11 -0
  54. package/components/button-link/button-link.module.css +7 -0
  55. package/components/calendar/calendar.d.ts +22 -0
  56. package/components/calendar/calendar.js +253 -0
  57. package/components/calendar/calendar.module.css +51 -0
  58. package/components/card/card.d.ts +19 -0
  59. package/components/card/card.js +108 -0
  60. package/components/card/card.module.css +51 -0
  61. package/components/card-stack/card-stack.d.ts +34 -0
  62. package/components/card-stack/card-stack.js +291 -0
  63. package/components/card-stack/card-stack.module.css +63 -0
  64. package/components/carousel/carousel.d.ts +28 -0
  65. package/components/carousel/carousel.js +332 -0
  66. package/components/carousel/carousel.module.css +42 -0
  67. package/components/chat-thread/chat-thread.d.ts +135 -0
  68. package/components/chat-thread/chat-thread.js +406 -0
  69. package/components/chat-thread/chat-thread.module.css +242 -0
  70. package/components/checkbox/checkbox.d.ts +7 -0
  71. package/components/checkbox/checkbox.js +23 -0
  72. package/components/checkbox/checkbox.module.css +15 -0
  73. package/components/chip-group/chip-group.d.ts +24 -0
  74. package/components/chip-group/chip-group.js +196 -0
  75. package/components/chip-group/chip-group.module.css +38 -0
  76. package/components/code-block/code-block.d.ts +11 -0
  77. package/components/code-block/code-block.js +133 -0
  78. package/components/code-block/code-block.module.css +43 -0
  79. package/components/color-picker/color-picker.d.ts +40 -0
  80. package/components/color-picker/color-picker.js +449 -0
  81. package/components/color-picker/color-picker.module.css +111 -0
  82. package/components/combobox/combobox.d.ts +19 -0
  83. package/components/combobox/combobox.js +167 -0
  84. package/components/combobox/combobox.module.css +28 -0
  85. package/components/command-palette/command-palette.d.ts +20 -0
  86. package/components/command-palette/command-palette.js +151 -0
  87. package/components/command-palette/command-palette.module.css +94 -0
  88. package/components/comment-thread/comment-thread.d.ts +120 -0
  89. package/components/comment-thread/comment-thread.js +343 -0
  90. package/components/comment-thread/comment-thread.module.css +195 -0
  91. package/components/confirm-morph/confirm-morph.d.ts +65 -0
  92. package/components/confirm-morph/confirm-morph.js +355 -0
  93. package/components/confirm-morph/confirm-morph.module.css +146 -0
  94. package/components/context-menu/context-menu.d.ts +18 -0
  95. package/components/context-menu/context-menu.js +148 -0
  96. package/components/context-menu/context-menu.module.css +17 -0
  97. package/components/copy-button/copy-button.d.ts +10 -0
  98. package/components/copy-button/copy-button.js +69 -0
  99. package/components/copy-button/copy-button.module.css +21 -0
  100. package/components/countdown/countdown.d.ts +31 -0
  101. package/components/countdown/countdown.js +177 -0
  102. package/components/countdown/countdown.module.css +49 -0
  103. package/components/date-picker/date-picker.d.ts +17 -0
  104. package/components/date-picker/date-picker.js +100 -0
  105. package/components/date-picker/date-picker.module.css +34 -0
  106. package/components/date-range-picker/date-range-picker.d.ts +44 -0
  107. package/components/date-range-picker/date-range-picker.js +534 -0
  108. package/components/date-range-picker/date-range-picker.module.css +214 -0
  109. package/components/dialog/dialog.d.ts +11 -0
  110. package/components/dialog/dialog.js +52 -0
  111. package/components/dialog/dialog.module.css +36 -0
  112. package/components/donut-chart/donut-chart.d.ts +46 -0
  113. package/components/donut-chart/donut-chart.js +382 -0
  114. package/components/donut-chart/donut-chart.module.css +48 -0
  115. package/components/drawer/drawer.d.ts +20 -0
  116. package/components/drawer/drawer.js +111 -0
  117. package/components/drawer/drawer.module.css +97 -0
  118. package/components/dropdown-menu/dropdown-menu.d.ts +16 -0
  119. package/components/dropdown-menu/dropdown-menu.js +39 -0
  120. package/components/dropdown-menu/dropdown-menu.module.css +38 -0
  121. package/components/elastic-slider/elastic-slider.d.ts +39 -0
  122. package/components/elastic-slider/elastic-slider.js +261 -0
  123. package/components/elastic-slider/elastic-slider.module.css +40 -0
  124. package/components/empty-state/empty-state.d.ts +12 -0
  125. package/components/empty-state/empty-state.js +69 -0
  126. package/components/empty-state/empty-state.module.css +13 -0
  127. package/components/expandable-card/expandable-card.d.ts +13 -0
  128. package/components/expandable-card/expandable-card.js +89 -0
  129. package/components/expandable-card/expandable-card.module.css +22 -0
  130. package/components/expanding-button-group/expanding-button-group.d.ts +41 -0
  131. package/components/expanding-button-group/expanding-button-group.js +258 -0
  132. package/components/expanding-button-group/expanding-button-group.module.css +44 -0
  133. package/components/expanding-search/expanding-search.d.ts +38 -0
  134. package/components/expanding-search/expanding-search.js +242 -0
  135. package/components/expanding-search/expanding-search.module.css +52 -0
  136. package/components/file-dropzone/file-dropzone.d.ts +44 -0
  137. package/components/file-dropzone/file-dropzone.js +379 -0
  138. package/components/file-dropzone/file-dropzone.module.css +115 -0
  139. package/components/file-upload/file-upload.d.ts +22 -0
  140. package/components/file-upload/file-upload.js +192 -0
  141. package/components/file-upload/file-upload.module.css +49 -0
  142. package/components/filter-toolbar/filter-toolbar.d.ts +48 -0
  143. package/components/filter-toolbar/filter-toolbar.js +446 -0
  144. package/components/filter-toolbar/filter-toolbar.module.css +70 -0
  145. package/components/floating-button-group/floating-button-group.d.ts +51 -0
  146. package/components/floating-button-group/floating-button-group.js +215 -0
  147. package/components/floating-button-group/floating-button-group.module.css +74 -0
  148. package/components/gauge/gauge.d.ts +18 -0
  149. package/components/gauge/gauge.js +101 -0
  150. package/components/gauge/gauge.module.css +22 -0
  151. package/components/hold-to-confirm/hold-to-confirm.d.ts +25 -0
  152. package/components/hold-to-confirm/hold-to-confirm.js +165 -0
  153. package/components/hold-to-confirm/hold-to-confirm.module.css +20 -0
  154. package/components/hover-card/hover-card.d.ts +38 -0
  155. package/components/hover-card/hover-card.js +145 -0
  156. package/components/hover-card/hover-card.module.css +20 -0
  157. package/components/image-compare/image-compare.d.ts +27 -0
  158. package/components/image-compare/image-compare.js +267 -0
  159. package/components/image-compare/image-compare.module.css +25 -0
  160. package/components/in-view-title/in-view-title.d.ts +17 -0
  161. package/components/in-view-title/in-view-title.js +70 -0
  162. package/components/in-view-title/in-view-title.module.css +13 -0
  163. package/components/inline-edit/inline-edit.d.ts +27 -0
  164. package/components/inline-edit/inline-edit.js +315 -0
  165. package/components/inline-edit/inline-edit.module.css +73 -0
  166. package/components/input/input.d.ts +7 -0
  167. package/components/input/input.js +60 -0
  168. package/components/input/input.module.css +22 -0
  169. package/components/json-viewer/json-viewer.d.ts +48 -0
  170. package/components/json-viewer/json-viewer.js +463 -0
  171. package/components/json-viewer/json-viewer.module.css +92 -0
  172. package/components/line-chart/line-chart.d.ts +58 -0
  173. package/components/line-chart/line-chart.js +383 -0
  174. package/components/line-chart/line-chart.module.css +60 -0
  175. package/components/mention-input/mention-input.d.ts +72 -0
  176. package/components/mention-input/mention-input.js +417 -0
  177. package/components/mention-input/mention-input.module.css +134 -0
  178. package/components/metric-card/metric-card.d.ts +8 -0
  179. package/components/metric-card/metric-card.js +44 -0
  180. package/components/metric-card/metric-card.module.css +18 -0
  181. package/components/money-input/money-input.d.ts +48 -0
  182. package/components/money-input/money-input.js +503 -0
  183. package/components/money-input/money-input.module.css +77 -0
  184. package/components/morph-select/morph-select.d.ts +50 -0
  185. package/components/morph-select/morph-select.js +395 -0
  186. package/components/morph-select/morph-select.module.css +88 -0
  187. package/components/multi-select/multi-select.d.ts +18 -0
  188. package/components/multi-select/multi-select.js +105 -0
  189. package/components/multi-select/multi-select.module.css +37 -0
  190. package/components/notification-center/notification-center.d.ts +24 -0
  191. package/components/notification-center/notification-center.js +146 -0
  192. package/components/notification-center/notification-center.module.css +79 -0
  193. package/components/number-field/number-field.d.ts +41 -0
  194. package/components/number-field/number-field.js +455 -0
  195. package/components/number-field/number-field.module.css +71 -0
  196. package/components/otp-input/otp-input.d.ts +13 -0
  197. package/components/otp-input/otp-input.js +129 -0
  198. package/components/otp-input/otp-input.module.css +28 -0
  199. package/components/pagination/pagination.d.ts +7 -0
  200. package/components/pagination/pagination.js +60 -0
  201. package/components/pagination/pagination.module.css +16 -0
  202. package/components/password-field/password-field.d.ts +14 -0
  203. package/components/password-field/password-field.js +51 -0
  204. package/components/password-field/password-field.module.css +27 -0
  205. package/components/password-strength/password-strength.d.ts +107 -0
  206. package/components/password-strength/password-strength.js +161 -0
  207. package/components/password-strength/password-strength.module.css +57 -0
  208. package/components/phone-input/phone-input.d.ts +73 -0
  209. package/components/phone-input/phone-input.js +612 -0
  210. package/components/phone-input/phone-input.module.css +98 -0
  211. package/components/popover/popover.d.ts +6 -0
  212. package/components/popover/popover.js +19 -0
  213. package/components/popover/popover.module.css +32 -0
  214. package/components/progress/progress.d.ts +8 -0
  215. package/components/progress/progress.js +42 -0
  216. package/components/progress/progress.module.css +1 -0
  217. package/components/radio-cards/radio-cards.d.ts +35 -0
  218. package/components/radio-cards/radio-cards.js +110 -0
  219. package/components/radio-cards/radio-cards.module.css +84 -0
  220. package/components/radio-group/radio-group.d.ts +13 -0
  221. package/components/radio-group/radio-group.js +55 -0
  222. package/components/radio-group/radio-group.module.css +30 -0
  223. package/components/resizable-panels/resizable-panels.d.ts +37 -0
  224. package/components/resizable-panels/resizable-panels.js +338 -0
  225. package/components/resizable-panels/resizable-panels.module.css +40 -0
  226. package/components/rich-text-editor/rich-text-editor.d.ts +55 -0
  227. package/components/rich-text-editor/rich-text-editor.js +1733 -0
  228. package/components/rich-text-editor/rich-text-editor.module.css +201 -0
  229. package/components/ridgeline/ridgeline.d.ts +37 -0
  230. package/components/ridgeline/ridgeline.js +346 -0
  231. package/components/ridgeline/ridgeline.module.css +58 -0
  232. package/components/scroll-area/scroll-area.d.ts +40 -0
  233. package/components/scroll-area/scroll-area.js +153 -0
  234. package/components/scroll-area/scroll-area.module.css +79 -0
  235. package/components/search-field/search-field.d.ts +7 -0
  236. package/components/search-field/search-field.js +20 -0
  237. package/components/search-field/search-field.module.css +17 -0
  238. package/components/segmented-control/segmented-control.d.ts +16 -0
  239. package/components/segmented-control/segmented-control.js +56 -0
  240. package/components/segmented-control/segmented-control.module.css +15 -0
  241. package/components/select/select.d.ts +15 -0
  242. package/components/select/select.js +36 -0
  243. package/components/select/select.module.css +35 -0
  244. package/components/shortcut-recorder/shortcut-recorder.d.ts +108 -0
  245. package/components/shortcut-recorder/shortcut-recorder.js +380 -0
  246. package/components/shortcut-recorder/shortcut-recorder.module.css +85 -0
  247. package/components/signature-pad/signature-pad.d.ts +72 -0
  248. package/components/signature-pad/signature-pad.js +450 -0
  249. package/components/signature-pad/signature-pad.module.css +84 -0
  250. package/components/skeleton/skeleton.d.ts +13 -0
  251. package/components/skeleton/skeleton.js +53 -0
  252. package/components/skeleton/skeleton.module.css +11 -0
  253. package/components/slider/slider.d.ts +45 -0
  254. package/components/slider/slider.js +347 -0
  255. package/components/slider/slider.module.css +45 -0
  256. package/components/slope-chart/slope-chart.d.ts +38 -0
  257. package/components/slope-chart/slope-chart.js +183 -0
  258. package/components/slope-chart/slope-chart.module.css +51 -0
  259. package/components/slot-text/slot-text.d.ts +26 -0
  260. package/components/slot-text/slot-text.js +119 -0
  261. package/components/slot-text/slot-text.module.css +19 -0
  262. package/components/sortable-data-table/sortable-data-table.d.ts +38 -0
  263. package/components/sortable-data-table/sortable-data-table.js +240 -0
  264. package/components/sortable-data-table/sortable-data-table.module.css +116 -0
  265. package/components/sparkline/sparkline.d.ts +19 -0
  266. package/components/sparkline/sparkline.js +239 -0
  267. package/components/sparkline/sparkline.module.css +26 -0
  268. package/components/split-button/split-button.d.ts +19 -0
  269. package/components/split-button/split-button.js +33 -0
  270. package/components/split-button/split-button.module.css +51 -0
  271. package/components/stepper/stepper.d.ts +36 -0
  272. package/components/stepper/stepper.js +108 -0
  273. package/components/stepper/stepper.module.css +74 -0
  274. package/components/streamgraph/streamgraph.d.ts +51 -0
  275. package/components/streamgraph/streamgraph.js +376 -0
  276. package/components/streamgraph/streamgraph.module.css +55 -0
  277. package/components/swipe-actions/swipe-actions.d.ts +35 -0
  278. package/components/swipe-actions/swipe-actions.js +330 -0
  279. package/components/swipe-actions/swipe-actions.module.css +64 -0
  280. package/components/switch/switch.d.ts +7 -0
  281. package/components/switch/switch.js +45 -0
  282. package/components/switch/switch.module.css +12 -0
  283. package/components/tabs/tabs.d.ts +8 -0
  284. package/components/tabs/tabs.js +138 -0
  285. package/components/tabs/tabs.module.css +27 -0
  286. package/components/tag-input/tag-input.d.ts +15 -0
  287. package/components/tag-input/tag-input.js +150 -0
  288. package/components/tag-input/tag-input.module.css +34 -0
  289. package/components/text-morph/text-morph.d.ts +13 -0
  290. package/components/text-morph/text-morph.js +69 -0
  291. package/components/text-morph/text-morph.module.css +8 -0
  292. package/components/text-reveal/text-reveal.d.ts +14 -0
  293. package/components/text-reveal/text-reveal.js +20 -0
  294. package/components/text-reveal/text-reveal.module.css +13 -0
  295. package/components/text-shimmer/text-shimmer.d.ts +18 -0
  296. package/components/text-shimmer/text-shimmer.js +90 -0
  297. package/components/text-shimmer/text-shimmer.module.css +9 -0
  298. package/components/textarea/textarea.d.ts +7 -0
  299. package/components/textarea/textarea.js +56 -0
  300. package/components/textarea/textarea.module.css +22 -0
  301. package/components/theme-switch/theme-switch.d.ts +11 -0
  302. package/components/theme-switch/theme-switch.js +37 -0
  303. package/components/theme-switch/theme-switch.module.css +31 -0
  304. package/components/time-picker/time-picker.d.ts +13 -0
  305. package/components/time-picker/time-picker.js +95 -0
  306. package/components/time-picker/time-picker.module.css +23 -0
  307. package/components/timeline/timeline.d.ts +47 -0
  308. package/components/timeline/timeline.js +171 -0
  309. package/components/timeline/timeline.module.css +51 -0
  310. package/components/toast/toast.d.ts +8 -0
  311. package/components/toast/toast.js +118 -0
  312. package/components/toast/toast.module.css +100 -0
  313. package/components/toast-stack/toast-stack.d.ts +57 -0
  314. package/components/toast-stack/toast-stack.js +399 -0
  315. package/components/toast-stack/toast-stack.module.css +61 -0
  316. package/components/tooltip/tooltip.d.ts +8 -0
  317. package/components/tooltip/tooltip.js +62 -0
  318. package/components/tooltip/tooltip.module.css +18 -0
  319. package/components/tree-view/tree-view.d.ts +17 -0
  320. package/components/tree-view/tree-view.js +147 -0
  321. package/components/tree-view/tree-view.module.css +22 -0
  322. package/components/treemap/treemap.d.ts +35 -0
  323. package/components/treemap/treemap.js +375 -0
  324. package/components/treemap/treemap.module.css +59 -0
  325. package/components/usage-meter/usage-meter.d.ts +24 -0
  326. package/components/usage-meter/usage-meter.js +296 -0
  327. package/components/usage-meter/usage-meter.module.css +61 -0
  328. package/components/user-menu/user-menu.d.ts +62 -0
  329. package/components/user-menu/user-menu.js +316 -0
  330. package/components/user-menu/user-menu.module.css +97 -0
  331. package/components/waffle-chart/waffle-chart.d.ts +39 -0
  332. package/components/waffle-chart/waffle-chart.js +244 -0
  333. package/components/waffle-chart/waffle-chart.module.css +52 -0
  334. package/components.json +1330 -0
  335. package/eslint.js +53 -0
  336. package/lib/escape.d.ts +19 -0
  337. package/lib/escape.js +50 -0
  338. package/lib/media.d.ts +353 -0
  339. package/lib/media.js +65 -0
  340. package/lib/menu-highlight.d.ts +28 -0
  341. package/lib/menu-highlight.js +43 -0
  342. package/lib/motion-tokens.d.ts +60 -0
  343. package/lib/motion-tokens.js +25 -0
  344. package/lib/return-focus.d.ts +9 -0
  345. package/lib/return-focus.js +53 -0
  346. package/lib/silicon-provider.d.ts +60 -0
  347. package/lib/silicon-provider.js +47 -0
  348. package/lib/use-copy-feedback.d.ts +8 -0
  349. package/lib/use-copy-feedback.js +36 -0
  350. package/lib/use-today.d.ts +2 -0
  351. package/lib/use-today.js +29 -0
  352. package/package.json +76 -4
  353. package/styles.css +218 -0
  354. package/styles.css.d.ts +1 -0
@@ -0,0 +1,338 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Children, Fragment, isValidElement, useEffect, useRef, useState } from "react";
4
+ import { AnimatePresence, animate, motion, motionValue, useReducedMotion, useTransform } from "motion/react";
5
+ import { ChevronLeft, ChevronRight } from "lucide-react";
6
+ import { motionTokens } from "../../lib/motion-tokens.js";
7
+ import styles from "./resizable-panels.module.css";
8
+ const DEFAULT_MIN = 80;
9
+ /** How far in px a pane can be pulled past a limit before it stops giving. */
10
+ const STRETCH = 44;
11
+ /** Keyboard steps in px; Shift takes the larger one. */
12
+ const STEP = 16, BIG_STEP = 64;
13
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
14
+ /** Past a limit every pixel costs more, like pulling against elastic. */
15
+ const rubber = (overshoot) => overshoot * STRETCH * .55 / (STRETCH + .55 * overshoot);
16
+ const band = (value, lo, hi) => value < lo ? lo - rubber(lo - value) : value > hi ? hi + rubber(value - hi) : value;
17
+ /** A collapsible pane snaps closed once the pointer is this far below its minimum. */
18
+ const collapseAt = (min) => min - Math.max(min * .5, 40);
19
+ /** Short momentum projection, used only to decide whether a flick collapses or restores a pane. */
20
+ const project = (velocity, rate = .99) => velocity / 1000 * rate / (1 - rate);
21
+ const toShares = (values) => { const total = values.reduce((sum, value) => sum + value, 0) || 1; return values.map(value => value / total * 100); };
22
+ const tabIn = { opacity: 0, scale: .6, filter: `blur(${motionTokens.blur.subtle}px)` };
23
+ const tabRest = { opacity: 1, scale: 1, filter: "blur(0px)" };
24
+ const tabOut = { ...tabIn, transition: { duration: motionTokens.duration.fast, ease: [...motionTokens.ease.standard] } };
25
+ const tabEnter = { ...motionTokens.spring.snappy, opacity: { duration: motionTokens.duration.fast, ease: [...motionTokens.ease.enter] }, filter: { duration: motionTokens.duration.fast, ease: [...motionTokens.ease.enter] } };
26
+ function velocityOf(samples, now) {
27
+ const recent = samples.filter(([time]) => now - time <= 90);
28
+ const first = recent[0], last = recent[recent.length - 1];
29
+ if (!first || !last || recent.length < 2 || now - last[0] > 50)
30
+ return 0;
31
+ const [firstTime, firstX] = first, [lastTime, lastX] = last;
32
+ return lastTime > firstTime ? (lastX - firstX) / ((lastTime - firstTime) / 1000) : 0;
33
+ }
34
+ /** Carries a pane's configuration into `ResizablePanels`. Rendered on its own it shows its children unchanged. */
35
+ export function ResizablePanel({ children }) {
36
+ return _jsx(_Fragment, { children: children });
37
+ }
38
+ export function ResizablePanels({ label, children, onLayoutChange, className }) {
39
+ const configs = Children.toArray(children).filter((child) => isValidElement(child)).map(child => child.props);
40
+ const count = configs.length;
41
+ const reduced = useReducedMotion() ?? false;
42
+ const startsCollapsed = (config) => Boolean(config.collapsible && config.defaultCollapsed);
43
+ // Sizes are flex-grow factors: the default shares before the first interaction, then px. Flex keeps them proportional as the group resizes.
44
+ const [sizes] = useState(() => configs.map(config => motionValue(startsCollapsed(config) ? 0 : config.defaultSize)));
45
+ const [fades] = useState(() => configs.map(config => motionValue(startsCollapsed(config) ? 0 : 1)));
46
+ const [collapsed, setCollapsed] = useState(() => configs.map(startsCollapsed));
47
+ const [free, setFree] = useState(() => configs.map(() => false));
48
+ const [resizing, setResizing] = useState(null);
49
+ const [shares, setShares] = useState(() => toShares(configs.map(config => startsCollapsed(config) ? 0 : config.defaultSize)));
50
+ const [available, setAvailable] = useState(0);
51
+ const groupRef = useRef(null);
52
+ const panelRefs = useRef([]);
53
+ const restoreSizes = useRef(configs.map(() => null));
54
+ const running = useRef([]);
55
+ const token = useRef(0);
56
+ const goals = useRef(null);
57
+ const stale = useRef(true);
58
+ const drag = useRef(null);
59
+ // A group narrower than every minimum together scales the minimums down in proportion, the same floor the CSS applies,
60
+ // so the panes fill the group instead of overflowing it and a press never re-lays them out.
61
+ const minTotal = configs.reduce((sum, config) => sum + (config.minSize ?? DEFAULT_MIN), 0);
62
+ const minOf = (index) => { const min = configs[index]?.minSize ?? DEFAULT_MIN; return available > 0 && available < minTotal ? min * available / minTotal : min; };
63
+ const maxOf = (index) => configs[index]?.maxSize ?? Infinity;
64
+ // Content fades as a pane is squeezed below its minimum, so a collapsing pane dissolves rather than crushes.
65
+ const minKey = configs.map((_, index) => minOf(index)).join();
66
+ useEffect(() => {
67
+ const mins = minKey.split(",").map(Number);
68
+ const stops = sizes.map((size, index) => size.on("change", value => fades[index]?.set(clamp(value / Math.max(1, mins[index] ?? DEFAULT_MIN), 0, 1))));
69
+ return () => stops.forEach(stop => stop());
70
+ }, [sizes, fades, minKey]);
71
+ useEffect(() => {
72
+ const group = groupRef.current;
73
+ if (!group || typeof ResizeObserver === "undefined")
74
+ return;
75
+ const observer = new ResizeObserver(() => {
76
+ stale.current = true;
77
+ setAvailable(panelRefs.current.reduce((sum, node) => sum + (node?.getBoundingClientRect().width ?? 0), 0));
78
+ });
79
+ observer.observe(group);
80
+ return () => observer.disconnect();
81
+ }, []);
82
+ /** Starts an interaction: stops anything in flight and makes sure the sizes are the px widths on screen, so nothing moves. */
83
+ function begin(involved) {
84
+ token.current += 1;
85
+ running.current.forEach(controls => controls.stop());
86
+ running.current = [];
87
+ // Only a group resize (or the first interaction) can put the sizes out of step with the screen; otherwise they are the truth,
88
+ // even before a jump has painted.
89
+ if (stale.current) {
90
+ stale.current = false;
91
+ const widths = panelRefs.current.slice(0, count).map(node => node?.getBoundingClientRect().width ?? 0);
92
+ if (widths.some((width, index) => Math.abs(width - sizes[index].get()) > .5))
93
+ widths.forEach((width, index) => sizes[index].jump(width));
94
+ }
95
+ // Freed panes drop their CSS limits while JS owns them, so rubber-banding and collapsing can go past them.
96
+ if (involved.some(index => !free[index]))
97
+ setFree(current => current.map((value, index) => value || involved.includes(index)));
98
+ return sizes.map(size => size.get());
99
+ }
100
+ function commit() {
101
+ const values = sizes.map(size => size.get());
102
+ setFree(configs.map(() => false));
103
+ setShares(toShares(values));
104
+ onLayoutChange?.(toShares(values));
105
+ }
106
+ /** Springs panes to new widths from wherever they are, keeping their velocity, then hands the limits back to CSS. */
107
+ function glide(targets, transition = motionTokens.spring.smooth) {
108
+ const mine = token.current;
109
+ const finals = targets.map((target, index) => target ?? sizes[index].get());
110
+ goals.current = finals;
111
+ // Assistive technology hears the destination right away rather than after the spring's tail settles.
112
+ setShares(toShares(finals));
113
+ const moving = targets.flatMap((target, index) => target === null || Math.abs(target - sizes[index].get()) < .01 ? [] : [[index, target]]);
114
+ let pending = moving.length;
115
+ const done = () => { if (token.current === mine)
116
+ commit(); };
117
+ if (reduced || !pending) {
118
+ moving.forEach(([index, target]) => sizes[index].jump(target));
119
+ done();
120
+ return;
121
+ }
122
+ running.current = moving.map(([index, target]) => animate(sizes[index], target, { ...transition, onComplete: () => { pending -= 1; if (!pending)
123
+ done(); } }));
124
+ }
125
+ function limits(handle, a, b) {
126
+ const pair = a + b;
127
+ let lo = Math.max(minOf(handle), pair - maxOf(handle + 1)), hi = Math.min(maxOf(handle), pair - minOf(handle + 1));
128
+ // A group too narrow for every minimum may already hold a pane below it; never yank it to the limit on grab.
129
+ if (a > 0 && b > 0) {
130
+ lo = Math.min(lo, a);
131
+ hi = Math.max(hi, a);
132
+ }
133
+ if (lo > hi)
134
+ lo = hi = clamp((lo + hi) / 2, 0, pair);
135
+ return { pair, lo: clamp(lo, 0, pair), hi: clamp(hi, 0, pair) };
136
+ }
137
+ function resolve(handle, raw, pair, lo, hi) {
138
+ if (configs[handle].collapsible && raw < collapseAt(minOf(handle)))
139
+ return { mode: "before", size: 0 };
140
+ if (configs[handle + 1].collapsible && pair - raw < collapseAt(minOf(handle + 1)))
141
+ return { mode: "after", size: pair };
142
+ return { mode: "open", size: band(raw, lo, hi) };
143
+ }
144
+ function setCollapsedPair(handle, mode) {
145
+ setCollapsed(current => current.map((value, index) => index === handle ? mode === "before" : index === handle + 1 ? mode === "after" : value));
146
+ }
147
+ function remember(handle, a, b, mode) {
148
+ if (mode === "before" && a > 0)
149
+ restoreSizes.current[handle] = a;
150
+ if (mode === "after" && b > 0)
151
+ restoreSizes.current[handle + 1] = b;
152
+ }
153
+ function modeOf(handle) {
154
+ return collapsed[handle] ? "before" : collapsed[handle + 1] ? "after" : "open";
155
+ }
156
+ /** Sets a pane pair to a new boundary. Any change of collapse state springs; everything else moves with the pointer. */
157
+ function moveBoundary(current, size) {
158
+ const [a, b] = [sizes[current.handle], sizes[current.handle + 1]];
159
+ if (current.catching && !reduced) {
160
+ if (Math.abs(a.get() - size) < .75) {
161
+ current.catching = false;
162
+ running.current.forEach(controls => controls.stop());
163
+ running.current = [];
164
+ }
165
+ else {
166
+ running.current = [animate(a, size, motionTokens.spring.smooth), animate(b, current.pair - size, motionTokens.spring.smooth)];
167
+ return;
168
+ }
169
+ }
170
+ a.set(size);
171
+ b.set(current.pair - size);
172
+ }
173
+ function onPointerDown(handle, event) {
174
+ if (drag.current || (event.pointerType === "mouse" && event.button !== 0))
175
+ return;
176
+ const values = begin([handle, handle + 1]);
177
+ const { pair, lo, hi } = limits(handle, values[handle], values[handle + 1]);
178
+ event.currentTarget.setPointerCapture(event.pointerId);
179
+ const mode = modeOf(handle);
180
+ drag.current = { handle, pointer: event.pointerId, startX: event.clientX, a0: values[handle], b0: values[handle + 1], pair, lo, hi, mode, startMode: mode, moved: false, catching: false, samples: [[event.timeStamp, event.clientX]] };
181
+ }
182
+ function onPointerMove(event) {
183
+ const current = drag.current;
184
+ if (!current || current.pointer !== event.pointerId)
185
+ return;
186
+ const dx = event.clientX - current.startX;
187
+ if (!current.moved) {
188
+ if (Math.abs(dx) < 2)
189
+ return;
190
+ current.moved = true;
191
+ setResizing(current.handle);
192
+ }
193
+ const next = resolve(current.handle, current.a0 + dx, current.pair, current.lo, current.hi);
194
+ if (next.mode !== current.mode) {
195
+ current.mode = next.mode;
196
+ current.catching = true;
197
+ }
198
+ moveBoundary(current, next.size);
199
+ current.samples.push([event.timeStamp, event.clientX]);
200
+ if (current.samples.length > 16)
201
+ current.samples.shift();
202
+ }
203
+ function finish(event, cancelled) {
204
+ const current = drag.current;
205
+ if (!current || current.pointer !== event.pointerId)
206
+ return;
207
+ drag.current = null;
208
+ setResizing(null);
209
+ const { handle, pair, lo, hi } = current;
210
+ if (!current.moved) {
211
+ // A press on a divider that hides a pane brings it back.
212
+ if (current.startMode !== "open" && !cancelled)
213
+ restore(handle, current.startMode);
214
+ else
215
+ commit();
216
+ return;
217
+ }
218
+ const raw = current.a0 + event.clientX - current.startX;
219
+ const velocity = cancelled ? 0 : velocityOf(current.samples, event.timeStamp);
220
+ const flung = resolve(handle, raw + project(velocity), pair, lo, hi);
221
+ // A flick toward an edge collapses; a flick back out restores. Otherwise the divider stays where it was let go, inside its limits.
222
+ const mode = cancelled ? current.startMode : flung.mode !== "open" ? flung.mode : "open";
223
+ const size = mode === "before" ? 0 : mode === "after" ? pair : cancelled ? current.a0 : clamp(raw, lo, hi);
224
+ remember(handle, current.a0, current.b0, mode);
225
+ setCollapsedPair(handle, mode);
226
+ glide(sizes.map((_, index) => index === handle ? size : index === handle + 1 ? pair - size : null));
227
+ }
228
+ function restore(handle, side) {
229
+ const values = begin([handle, handle + 1]);
230
+ const { pair, lo, hi } = limits(handle, values[handle], values[handle + 1]);
231
+ const size = side === "before" ? clamp(restoreSizes.current[handle] ?? minOf(handle), lo, hi) : clamp(pair - (restoreSizes.current[handle + 1] ?? minOf(handle + 1)), lo, hi);
232
+ setCollapsedPair(handle, "open");
233
+ glide(sizes.map((_, index) => index === handle ? size : index === handle + 1 ? pair - size : null));
234
+ }
235
+ function collapse(handle, side) {
236
+ const values = begin([handle, handle + 1]);
237
+ const pair = values[handle] + values[handle + 1];
238
+ remember(handle, values[handle], values[handle + 1], side);
239
+ setCollapsedPair(handle, side);
240
+ glide(sizes.map((_, index) => index === handle ? (side === "before" ? 0 : pair) : index === handle + 1 ? (side === "before" ? pair : 0) : null));
241
+ }
242
+ /** Resets to the default shares, fitted to the current width so every pane respects its limits. */
243
+ function reset() {
244
+ const values = begin(configs.map((_, index) => index));
245
+ const total = values.reduce((sum, value) => sum + value, 0);
246
+ const wanted = configs.map(config => startsCollapsed(config) ? 0 : config.defaultSize);
247
+ const targets = [...wanted];
248
+ const frozen = wanted.map(value => value === 0);
249
+ for (let pass = 0; pass < count; pass++) {
250
+ const fixed = targets.reduce((sum, value, index) => frozen[index] ? sum + value : sum, 0);
251
+ const share = wanted.reduce((sum, value, index) => frozen[index] ? sum : sum + value, 0);
252
+ let violated = false;
253
+ targets.forEach((_, index) => {
254
+ if (frozen[index])
255
+ return;
256
+ const size = share ? wanted[index] / share * (total - fixed) : 0;
257
+ const bounded = clamp(size, minOf(index), maxOf(index));
258
+ targets[index] = size;
259
+ if (bounded !== size) {
260
+ targets[index] = bounded;
261
+ frozen[index] = true;
262
+ violated = true;
263
+ }
264
+ });
265
+ if (!violated)
266
+ break;
267
+ }
268
+ setCollapsed(configs.map(startsCollapsed));
269
+ glide(targets);
270
+ }
271
+ function onKeyDown(handle, event) {
272
+ const current = drag.current;
273
+ if (event.key === "Escape" && current) {
274
+ // Escape during a drag puts the divider back where it started.
275
+ event.preventDefault();
276
+ drag.current = null;
277
+ setResizing(null);
278
+ setCollapsedPair(handle, current.startMode);
279
+ glide(sizes.map((_, index) => index === handle ? current.a0 : index === handle + 1 ? current.b0 : null));
280
+ return;
281
+ }
282
+ if (current || !["ArrowLeft", "ArrowRight", "Home", "End", "Enter"].includes(event.key))
283
+ return;
284
+ event.preventDefault();
285
+ const mode = modeOf(handle);
286
+ const canCollapseBefore = Boolean(configs[handle].collapsible), canCollapseAfter = Boolean(configs[handle + 1].collapsible);
287
+ if (event.key === "Enter") {
288
+ if (mode !== "open")
289
+ restore(handle, mode);
290
+ else if (canCollapseBefore)
291
+ collapse(handle, "before");
292
+ else if (canCollapseAfter)
293
+ collapse(handle, "after");
294
+ return;
295
+ }
296
+ // Repeated presses build on where the divider is heading, not on where the spring happens to be this frame.
297
+ const heading = goals.current && (sizes[handle].isAnimating() || sizes[handle + 1].isAnimating()) ? goals.current : null;
298
+ const values = begin([handle, handle + 1]);
299
+ const pair = values[handle] + values[handle + 1];
300
+ const a = heading ? clamp(heading[handle], 0, pair) : values[handle], step = event.shiftKey ? BIG_STEP : STEP;
301
+ const { lo, hi } = limits(handle, a, pair - a);
302
+ // Arrows walk out of a collapsed pane at its minimum, and past a limit into collapse when the pane allows it.
303
+ if (event.key === "ArrowLeft" && mode === "after")
304
+ return restoreTo(handle, hi, pair);
305
+ if (event.key === "ArrowRight" && mode === "before")
306
+ return restoreTo(handle, lo, pair);
307
+ if (event.key === "ArrowLeft" && a <= lo + .5 && canCollapseBefore && mode === "open")
308
+ return collapse(handle, "before");
309
+ if (event.key === "ArrowRight" && a >= hi - .5 && canCollapseAfter && mode === "open")
310
+ return collapse(handle, "after");
311
+ if (mode !== "open")
312
+ return;
313
+ const size = event.key === "Home" ? lo : event.key === "End" ? hi : clamp(a + (event.key === "ArrowLeft" ? -step : step), lo, hi);
314
+ glide(sizes.map((_, index) => index === handle ? size : index === handle + 1 ? pair - size : null), event.key.startsWith("Arrow") ? motionTokens.spring.snappy : motionTokens.spring.smooth);
315
+ }
316
+ function restoreTo(handle, size, pair) {
317
+ setCollapsedPair(handle, "open");
318
+ glide(sizes.map((_, index) => index === handle ? size : index === handle + 1 ? pair - size : null));
319
+ }
320
+ return _jsx("div", { ref: groupRef, className: [styles.group, className].filter(Boolean).join(" "), role: "group", "aria-label": label, "data-resizing": resizing !== null || undefined, children: configs.map((config, index) => _jsxs(Fragment, { children: [index > 0 && _jsx(Handle, { before: configs[index - 1], after: config, share: shares[index - 1], available: available, limits: available ? limits(index - 1, shares[index - 1] / 100 * available, shares[index] / 100 * available) : null, mode: collapsed[index - 1] ? "before" : collapsed[index] ? "after" : "open", active: resizing === index - 1, reduced: reduced, onPointerDown: event => onPointerDown(index - 1, event), onPointerMove: onPointerMove, onPointerUp: event => finish(event, false), onPointerCancel: event => finish(event, true), onKeyDown: event => onKeyDown(index - 1, event), onDoubleClick: reset }), _jsx(Pane, { config: config, size: sizes[index], fade: fades[index], collapsed: collapsed[index], free: free[index], anchor: index === 0 && count > 1 ? "end" : "start", minTotal: minTotal, gaps: count - 1, paneRef: node => { panelRefs.current[index] = node; } })] }, config.id)) });
321
+ }
322
+ function Pane({ config, size, fade, collapsed, free, anchor, minTotal, gaps, paneRef }) {
323
+ const grow = useTransform(size, value => Math.max(0, value));
324
+ const min = config.minSize ?? DEFAULT_MIN;
325
+ // The group is a size container: below the sum of the minimums, each floor becomes its share of the room between the dividers.
326
+ const style = { flexGrow: grow, "--panel-min": `min(${min}px, (100cqw - ${gaps}px) * ${+(min / Math.max(1, minTotal)).toFixed(5)})`, "--panel-max": config.maxSize ? `${config.maxSize}px` : "none" };
327
+ // The content stays anchored to the moving edge, so a closing pane slides away like a drawer instead of being crushed.
328
+ return _jsx(motion.div, { ref: paneRef, id: config.id, className: [styles.panel, config.className].filter(Boolean).join(" "), style: style, "data-collapsed": collapsed || undefined, "data-free": free || undefined, "data-anchor": anchor, children: _jsx(motion.div, { className: styles.content, style: { opacity: fade }, inert: collapsed, children: config.children }) });
329
+ }
330
+ /** A one pixel divider with a wider grab area. It shows a grip while hovered or dragged, and a restore tab once a neighbouring pane is hidden. */
331
+ function Handle({ before, after, share, available, limits, mode, active, reduced, onPointerDown, onPointerMove, onPointerUp, onPointerCancel, onKeyDown, onDoubleClick }) {
332
+ const now = Math.round(share);
333
+ const min = limits && available ? Math.round(limits.lo / available * 100) : 0;
334
+ const max = limits && available ? Math.round(limits.hi / available * 100) : 100;
335
+ const hidden = mode === "before" ? before.label : mode === "after" ? after.label : null;
336
+ return _jsxs("div", { role: "separator", tabIndex: 0, "aria-orientation": "vertical", "aria-controls": before.id, "aria-label": before.label, "aria-valuenow": now, "aria-valuemin": Math.min(min, now), "aria-valuemax": Math.max(max, now), "aria-valuetext": hidden ? `${hidden} hidden, press Enter to show` : `${now}%`, className: styles.handle, "data-collapsed": mode === "open" ? undefined : mode, "data-active": active || undefined, onPointerDown: onPointerDown, onPointerMove: onPointerMove, onPointerUp: onPointerUp, onPointerCancel: onPointerCancel, onKeyDown: onKeyDown, onDoubleClick: onDoubleClick, children: [_jsx("span", { className: styles.grip, "aria-hidden": "true" }), _jsx(AnimatePresence, { initial: false, children: mode !== "open" && _jsx(motion.span, { className: styles.restore, "data-side": mode, "aria-hidden": "true", initial: reduced ? { opacity: 0 } : tabIn, animate: tabRest, exit: reduced ? { opacity: 0, transition: { duration: motionTokens.duration.instant } } : tabOut, transition: reduced ? { duration: motionTokens.duration.instant } : tabEnter, children: mode === "before" ? _jsx(ChevronRight, { size: 14, strokeWidth: 1.75 }) : _jsx(ChevronLeft, { size: 14, strokeWidth: 1.75 }) }, mode) })] });
337
+ }
338
+ export default ResizablePanels;
@@ -0,0 +1,40 @@
1
+ /* Panes share the width through flex-grow factors, so the layout is right on the server and stays proportional as the group resizes. */
2
+ /* A size container, so each pane's floor can scale with the group when it is too narrow for every minimum (see --panel-min). */
3
+ .group { display: flex; width: 100%; height: 100%; min-width: 0; min-height: 0; overflow: hidden; container-type: inline-size; }
4
+ .group[data-resizing] { cursor: col-resize; user-select: none; -webkit-user-select: none; }
5
+ /* Content ignores the pointer while a divider moves, so hover states never flicker underneath it. */
6
+ .group[data-resizing] .content { pointer-events: none; }
7
+
8
+ /* CSS enforces each pane's limits until an interaction frees it; JS hands them back once the pane settles inside them. */
9
+ .panel { position: relative; display: flex; min-width: var(--panel-min); max-width: var(--panel-max); min-height: 0; flex: 0 1 0px; overflow: hidden; }
10
+ .panel[data-anchor="end"] { justify-content: flex-end; }
11
+ .panel[data-free], .panel[data-collapsed] { min-width: 0; max-width: none; }
12
+ .content { display: flex; width: 100%; flex: none; flex-direction: column; min-height: 0; }
13
+ .panel[data-free] .content, .panel[data-collapsed] .content { min-width: var(--panel-min); }
14
+
15
+ /* The divider is a one pixel line with a 13px grab area, and a grip that forms while it is hovered, focused, or dragged. */
16
+ .handle { position: relative; z-index: 2; flex: 0 0 1px; background: var(--border); cursor: col-resize; touch-action: none; outline: none; -webkit-tap-highlight-color: transparent; transition: background-color var(--duration-fast) var(--ease-standard); }
17
+ .handle::before { position: absolute; inset: 0 -6px; content: ""; }
18
+ .handle[data-collapsed] { background: transparent; cursor: pointer; }
19
+ .grip { position: absolute; top: 50%; left: 50%; width: 4px; height: 32px; border-radius: var(--radius-full); corner-shape: round; background: var(--border-strong); opacity: 0; pointer-events: none; transform: translate(-50%, -50%) scaleY(.6); transition: opacity var(--duration-fast) var(--ease-standard), background-color var(--duration-fast) var(--ease-standard), transform var(--duration-spring) var(--ease-spring); }
20
+ @media (hover: hover) and (pointer: fine) {
21
+ .handle:not([data-collapsed]):hover { background: var(--border-strong); }
22
+ .handle:not([data-collapsed]):hover .grip { opacity: 1; transform: translate(-50%, -50%) scaleY(1); }
23
+ .handle[data-collapsed]:hover .restore { border-color: var(--border-strong); color: var(--foreground); }
24
+ }
25
+ .handle[data-active] { background: var(--border-strong); }
26
+ .handle[data-active] .grip { background: var(--foreground); opacity: 1; transform: translate(-50%, -50%) scaleY(1); }
27
+ .handle:focus-visible:not([data-collapsed]) .grip { opacity: 1; transform: translate(-50%, -50%) scaleY(1); }
28
+ .handle[data-collapsed]:focus-visible .restore { border-color: var(--border-strong); color: var(--foreground); }
29
+
30
+ /* Once a neighbour is hidden, a tab on the divider points the way it will come back. */
31
+ .restore { position: absolute; top: 50%; display: grid; width: 18px; height: 40px; margin-top: -20px; place-items: center; border: 1px solid var(--border); border-radius: var(--radius-full); corner-shape: round; background: var(--surface); box-shadow: var(--shadow-resting); color: var(--text-secondary); pointer-events: none; transition: border-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
32
+ .restore[data-side="before"] { left: 5px; transform-origin: 0 50%; }
33
+ .restore[data-side="after"] { right: 5px; transform-origin: 100% 50%; }
34
+ .handle[data-collapsed]::before { inset: 0 -30px; }
35
+ .handle[data-collapsed="before"]::before { left: 0; }
36
+ .handle[data-collapsed="after"]::before { right: 0; }
37
+
38
+ @media (prefers-reduced-motion: reduce) {
39
+ .handle, .grip, .restore { transition: none; }
40
+ }
@@ -0,0 +1,55 @@
1
+ import type { CSSProperties } from "react";
2
+ export type BlockType = "p" | "h1" | "h2" | "h3" | "ul" | "ol" | "blockquote" | "pre" | "hr";
3
+ /** Adds a scheme to bare domains so `example.com/docs` becomes a working link. */
4
+ export declare function normalizeUrl(input: string): string;
5
+ /** Converts Markdown to the editor's HTML: headings (three levels), lists, quotes, fenced code, rules, and inline marks. */
6
+ export declare function markdownToHtml(markdown: string): string;
7
+ /** Converts editor HTML (or an element) to Markdown. */
8
+ export declare function htmlToMarkdown(input: string | HTMLElement): string;
9
+ /** Keeps only the tags the editor understands and drops every attribute except safe link targets. Bold and italic spans from other editors become marks. */
10
+ export declare function sanitizeHtml(html: string): string;
11
+ export interface RichTextValue {
12
+ html: string;
13
+ markdown: string;
14
+ text: string;
15
+ empty: boolean;
16
+ }
17
+ export interface RichTextEditorHandle {
18
+ focus: () => void;
19
+ getHTML: () => string;
20
+ getMarkdown: () => string;
21
+ getText: () => string;
22
+ setHTML: (html: string) => void;
23
+ setMarkdown: (markdown: string) => void;
24
+ clear: () => void;
25
+ undo: () => void;
26
+ redo: () => void;
27
+ element: HTMLDivElement | null;
28
+ }
29
+ export interface RichTextEditorProps {
30
+ /** Controlled HTML. The editor only rewrites its content when this differs from what it last emitted. */
31
+ value?: string;
32
+ defaultValue?: string;
33
+ /** Initial content as Markdown, used when no HTML value is given. */
34
+ defaultMarkdown?: string;
35
+ onChange?: (value: RichTextValue) => void;
36
+ /** Reports whether undo and redo are available, for your own toolbar. */
37
+ onHistoryChange?: (state: {
38
+ canUndo: boolean;
39
+ canRedo: boolean;
40
+ }) => void;
41
+ placeholder?: string;
42
+ /** The hint on an empty line while typing. */
43
+ blockHint?: string;
44
+ readOnly?: boolean;
45
+ autoFocus?: boolean;
46
+ "aria-label"?: string;
47
+ className?: string;
48
+ style?: CSSProperties;
49
+ }
50
+ /**
51
+ * A light rich text editor on contentEditable. Markdown shortcuts as you type, a floating selection toolbar that morphs into a link field,
52
+ * a slash menu for blocks, its own undo history, and HTML plus Markdown output. No dependencies beyond Motion and icons.
53
+ */
54
+ export declare const RichTextEditor: import("react").ForwardRefExoticComponent<RichTextEditorProps & import("react").RefAttributes<RichTextEditorHandle>>;
55
+ export default RichTextEditor;