@torpor/ui 0.4.0 → 1.0.1

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 (342) hide show
  1. package/README.md +83 -7
  2. package/dist/Accordion/Accordion.torp +42 -165
  3. package/dist/Accordion/AccordionContent.torp +6 -6
  4. package/dist/Accordion/AccordionHeader.torp +7 -11
  5. package/dist/Accordion/AccordionItem.torp +24 -24
  6. package/dist/Accordion/AccordionTrigger.torp +17 -8
  7. package/dist/Accordion/AccordionTypes.ts +1 -1
  8. package/dist/Accordion/index.d.ts +23 -25
  9. package/dist/Accordion/index.js +6 -22
  10. package/dist/Breadcrumb/Breadcrumb.torp +12 -10
  11. package/dist/Breadcrumb/BreadcrumbItem.torp +6 -6
  12. package/dist/Breadcrumb/BreadcrumbList.torp +21 -0
  13. package/dist/Breadcrumb/BreadcrumbSeparator.torp +4 -4
  14. package/dist/Breadcrumb/index.d.ts +39 -15
  15. package/dist/Breadcrumb/index.js +5 -14
  16. package/dist/Calendar/Calendar.torp +163 -156
  17. package/dist/Calendar/CalendarDay.torp +91 -45
  18. package/dist/Calendar/CalendarDayHeader.torp +36 -0
  19. package/dist/Calendar/CalendarGrid.torp +104 -0
  20. package/dist/Calendar/CalendarGridHeader.torp +43 -0
  21. package/dist/Calendar/CalendarHeader.torp +48 -0
  22. package/dist/Calendar/CalendarHeaderTrigger.torp +54 -0
  23. package/dist/Calendar/CalendarTypes.ts +24 -3
  24. package/dist/Calendar/buildDays.ts +54 -0
  25. package/dist/Calendar/index.d.ts +191 -5
  26. package/dist/Calendar/index.js +8 -10
  27. package/dist/Carousel/Carousel.torp +180 -0
  28. package/dist/Carousel/CarouselIndicators.torp +65 -0
  29. package/dist/Carousel/CarouselNext.torp +43 -0
  30. package/dist/Carousel/CarouselPrevious.torp +44 -0
  31. package/dist/Carousel/CarouselSlide.torp +57 -0
  32. package/dist/Carousel/CarouselTypes.ts +28 -0
  33. package/dist/Carousel/index.d.ts +147 -0
  34. package/dist/Carousel/index.js +6 -0
  35. package/dist/Charts/BarChart.torp +55 -144
  36. package/dist/Charts/Chart.torp +120 -0
  37. package/dist/Charts/ChartBars.torp +78 -0
  38. package/dist/Charts/ChartColumns.torp +66 -0
  39. package/dist/Charts/ChartGrid.torp +54 -0
  40. package/dist/Charts/ChartLines.torp +60 -0
  41. package/dist/Charts/ChartTypes.ts +25 -0
  42. package/dist/Charts/ChartXAxis.torp +85 -0
  43. package/dist/Charts/ChartYAxis.torp +107 -0
  44. package/dist/Charts/ColumnChart.torp +70 -0
  45. package/dist/Charts/GridLines.torp +4 -4
  46. package/dist/Charts/LineChart.torp +55 -178
  47. package/dist/Charts/PieChart.torp +14 -20
  48. package/dist/Charts/ScatterChart.torp +45 -38
  49. package/dist/Charts/SparkLine.torp +16 -19
  50. package/dist/Charts/XAxis.torp +14 -11
  51. package/dist/Charts/YAxis.torp +10 -8
  52. package/dist/Charts/index.d.ts +328 -79
  53. package/dist/Charts/index.js +17 -34
  54. package/dist/ColorPicker/ColorPalette.torp +154 -0
  55. package/dist/ColorPicker/ColorPicker.torp +157 -0
  56. package/dist/ColorPicker/index.d.ts +85 -0
  57. package/dist/ColorPicker/index.js +3 -0
  58. package/dist/ComboBox/ComboBox.torp +205 -0
  59. package/dist/ComboBox/ComboBoxContent.torp +120 -0
  60. package/dist/ComboBox/ComboBoxInput.torp +161 -0
  61. package/dist/ComboBox/ComboBoxTrigger.torp +49 -0
  62. package/dist/ComboBox/ComboBoxTypes.ts +39 -0
  63. package/dist/ComboBox/index.d.ts +154 -0
  64. package/dist/ComboBox/index.js +6 -0
  65. package/dist/CommandPalette/CommandPalette.torp +223 -0
  66. package/dist/CommandPalette/CommandTypes.ts +14 -0
  67. package/dist/CommandPalette/index.d.ts +45 -0
  68. package/dist/CommandPalette/index.js +2 -0
  69. package/dist/Contextual/Contextual.torp +32 -50
  70. package/dist/Contextual/ContextualContent.torp +29 -73
  71. package/dist/Contextual/ContextualHover.torp +112 -0
  72. package/dist/Contextual/ContextualTrigger.torp +31 -42
  73. package/dist/Contextual/ContextualTypes.ts +4 -17
  74. package/dist/Contextual/index.d.ts +44 -27
  75. package/dist/Contextual/index.js +5 -14
  76. package/dist/DataGrid/DataGrid.torp +496 -0
  77. package/dist/DataGrid/DataGridTypes.ts +25 -0
  78. package/dist/DataGrid/index.d.ts +90 -0
  79. package/dist/DataGrid/index.js +3 -0
  80. package/dist/DataGrid/sortRows.ts +32 -0
  81. package/dist/DatePicker/DatePicker.torp +222 -0
  82. package/dist/DatePicker/DatePickerHeader.torp +20 -0
  83. package/dist/DatePicker/index.d.ts +55 -0
  84. package/dist/DatePicker/index.js +2 -0
  85. package/dist/DateRangePicker/DateRangePicker.torp +315 -0
  86. package/dist/DateRangePicker/DateRangePickerDay.torp +137 -0
  87. package/dist/DateRangePicker/DateRangePickerTypes.ts +21 -0
  88. package/dist/DateRangePicker/index.d.ts +76 -0
  89. package/dist/DateRangePicker/index.js +3 -0
  90. package/dist/Dialog/Dialog.torp +24 -17
  91. package/dist/Dialog/DialogBody.torp +5 -9
  92. package/dist/Dialog/DialogButton.torp +12 -12
  93. package/dist/Dialog/DialogFooter.torp +3 -7
  94. package/dist/Dialog/DialogHeader.torp +6 -10
  95. package/dist/Dialog/index.d.ts +27 -27
  96. package/dist/Dialog/index.js +6 -22
  97. package/dist/Disclosure/Disclosure.torp +18 -18
  98. package/dist/Disclosure/DisclosureContent.torp +5 -6
  99. package/dist/Disclosure/DisclosureHeader.torp +7 -11
  100. package/dist/Disclosure/DisclosureTrigger.torp +4 -5
  101. package/dist/Disclosure/index.d.ts +14 -16
  102. package/dist/Disclosure/index.js +5 -18
  103. package/dist/Drawer/Drawer.torp +19 -49
  104. package/dist/Drawer/DrawerContent.torp +70 -13
  105. package/dist/Drawer/DrawerOverlay.torp +4 -4
  106. package/dist/Drawer/DrawerTrigger.torp +16 -4
  107. package/dist/Drawer/DrawerTypes.ts +3 -0
  108. package/dist/Drawer/index.d.ts +16 -20
  109. package/dist/Drawer/index.js +5 -18
  110. package/dist/FocusGroup/FocusGroup.torp +70 -0
  111. package/dist/FocusGroup/FocusGroupButton.torp +59 -0
  112. package/dist/FocusGroup/FocusGroupTypes.ts +14 -0
  113. package/dist/FocusGroup/index.d.ts +44 -0
  114. package/dist/FocusGroup/index.js +3 -0
  115. package/dist/Form/CheckBox.torp +27 -18
  116. package/dist/Form/Field.torp +17 -17
  117. package/dist/Form/File.torp +31 -22
  118. package/dist/Form/FileDrop.torp +187 -0
  119. package/dist/Form/Form.torp +24 -22
  120. package/dist/Form/FormTypes.ts +2 -0
  121. package/dist/Form/FormValues.torp +37 -0
  122. package/dist/Form/Hidden.torp +4 -12
  123. package/dist/Form/Input.torp +38 -32
  124. package/dist/Form/Label.torp +3 -3
  125. package/dist/Form/Message.torp +13 -5
  126. package/dist/Form/MessageSummary.torp +5 -4
  127. package/dist/Form/Option.torp +11 -7
  128. package/dist/Form/Select.torp +32 -28
  129. package/dist/Form/TextArea.torp +35 -31
  130. package/dist/Form/Toggle.torp +109 -0
  131. package/dist/Form/index.d.ts +178 -79
  132. package/dist/Form/index.js +16 -50
  133. package/dist/ListBox/ListBox.torp +253 -150
  134. package/dist/ListBox/ListBoxItem.torp +54 -30
  135. package/dist/ListBox/ListBoxSeparator.torp +5 -2
  136. package/dist/ListBox/ListBoxTypes.ts +23 -5
  137. package/dist/ListBox/LoadedListBoxItems.torp +41 -0
  138. package/dist/ListBox/index.d.ts +56 -17
  139. package/dist/ListBox/index.js +4 -14
  140. package/dist/MaskedInput/MaskedInput.torp +143 -0
  141. package/dist/MaskedInput/index.d.ts +52 -0
  142. package/dist/MaskedInput/index.js +2 -0
  143. package/dist/Menu/Menu.torp +86 -71
  144. package/dist/Menu/MenuButton.torp +17 -10
  145. package/dist/Menu/MenuCheck.torp +22 -18
  146. package/dist/Menu/MenuGroup.torp +4 -4
  147. package/dist/Menu/MenuIndicator.torp +5 -13
  148. package/dist/Menu/MenuPopout.torp +20 -50
  149. package/dist/Menu/MenuPopoutContent.torp +15 -66
  150. package/dist/Menu/MenuPopoutTrigger.torp +19 -100
  151. package/dist/Menu/MenuRadio.torp +25 -26
  152. package/dist/Menu/MenuRadioGroup.torp +25 -68
  153. package/dist/Menu/MenuSeparator.torp +3 -2
  154. package/dist/Menu/MenuTypes.ts +9 -19
  155. package/dist/Menu/index.d.ts +45 -51
  156. package/dist/Menu/index.js +12 -46
  157. package/dist/MenuBar/MenuBar.torp +31 -83
  158. package/dist/MenuBar/MenuBarItem.torp +33 -51
  159. package/dist/MenuBar/MenuBarItemContent.torp +15 -101
  160. package/dist/MenuBar/MenuBarItemTrigger.torp +20 -55
  161. package/dist/MenuBar/MenuBarTypes.ts +11 -10
  162. package/dist/MenuBar/index.d.ts +17 -19
  163. package/dist/MenuBar/index.js +5 -18
  164. package/dist/Modal/Modal.torp +22 -47
  165. package/dist/Modal/ModalContent.torp +21 -44
  166. package/dist/Modal/ModalOverlay.torp +4 -4
  167. package/dist/Modal/ModalTrigger.torp +16 -32
  168. package/dist/Modal/ModalTypes.ts +5 -16
  169. package/dist/Modal/index.d.ts +17 -29
  170. package/dist/Modal/index.js +29 -28
  171. package/dist/Modal/index.js.map +1 -1
  172. package/dist/Modal/showPrompt.ts +2 -2
  173. package/dist/NavMenu/NavMenu.torp +22 -111
  174. package/dist/NavMenu/NavMenuButton.torp +7 -8
  175. package/dist/NavMenu/NavMenuElement.torp +6 -7
  176. package/dist/NavMenu/NavMenuGroup.torp +5 -5
  177. package/dist/NavMenu/NavMenuGroupHeader.torp +5 -8
  178. package/dist/NavMenu/NavMenuLink.torp +7 -10
  179. package/dist/NavMenu/NavMenuPopout.torp +15 -60
  180. package/dist/NavMenu/NavMenuPopoutContent.torp +14 -73
  181. package/dist/NavMenu/NavMenuPopoutTrigger.torp +17 -99
  182. package/dist/NavMenu/NavMenuSeparator.torp +3 -7
  183. package/dist/NavMenu/NavMenuTypes.ts +4 -14
  184. package/dist/NavMenu/index.d.ts +40 -44
  185. package/dist/NavMenu/index.js +11 -42
  186. package/dist/Notification/Notification.torp +12 -24
  187. package/dist/Notification/NotificationClose.torp +6 -3
  188. package/dist/Notification/NotificationContainer.torp +3 -7
  189. package/dist/Notification/NotificationContent.torp +3 -7
  190. package/dist/Notification/NotificationTypes.ts +1 -1
  191. package/dist/Notification/index.d.ts +15 -12
  192. package/dist/Notification/index.js +22 -32
  193. package/dist/Notification/index.js.map +1 -1
  194. package/dist/NumberInput/NumberInput.torp +255 -0
  195. package/dist/NumberInput/index.d.ts +44 -0
  196. package/dist/NumberInput/index.js +2 -0
  197. package/dist/Pagination/Pagination.torp +41 -34
  198. package/dist/Pagination/PaginationItem.torp +50 -13
  199. package/dist/Pagination/PaginationTypes.ts +3 -6
  200. package/dist/Pagination/buildPages.ts +9 -5
  201. package/dist/Pagination/index.d.ts +19 -9
  202. package/dist/Pagination/index.js +3 -40
  203. package/dist/Popover/Popover.torp +32 -50
  204. package/dist/Popover/PopoverContent.torp +27 -76
  205. package/dist/Popover/PopoverHover.torp +90 -0
  206. package/dist/Popover/PopoverTrigger.torp +17 -40
  207. package/dist/Popover/PopoverTypes.ts +4 -17
  208. package/dist/Popover/index.d.ts +40 -25
  209. package/dist/Popover/index.js +18 -18
  210. package/dist/Popover/index.js.map +1 -1
  211. package/dist/Progress/Progress.torp +88 -0
  212. package/dist/Progress/index.d.ts +37 -0
  213. package/dist/Progress/index.js +2 -0
  214. package/dist/Rating/Rating.torp +225 -0
  215. package/dist/Rating/index.d.ts +44 -0
  216. package/dist/Rating/index.js +2 -0
  217. package/dist/SegmentedControl/SegmentedControl.torp +233 -0
  218. package/dist/SegmentedControl/SegmentedControlTypes.ts +26 -0
  219. package/dist/SegmentedControl/SegmentedItem.torp +78 -0
  220. package/dist/SegmentedControl/index.d.ts +74 -0
  221. package/dist/SegmentedControl/index.js +3 -0
  222. package/dist/SelectBox/SelectBox.torp +107 -53
  223. package/dist/SelectBox/SelectBoxContent.torp +49 -19
  224. package/dist/SelectBox/SelectBoxTrigger.torp +108 -8
  225. package/dist/SelectBox/SelectBoxTypes.ts +26 -11
  226. package/dist/SelectBox/index.d.ts +39 -54
  227. package/dist/SelectBox/index.js +5 -18
  228. package/dist/Slider/Slider.torp +245 -0
  229. package/dist/Slider/index.d.ts +45 -0
  230. package/dist/Slider/index.js +2 -0
  231. package/dist/Splitter/Splitter.torp +156 -0
  232. package/dist/Splitter/SplitterHandle.torp +161 -0
  233. package/dist/Splitter/SplitterPane.torp +63 -0
  234. package/dist/Splitter/SplitterTypes.ts +31 -0
  235. package/dist/Splitter/index.d.ts +103 -0
  236. package/dist/Splitter/index.js +4 -0
  237. package/dist/Stepper/Stepper.torp +146 -0
  238. package/dist/Stepper/StepperMarker.torp +24 -0
  239. package/dist/Stepper/StepperNext.torp +44 -0
  240. package/dist/Stepper/StepperPrevious.torp +44 -0
  241. package/dist/Stepper/StepperStep.torp +90 -0
  242. package/dist/Stepper/StepperTypes.ts +30 -0
  243. package/dist/Stepper/index.d.ts +149 -0
  244. package/dist/Stepper/index.js +6 -0
  245. package/dist/TabGroup/TabContent.torp +6 -6
  246. package/dist/TabGroup/TabGroup.torp +97 -113
  247. package/dist/TabGroup/TabGroupTypes.ts +1 -1
  248. package/dist/TabGroup/TabHeader.torp +23 -19
  249. package/dist/TabGroup/TabList.torp +8 -21
  250. package/dist/TabGroup/TabTrigger.torp +6 -7
  251. package/dist/TabGroup/index.d.ts +26 -26
  252. package/dist/TabGroup/index.js +6 -22
  253. package/dist/TagInput/TagInput.torp +378 -0
  254. package/dist/TagInput/index.d.ts +48 -0
  255. package/dist/TagInput/index.js +2 -0
  256. package/dist/TimePicker/TimePicker.torp +462 -0
  257. package/dist/TimePicker/index.d.ts +53 -0
  258. package/dist/TimePicker/index.js +2 -0
  259. package/dist/ToolBar/ToolBar.torp +29 -110
  260. package/dist/ToolBar/ToolBarButton.torp +7 -8
  261. package/dist/ToolBar/ToolBarElement.torp +7 -11
  262. package/dist/ToolBar/ToolBarPopout.torp +16 -68
  263. package/dist/ToolBar/ToolBarPopoutContent.torp +15 -73
  264. package/dist/ToolBar/ToolBarPopoutTrigger.torp +19 -110
  265. package/dist/ToolBar/ToolBarSeparator.torp +3 -7
  266. package/dist/ToolBar/ToolBarTypes.ts +7 -14
  267. package/dist/ToolBar/index.d.ts +30 -32
  268. package/dist/ToolBar/index.js +8 -30
  269. package/dist/Tree/Tree.torp +395 -0
  270. package/dist/Tree/TreeItem.torp +176 -0
  271. package/dist/Tree/TreeItemChildren.torp +60 -0
  272. package/dist/Tree/TreeItemContent.torp +46 -0
  273. package/dist/Tree/TreeItemLabel.torp +94 -0
  274. package/dist/Tree/TreeItemTrigger.torp +78 -0
  275. package/dist/Tree/TreeLoadedChildren.torp +122 -0
  276. package/dist/Tree/TreeTypes.ts +63 -0
  277. package/dist/Tree/index.d.ts +262 -0
  278. package/dist/Tree/index.js +7 -0
  279. package/dist/icons/ChevronDoubleLeft.torp +19 -0
  280. package/dist/icons/ChevronDoubleRight.torp +19 -0
  281. package/dist/icons/index.d.ts +61 -1
  282. package/dist/icons/index.js +17 -58
  283. package/dist/loader-DEeG5vFY.js +44 -0
  284. package/dist/loader-DEeG5vFY.js.map +1 -0
  285. package/dist/motion/index.d.ts +12 -8
  286. package/dist/motion/index.d.ts.map +1 -0
  287. package/dist/motion/index.js +70 -88
  288. package/dist/motion/index.js.map +1 -1
  289. package/dist/mount/draggable.ts +63 -0
  290. package/dist/mount/dropTarget.ts +108 -0
  291. package/dist/mount/hoverTrigger.ts +1 -1
  292. package/dist/utils/$handle.ts +23 -0
  293. package/dist/utils/LoadedItems.torp +47 -0
  294. package/dist/utils/PopoutClickTrigger.torp +99 -0
  295. package/dist/utils/PopoutTypes.ts +59 -12
  296. package/dist/utils/SubmenuPopout.torp +89 -0
  297. package/dist/utils/SubmenuPopoutContent.torp +87 -0
  298. package/dist/utils/SubmenuPopoutTrigger.torp +160 -0
  299. package/dist/utils/chartColors.ts +13 -13
  300. package/dist/utils/chartLayout.ts +143 -0
  301. package/dist/utils/colorUtils.ts +103 -0
  302. package/dist/utils/createItemGroup.ts +152 -0
  303. package/dist/utils/dateUtils.ts +8 -7
  304. package/dist/utils/documentEvents.ts +4 -4
  305. package/dist/utils/dragState.ts +86 -0
  306. package/dist/utils/focusGroup.ts +204 -0
  307. package/dist/utils/focusItem.ts +44 -0
  308. package/dist/utils/formField.ts +70 -0
  309. package/dist/utils/hoverOpen.ts +50 -0
  310. package/dist/utils/hoverReveal.ts +194 -0
  311. package/dist/utils/loader.ts +113 -0
  312. package/dist/utils/maskUtils.ts +98 -0
  313. package/dist/utils/popoutContent.ts +137 -0
  314. package/dist/utils/reorderList.ts +52 -0
  315. package/package.json +97 -22
  316. package/dist/Accordion/index.js.map +0 -1
  317. package/dist/Breadcrumb/index.js.map +0 -1
  318. package/dist/Calendar/index.js.map +0 -1
  319. package/dist/Charts/index.js.map +0 -1
  320. package/dist/Contextual/index.js.map +0 -1
  321. package/dist/Dialog/index.js.map +0 -1
  322. package/dist/Disclosure/index.js.map +0 -1
  323. package/dist/Drawer/index.js.map +0 -1
  324. package/dist/Form/index.js.map +0 -1
  325. package/dist/ListBox/index.js.map +0 -1
  326. package/dist/Menu/index.js.map +0 -1
  327. package/dist/MenuBar/index.js.map +0 -1
  328. package/dist/NavMenu/index.js.map +0 -1
  329. package/dist/Pagination/index.js.map +0 -1
  330. package/dist/SelectBox/SelectBoxInput.torp +0 -95
  331. package/dist/SelectBox/index.js.map +0 -1
  332. package/dist/TabGroup/index.js.map +0 -1
  333. package/dist/ToolBar/index.js.map +0 -1
  334. package/dist/icons/index.js.map +0 -1
  335. package/dist/index.d.ts +0 -19
  336. package/dist/metafile-esm.json +0 -1
  337. package/dist/motion/fade.ts +0 -16
  338. package/dist/motion/grow.ts +0 -23
  339. package/dist/motion/measure.ts +0 -28
  340. package/dist/motion/slide.ts +0 -45
  341. package/dist/mount/index.d.ts +0 -2
  342. package/dist/utils/index.d.ts +0 -2
@@ -1,97 +1,79 @@
1
- // src/motion/fade.ts
1
+ //#region src/motion/fade.ts
2
2
  function fade(_el, options) {
3
- const keyframes = [
4
- {
5
- opacity: 0
6
- },
7
- {
8
- opacity: 1
9
- }
10
- ];
11
- return { keyframes, options };
3
+ return {
4
+ keyframes: [{ opacity: 0 }, { opacity: 1 }],
5
+ options
6
+ };
12
7
  }
13
-
14
- // src/motion/measure.ts
8
+ //#endregion
9
+ //#region src/motion/measure.ts
10
+ /**
11
+ * Measures an element before it is added to the DOM
12
+ * @param el The element to measure
13
+ * @param fn The function to use to get the desired measurement (e.g. el.offsetHeight)
14
+ */
15
15
  function measure(el, fn) {
16
- let oldVisibility = el.style.visibility;
17
- let oldPosition = el.style.position;
18
- let oldParent = el.parentNode;
19
- let oldBefore = el.nextSibling;
20
- el.style.visibility = "hidden";
21
- el.style.position = "absolute";
22
- document.body.appendChild(el);
23
- let result = fn(el);
24
- el.parentNode.removeChild(el);
25
- if (oldParent !== null) {
26
- oldParent.insertBefore(el, oldBefore);
27
- el.style.visibility = oldVisibility;
28
- el.style.position = oldPosition;
29
- }
30
- return result;
16
+ let oldVisibility = el.style.visibility;
17
+ let oldPosition = el.style.position;
18
+ let oldParent = el.parentNode;
19
+ let oldBefore = el.nextSibling;
20
+ el.style.visibility = "hidden";
21
+ el.style.position = "absolute";
22
+ document.body.appendChild(el);
23
+ let result = fn(el);
24
+ el.parentNode.removeChild(el);
25
+ el.style.visibility = oldVisibility;
26
+ el.style.position = oldPosition;
27
+ if (oldParent !== null) oldParent.insertBefore(el, oldBefore);
28
+ return result;
31
29
  }
32
-
33
- // src/motion/grow.ts
30
+ //#endregion
31
+ //#region src/motion/grow.ts
34
32
  function grow(el, options) {
35
- const height = measure(el, (el2) => el2.clientHeight);
36
- const keyframes = [
37
- {
38
- height: "0px",
39
- overflow: "hidden",
40
- paddingTop: "0px",
41
- paddingBottom: "0px",
42
- marginTop: "0px",
43
- marginBottom: "0px"
44
- },
45
- {
46
- height: height + "px"
47
- }
48
- ];
49
- return { keyframes, options };
33
+ return {
34
+ keyframes: [{
35
+ height: "0px",
36
+ overflow: "hidden",
37
+ paddingTop: "0px",
38
+ paddingBottom: "0px",
39
+ marginTop: "0px",
40
+ marginBottom: "0px"
41
+ }, { height: measure(el, (el) => el.clientHeight) + "px" }],
42
+ options
43
+ };
50
44
  }
51
-
52
- // src/motion/slide.ts
45
+ //#endregion
46
+ //#region src/motion/slide.ts
53
47
  function slide(el, options) {
54
- let position = options?.side ?? "left";
55
- switch (position) {
56
- case "left": {
57
- el.style.left = "0px";
58
- const width = measure(el, (el2) => el2.offsetWidth);
59
- const keyframes = [
60
- { transform: `translateX(-${width}px)` },
61
- { transform: "translateX(0px)" }
62
- ];
63
- return { keyframes, options };
64
- }
65
- case "top": {
66
- el.style.top = "0px";
67
- const height = measure(el, (el2) => el2.offsetHeight);
68
- const keyframes = [
69
- { transform: `translateY(-${height}px)` },
70
- { transform: "translateY(0px)" }
71
- ];
72
- return { keyframes, options };
73
- }
74
- case "right": {
75
- el.style.right = "0px";
76
- const width = measure(el, (el2) => el2.offsetWidth);
77
- const keyframes = [{ transform: `translateX(${width}px)` }, { transform: "translateX(0px)" }];
78
- return { keyframes, options };
79
- }
80
- case "bottom": {
81
- el.style.bottom = "0px";
82
- const height = measure(el, (el2) => el2.offsetHeight);
83
- const keyframes = [
84
- { transform: `translateY(${height}px)` },
85
- { transform: "translateY(0px)" }
86
- ];
87
- return { keyframes, options };
88
- }
89
- }
48
+ el.style.position = "fixed";
49
+ switch (options?.side ?? "left") {
50
+ case "left":
51
+ el.style.left = "0px";
52
+ return {
53
+ keyframes: [{ transform: `translateX(-${measure(el, (el) => el.offsetWidth)}px)` }, { transform: "translateX(0px)" }],
54
+ options
55
+ };
56
+ case "top":
57
+ el.style.top = "0px";
58
+ return {
59
+ keyframes: [{ transform: `translateY(-${measure(el, (el) => el.offsetHeight)}px)` }, { transform: "translateY(0px)" }],
60
+ options
61
+ };
62
+ case "right":
63
+ el.style.right = "0px";
64
+ return {
65
+ keyframes: [{ transform: `translateX(${measure(el, (el) => el.offsetWidth)}px)` }, { transform: "translateX(0px)" }],
66
+ options
67
+ };
68
+ case "bottom":
69
+ el.style.bottom = "0px";
70
+ return {
71
+ keyframes: [{ transform: `translateY(${measure(el, (el) => el.offsetHeight)}px)` }, { transform: "translateY(0px)" }],
72
+ options
73
+ };
74
+ }
90
75
  }
91
- export {
92
- fade,
93
- grow,
94
- measure,
95
- slide
96
- };
76
+ //#endregion
77
+ export { fade, grow, measure, slide };
78
+
97
79
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/motion/fade.ts","../../src/motion/measure.ts","../../src/motion/grow.ts","../../src/motion/slide.ts"],"sourcesContent":["import { type Animation } from \"@torpor/view\";\n\nexport default function fade(\n\t_el: HTMLElement,\n\toptions?: number | KeyframeAnimationOptions,\n): Animation {\n\tconst keyframes = [\n\t\t{\n\t\t\topacity: 0,\n\t\t},\n\t\t{\n\t\t\topacity: 1,\n\t\t},\n\t];\n\treturn { keyframes, options };\n}\n","/**\n * Measures an element before it is added to the DOM\n * @param el The element to measure\n * @param fn The function to use to get the desired measurement (e.g. el.offsetHeight)\n */\nexport default function measure(el: HTMLElement, fn: (_: HTMLElement) => number): number {\n\t// From https://stackoverflow.com/a/46707458\n\tlet oldVisibility = el.style.visibility;\n\tlet oldPosition = el.style.position;\n\n\tlet oldParent = el.parentNode;\n\tlet oldBefore = el.nextSibling;\n\n\tel.style.visibility = \"hidden\";\n\tel.style.position = \"absolute\";\n\n\tdocument.body.appendChild(el);\n\tlet result = fn(el);\n\tel.parentNode!.removeChild(el);\n\n\tif (oldParent !== null) {\n\t\toldParent.insertBefore(el, oldBefore);\n\t\tel.style.visibility = oldVisibility;\n\t\tel.style.position = oldPosition;\n\t}\n\n\treturn result;\n}\n","import { type Animation } from \"@torpor/view\";\nimport measure from \"./measure\";\n\nexport default function grow(\n\tel: HTMLElement,\n\toptions?: number | KeyframeAnimationOptions,\n): Animation {\n\tconst height = measure(el, (el) => el.clientHeight);\n\tconst keyframes = [\n\t\t{\n\t\t\theight: \"0px\",\n\t\t\toverflow: \"hidden\",\n\t\t\tpaddingTop: \"0px\",\n\t\t\tpaddingBottom: \"0px\",\n\t\t\tmarginTop: \"0px\",\n\t\t\tmarginBottom: \"0px\",\n\t\t},\n\t\t{\n\t\t\theight: height + \"px\",\n\t\t},\n\t];\n\treturn { keyframes, options };\n}\n","import { type Animation } from \"@torpor/view\";\nimport measure from \"./measure\";\n\ninterface Options extends KeyframeAnimationOptions {\n\tside: \"left\" | \"right\" | \"top\" | \"bottom\";\n}\n\nexport default function slide(el: HTMLElement, options?: Options): Animation {\n\tlet position = options?.side ?? \"left\";\n\tswitch (position) {\n\t\tcase \"left\": {\n\t\t\tel.style.left = \"0px\";\n\t\t\tconst width = measure(el, (el) => el.offsetWidth);\n\t\t\tconst keyframes = [\n\t\t\t\t{ transform: `translateX(-${width}px)` },\n\t\t\t\t{ transform: \"translateX(0px)\" },\n\t\t\t];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t\tcase \"top\": {\n\t\t\tel.style.top = \"0px\";\n\t\t\tconst height = measure(el, (el) => el.offsetHeight);\n\t\t\tconst keyframes = [\n\t\t\t\t{ transform: `translateY(-${height}px)` },\n\t\t\t\t{ transform: \"translateY(0px)\" },\n\t\t\t];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t\tcase \"right\": {\n\t\t\tel.style.right = \"0px\";\n\t\t\tconst width = measure(el, (el) => el.offsetWidth);\n\t\t\tconst keyframes = [{ transform: `translateX(${width}px)` }, { transform: \"translateX(0px)\" }];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t\tcase \"bottom\": {\n\t\t\tel.style.bottom = \"0px\";\n\t\t\tconst height = measure(el, (el) => el.offsetHeight);\n\t\t\tconst keyframes = [\n\t\t\t\t{ transform: `translateY(${height}px)` },\n\t\t\t\t{ transform: \"translateY(0px)\" },\n\t\t\t];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t}\n}\n"],"mappings":";AAEe,SAAR,KACN,KACA,SACY;AACZ,QAAM,YAAY;AAAA,IACjB;AAAA,MACC,SAAS;AAAA,IACV;AAAA,IACA;AAAA,MACC,SAAS;AAAA,IACV;AAAA,EACD;AACA,SAAO,EAAE,WAAW,QAAQ;AAC7B;;;ACVe,SAAR,QAAyB,IAAiB,IAAwC;AAExF,MAAI,gBAAgB,GAAG,MAAM;AAC7B,MAAI,cAAc,GAAG,MAAM;AAE3B,MAAI,YAAY,GAAG;AACnB,MAAI,YAAY,GAAG;AAEnB,KAAG,MAAM,aAAa;AACtB,KAAG,MAAM,WAAW;AAEpB,WAAS,KAAK,YAAY,EAAE;AAC5B,MAAI,SAAS,GAAG,EAAE;AAClB,KAAG,WAAY,YAAY,EAAE;AAE7B,MAAI,cAAc,MAAM;AACvB,cAAU,aAAa,IAAI,SAAS;AACpC,OAAG,MAAM,aAAa;AACtB,OAAG,MAAM,WAAW;AAAA,EACrB;AAEA,SAAO;AACR;;;ACxBe,SAAR,KACN,IACA,SACY;AACZ,QAAM,SAAS,QAAQ,IAAI,CAACA,QAAOA,IAAG,YAAY;AAClD,QAAM,YAAY;AAAA,IACjB;AAAA,MACC,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,eAAe;AAAA,MACf,WAAW;AAAA,MACX,cAAc;AAAA,IACf;AAAA,IACA;AAAA,MACC,QAAQ,SAAS;AAAA,IAClB;AAAA,EACD;AACA,SAAO,EAAE,WAAW,QAAQ;AAC7B;;;ACfe,SAAR,MAAuB,IAAiB,SAA8B;AAC5E,MAAI,WAAW,SAAS,QAAQ;AAChC,UAAQ,UAAU;AAAA,IACjB,KAAK,QAAQ;AACZ,SAAG,MAAM,OAAO;AAChB,YAAM,QAAQ,QAAQ,IAAI,CAACC,QAAOA,IAAG,WAAW;AAChD,YAAM,YAAY;AAAA,QACjB,EAAE,WAAW,eAAe,KAAK,MAAM;AAAA,QACvC,EAAE,WAAW,kBAAkB;AAAA,MAChC;AACA,aAAO,EAAE,WAAW,QAAQ;AAAA,IAC7B;AAAA,IACA,KAAK,OAAO;AACX,SAAG,MAAM,MAAM;AACf,YAAM,SAAS,QAAQ,IAAI,CAACA,QAAOA,IAAG,YAAY;AAClD,YAAM,YAAY;AAAA,QACjB,EAAE,WAAW,eAAe,MAAM,MAAM;AAAA,QACxC,EAAE,WAAW,kBAAkB;AAAA,MAChC;AACA,aAAO,EAAE,WAAW,QAAQ;AAAA,IAC7B;AAAA,IACA,KAAK,SAAS;AACb,SAAG,MAAM,QAAQ;AACjB,YAAM,QAAQ,QAAQ,IAAI,CAACA,QAAOA,IAAG,WAAW;AAChD,YAAM,YAAY,CAAC,EAAE,WAAW,cAAc,KAAK,MAAM,GAAG,EAAE,WAAW,kBAAkB,CAAC;AAC5F,aAAO,EAAE,WAAW,QAAQ;AAAA,IAC7B;AAAA,IACA,KAAK,UAAU;AACd,SAAG,MAAM,SAAS;AAClB,YAAM,SAAS,QAAQ,IAAI,CAACA,QAAOA,IAAG,YAAY;AAClD,YAAM,YAAY;AAAA,QACjB,EAAE,WAAW,cAAc,MAAM,MAAM;AAAA,QACvC,EAAE,WAAW,kBAAkB;AAAA,MAChC;AACA,aAAO,EAAE,WAAW,QAAQ;AAAA,IAC7B;AAAA,EACD;AACD;","names":["el","el"]}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/motion/fade.ts","../../src/motion/measure.ts","../../src/motion/grow.ts","../../src/motion/slide.ts"],"sourcesContent":["import { type Animation } from \"@torpor/view\";\n\nexport default function fade(\n\t_el: HTMLElement,\n\toptions?: number | KeyframeAnimationOptions,\n): Animation {\n\tconst keyframes = [\n\t\t{\n\t\t\topacity: 0,\n\t\t},\n\t\t{\n\t\t\topacity: 1,\n\t\t},\n\t];\n\treturn { keyframes, options };\n}\n","/**\n * Measures an element before it is added to the DOM\n * @param el The element to measure\n * @param fn The function to use to get the desired measurement (e.g. el.offsetHeight)\n */\nexport default function measure(el: HTMLElement, fn: (_el: HTMLElement) => number): number {\n\t// From https://stackoverflow.com/a/46707458\n\tlet oldVisibility = el.style.visibility;\n\tlet oldPosition = el.style.position;\n\n\tlet oldParent = el.parentNode;\n\tlet oldBefore = el.nextSibling;\n\n\tel.style.visibility = \"hidden\";\n\tel.style.position = \"absolute\";\n\n\tdocument.body.appendChild(el);\n\tlet result = fn(el);\n\tel.parentNode!.removeChild(el);\n\n\t// Restore the styles unconditionally: transition functions call this with\n\t// a newly created element that isn't attached yet (oldParent is null), and\n\t// leaving the measuring styles on it would render it invisible\n\tel.style.visibility = oldVisibility;\n\tel.style.position = oldPosition;\n\n\tif (oldParent !== null) {\n\t\toldParent.insertBefore(el, oldBefore);\n\t}\n\n\treturn result;\n}\n","import { type Animation } from \"@torpor/view\";\nimport measure from \"./measure\";\n\nexport default function grow(\n\tel: HTMLElement,\n\toptions?: number | KeyframeAnimationOptions,\n): Animation {\n\tconst height = measure(el, (el) => el.clientHeight);\n\tconst keyframes = [\n\t\t{\n\t\t\theight: \"0px\",\n\t\t\toverflow: \"hidden\",\n\t\t\tpaddingTop: \"0px\",\n\t\t\tpaddingBottom: \"0px\",\n\t\t\tmarginTop: \"0px\",\n\t\t\tmarginBottom: \"0px\",\n\t\t},\n\t\t{\n\t\t\theight: height + \"px\",\n\t\t},\n\t];\n\treturn { keyframes, options };\n}\n","import { type Animation } from \"@torpor/view\";\nimport measure from \"./measure\";\n\ninterface Options extends KeyframeAnimationOptions {\n\tside: \"left\" | \"right\" | \"top\" | \"bottom\";\n}\n\nexport default function slide(el: HTMLElement, options?: Options): Animation {\n\tel.style.position = \"fixed\";\n\tswitch (options?.side ?? \"left\") {\n\t\tcase \"left\": {\n\t\t\tel.style.left = \"0px\";\n\t\t\tconst width = measure(el, (el) => el.offsetWidth);\n\t\t\tconst keyframes = [\n\t\t\t\t{ transform: `translateX(-${width}px)` },\n\t\t\t\t{ transform: \"translateX(0px)\" },\n\t\t\t];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t\tcase \"top\": {\n\t\t\tel.style.top = \"0px\";\n\t\t\tconst height = measure(el, (el) => el.offsetHeight);\n\t\t\tconst keyframes = [\n\t\t\t\t{ transform: `translateY(-${height}px)` },\n\t\t\t\t{ transform: \"translateY(0px)\" },\n\t\t\t];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t\tcase \"right\": {\n\t\t\tel.style.right = \"0px\";\n\t\t\tconst width = measure(el, (el) => el.offsetWidth);\n\t\t\tconst keyframes = [{ transform: `translateX(${width}px)` }, { transform: \"translateX(0px)\" }];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t\tcase \"bottom\": {\n\t\t\tel.style.bottom = \"0px\";\n\t\t\tconst height = measure(el, (el) => el.offsetHeight);\n\t\t\tconst keyframes = [\n\t\t\t\t{ transform: `translateY(${height}px)` },\n\t\t\t\t{ transform: \"translateY(0px)\" },\n\t\t\t];\n\t\t\treturn { keyframes, options };\n\t\t}\n\t}\n}\n"],"mappings":";AAEA,SAAwB,KACvB,KACA,SACY;CASZ,OAAO;EAAE,WAAA,CAPR,EACC,SAAS,EACV,GACA,EACC,SAAS,EACV,CAEgB;EAAG;CAAQ;AAC7B;;;;;;;;ACVA,SAAwB,QAAQ,IAAiB,IAA0C;CAE1F,IAAI,gBAAgB,GAAG,MAAM;CAC7B,IAAI,cAAc,GAAG,MAAM;CAE3B,IAAI,YAAY,GAAG;CACnB,IAAI,YAAY,GAAG;CAEnB,GAAG,MAAM,aAAa;CACtB,GAAG,MAAM,WAAW;CAEpB,SAAS,KAAK,YAAY,EAAE;CAC5B,IAAI,SAAS,GAAG,EAAE;CAClB,GAAG,WAAY,YAAY,EAAE;CAK7B,GAAG,MAAM,aAAa;CACtB,GAAG,MAAM,WAAW;CAEpB,IAAI,cAAc,MACjB,UAAU,aAAa,IAAI,SAAS;CAGrC,OAAO;AACR;;;AC5BA,SAAwB,KACvB,IACA,SACY;CAeZ,OAAO;EAAE,WAAA,CAZR;GACC,QAAQ;GACR,UAAU;GACV,YAAY;GACZ,eAAe;GACf,WAAW;GACX,cAAc;EACf,GACA,EACC,QAXa,QAAQ,KAAK,OAAO,GAAG,YAWvB,IAAI,KAClB,CAEgB;EAAG;CAAQ;AAC7B;;;ACfA,SAAwB,MAAM,IAAiB,SAA8B;CAC5E,GAAG,MAAM,WAAW;CACpB,QAAQ,SAAS,QAAQ,QAAzB;EACC,KAAK;GACJ,GAAG,MAAM,OAAO;GAMhB,OAAO;IAAE,WAAA,CAHR,EAAE,WAAW,eAFA,QAAQ,KAAK,OAAO,GAAG,WAEJ,EAAE,KAAK,GACvC,EAAE,WAAW,kBAAkB,CAEf;IAAG;GAAQ;EAE7B,KAAK;GACJ,GAAG,MAAM,MAAM;GAMf,OAAO;IAAE,WAAA,CAHR,EAAE,WAAW,eAFC,QAAQ,KAAK,OAAO,GAAG,YAEJ,EAAE,KAAK,GACxC,EAAE,WAAW,kBAAkB,CAEf;IAAG;GAAQ;EAE7B,KAAK;GACJ,GAAG,MAAM,QAAQ;GAGjB,OAAO;IAAE,WAAA,CADU,EAAE,WAAW,cADlB,QAAQ,KAAK,OAAO,GAAG,WACa,EAAE,KAAK,GAAG,EAAE,WAAW,kBAAkB,CAC1E;IAAG;GAAQ;EAE7B,KAAK;GACJ,GAAG,MAAM,SAAS;GAMlB,OAAO;IAAE,WAAA,CAHR,EAAE,WAAW,cAFC,QAAQ,KAAK,OAAO,GAAG,YAEL,EAAE,KAAK,GACvC,EAAE,WAAW,kBAAkB,CAEf;IAAG;GAAQ;CAE9B;AACD"}
@@ -0,0 +1,63 @@
1
+ import { beginDrag, endDrag, writeDragType } from "../utils/dragState";
2
+
3
+ interface DraggableOptions {
4
+ /** High-level kind for drop targets to filter on */
5
+ kind?: string;
6
+ /** Payload handed to the drop target that receives this drag */
7
+ data?: any;
8
+ /**
9
+ * Called when a drag starts; returning false cancels the drag entirely
10
+ * (useful for drags-in-progress controls, readonly flags etc)
11
+ */
12
+ onstart?: (e: DragEvent) => boolean | void;
13
+ /** Called when the drag finishes, whether it was dropped or cancelled */
14
+ onend?: (e: DragEvent) => void;
15
+ }
16
+
17
+ /**
18
+ * Makes an element draggable via the native HTML5 drag & drop API.
19
+ *
20
+ * ```
21
+ * <li onmount={(el) => draggable(el, { kind: "list-item", data: item })}>
22
+ * ```
23
+ *
24
+ * Pairs with dropTarget, which receives `{ kind, data }` for accepted
25
+ * drops. The tracked drag is always cleaned up on dragend, so handlers
26
+ * don't leak between drags.
27
+ */
28
+ export default function draggable(node: HTMLElement, options: DraggableOptions): () => void {
29
+ let started = false;
30
+
31
+ function handleStart(e: DragEvent) {
32
+ if (options.onstart?.(e) === false) {
33
+ e.preventDefault();
34
+ return;
35
+ }
36
+ const info = beginDrag(options.kind ?? "", options.data);
37
+ writeDragType(e, info.id);
38
+ if (e.dataTransfer) {
39
+ e.dataTransfer.effectAllowed = "move";
40
+ }
41
+ started = true;
42
+ }
43
+
44
+ function handleEnd(e: DragEvent) {
45
+ if (started) {
46
+ started = false;
47
+ endDrag();
48
+ options.onend?.(e);
49
+ }
50
+ }
51
+
52
+ node.addEventListener("dragstart", handleStart);
53
+ node.addEventListener("dragend", handleEnd);
54
+
55
+ return () => {
56
+ node.removeEventListener("dragstart", handleStart);
57
+ node.removeEventListener("dragend", handleEnd);
58
+ if (started) {
59
+ started = false;
60
+ endDrag();
61
+ }
62
+ };
63
+ }
@@ -0,0 +1,108 @@
1
+ import { type DragInfo, resolveDrag } from "../utils/dragState";
2
+
3
+ interface DropTargetOptions {
4
+ /** Filters incoming drags; only accepted kinds receive over/drop calls */
5
+ accepts?: (info: DragInfo) => boolean;
6
+ /** The cursor effect shown while hovering (default "move") */
7
+ effect?: "move" | "copy" | "link";
8
+ /** Called continuously while an accepted drag hovers the target */
9
+ onover?: (info: DragInfo, e: DragEvent) => void;
10
+ /** Called once when hovering starts */
11
+ onenter?: (info: DragInfo, e: DragEvent) => void;
12
+ /** Called once when hovering ends */
13
+ onleave?: () => void;
14
+ /** Called when an accepted drag is dropped; returning false rejects it */
15
+ ondrop?: (info: DragInfo, e: DragEvent) => boolean | void;
16
+ /** Class applied while an accepted drag hovers the target */
17
+ dragClass?: string;
18
+ }
19
+
20
+ /**
21
+ * Turns an element into a drop target for native HTML5 drags.
22
+ *
23
+ * ```
24
+ * <div
25
+ * class="panel"
26
+ * onmount={(el) =>
27
+ * dropTarget(el, {
28
+ * accepts: (info) => info.kind === "list-item",
29
+ * dragClass: "dropping",
30
+ * ondrop: (info) => addItem(info.data),
31
+ * })
32
+ * }
33
+ * />
34
+ * ```
35
+ *
36
+ * Handles the tedious parts of the platform API -- preventing the browser's
37
+ * default navigation, resolving the tracked drag, effect negotiation --
38
+ * so components only express what they accept and what happens on drop.
39
+ */
40
+ export default function dropTarget(node: HTMLElement, options: DropTargetOptions): () => void {
41
+ let hoverClassApplied = false;
42
+
43
+ function accepts(info: DragInfo | undefined): info is DragInfo {
44
+ return !!info && (!options.accepts || options.accepts(info));
45
+ }
46
+
47
+ function applyHover() {
48
+ if (!hoverClassApplied && options.dragClass) {
49
+ hoverClassApplied = true;
50
+ node.classList.add(options.dragClass);
51
+ }
52
+ }
53
+
54
+ function removeHover() {
55
+ if (hoverClassApplied) {
56
+ hoverClassApplied = false;
57
+ node.classList.remove(options.dragClass!);
58
+ }
59
+ }
60
+
61
+ function handleOver(e: DragEvent) {
62
+ const info = resolveDrag(e);
63
+ if (!accepts(info)) return;
64
+
65
+ e.preventDefault();
66
+ if (e.dataTransfer) {
67
+ e.dataTransfer.dropEffect = options.effect ?? "move";
68
+ }
69
+ applyHover();
70
+ options.onover?.(info!, e);
71
+ }
72
+
73
+ function handleEnter(e: DragEvent) {
74
+ const info = resolveDrag(e);
75
+ if (!accepts(info)) return;
76
+ applyHover();
77
+ options.onenter?.(info!, e);
78
+ }
79
+
80
+ function handleLeave(e: DragEvent) {
81
+ const related = e.relatedTarget as Node | null;
82
+ if (related && node.contains(related)) return;
83
+ removeHover();
84
+ options.onleave?.();
85
+ }
86
+
87
+ function handleDrop(e: DragEvent) {
88
+ e.preventDefault();
89
+ removeHover();
90
+
91
+ const info = resolveDrag(e);
92
+ if (!accepts(info)) return;
93
+ options.ondrop?.(info!, e);
94
+ }
95
+
96
+ node.addEventListener("dragover", handleOver);
97
+ node.addEventListener("dragenter", handleEnter);
98
+ node.addEventListener("dragleave", handleLeave);
99
+ node.addEventListener("drop", handleDrop);
100
+
101
+ return () => {
102
+ removeHover();
103
+ node.removeEventListener("dragover", handleOver);
104
+ node.removeEventListener("dragenter", handleEnter);
105
+ node.removeEventListener("dragleave", handleLeave);
106
+ node.removeEventListener("drop", handleDrop);
107
+ };
108
+ }
@@ -10,7 +10,7 @@ export default function hoverTrigger(node: HTMLElement, options: HoverTriggerOpt
10
10
  const hoverDelay = options.hoverDelay || 1000;
11
11
  const touchDelay = options.touchDelay || 1000;
12
12
 
13
- let interval: NodeJS.Timeout | undefined;
13
+ let interval: ReturnType<typeof setTimeout> | undefined;
14
14
 
15
15
  // Add click event handlers to the node
16
16
  node.addEventListener("mouseenter", handleMouseEnter);
@@ -0,0 +1,23 @@
1
+ import { $run } from "@torpor/view";
2
+
3
+ /**
4
+ * Runs a function once on subscription and re-runs it whenever any reactive
5
+ * state it read changes. The callback receives a `first` flag that is `true`
6
+ * on the initial run and `false` on every subsequent (change-driven) run, so
7
+ * callers can distinguish setup from "react to a change" without maintaining
8
+ * their own `firstChange` flag.
9
+ *
10
+ * This is a small helper over `$run` kept in @torpor/ui for its components;
11
+ * library authors can copy it if they need the same pattern.
12
+ *
13
+ * @param fn The function to run, receiving a `first` flag. May return a
14
+ * cleanup function.
15
+ */
16
+ export default function $handle(fn: (first: boolean) => void | (() => void)): void {
17
+ let firstRun = true;
18
+ $run(() => {
19
+ const first = firstRun;
20
+ firstRun = false;
21
+ return fn(first);
22
+ });
23
+ }
@@ -0,0 +1,47 @@
1
+ import { ListBox, ListBoxItem } from "../ListBox/index";
2
+
3
+ interface LoadedItemsProps {
4
+ /** The items to render */
5
+ items: any[];
6
+ /** The selected value(s), bound through to the internal ListBox */
7
+ value: any;
8
+ /** Whether multiple items can be selected */
9
+ multiple?: boolean;
10
+ /** Extracts the display text for an item (defaults to label ?? text ?? item) */
11
+ getItemLabel?: (item: any) => any;
12
+ /** Extracts the value for an item (defaults to value ?? id) */
13
+ getItemValue?: (item: any) => any;
14
+ }
15
+
16
+ function defaultLabel(item: any): string {
17
+ const label = item?.label ?? item?.text ?? item;
18
+ return typeof label === "string" ? label : String(label);
19
+ }
20
+
21
+ function defaultValue(item: any): any {
22
+ return item?.value ?? item?.id;
23
+ }
24
+
25
+ /**
26
+ * The internally rendered list of options for components that load their
27
+ * items from a network loader (ComboBox auto-complete etc). Used as the
28
+ * fallback content when a consumer doesn't slot their own ListBox.
29
+ */
30
+ export default function LoadedItems($props: LoadedItemsProps) {
31
+ const getLabel = $props.getItemLabel ?? defaultLabel;
32
+ const getValue = $props.getItemValue ?? defaultValue;
33
+
34
+ @render {
35
+ <ListBox type={$props.multiple ? "multiple" : "single"} value={$props.value}>
36
+ @for (let item of $props.items) {
37
+ @key = getValue(item)
38
+ <ListBoxItem value={getValue(item)}>
39
+ {getLabel(item)}
40
+ </ListBoxItem>
41
+ }
42
+ </ListBox>
43
+ @if ($props.items.length === 0) {
44
+ <span class="torp-loaded-items-empty">No results.</span>
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,99 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+ import getId from "./getId";
3
+ import { type PopoutContext } from "./PopoutTypes";
4
+
5
+ interface PopoutClickTriggerProps {
6
+ /** An ID for the root element */
7
+ id?: string;
8
+ /** Classes for the root element */
9
+ class?: ClassValue;
10
+ /** Styles for the root element */
11
+ style?: StyleValue;
12
+ /** The element to render: a button, or a div for right-click regions */
13
+ tag?: "button" | "div";
14
+ /** The event that activates the popout */
15
+ event?: "click" | "contextmenu";
16
+ /** The containing popout's context (the family-specific one, not PopoutContext) */
17
+ context: PopoutContext;
18
+ /**
19
+ * Called with the activating event before visibility is toggled, for
20
+ * triggers that track a position (right-click coordinates etc)
21
+ */
22
+ onactivate?: (node: HTMLElement, e: MouseEvent) => void;
23
+ }
24
+
25
+ /**
26
+ * The shared primitive behind PopoverTrigger, ContextualTrigger and
27
+ * ModalTrigger: it publishes the trigger id, renders the standard trigger
28
+ * attributes (aria-haspopup / aria-expanded / aria-controls), anchors the
29
+ * popout to itself and toggles visibility on the configured event.
30
+ *
31
+ * Hover activation deliberately lives in PopoverHover / ContextualHover,
32
+ * whose open/close semantics (intent delay, exit grace) differ enough from
33
+ * a press to warrant their own component.
34
+ */
35
+ export default function PopoutClickTrigger($props?: PopoutClickTriggerProps) {
36
+ let defaultId = getId();
37
+
38
+ const context = $props!.context;
39
+ const $state = context.state;
40
+
41
+ // Set the trigger ID so that it can be used with aria-labelledby
42
+ $state.triggerId = $props?.id ?? defaultId;
43
+
44
+ const tag = $props?.tag ?? "button";
45
+ const event = $props?.event ?? "click";
46
+
47
+ function handleEvent(node: HTMLElement, e: MouseEvent) {
48
+ if (event === "contextmenu") {
49
+ e.preventDefault();
50
+ }
51
+ $props?.onactivate?.(node, e);
52
+ $state.visible = !$state.visible;
53
+ }
54
+
55
+ function handleClick(e: MouseEvent) {
56
+ if (event !== "click") return;
57
+ handleEvent(e.currentTarget as HTMLElement, e);
58
+ }
59
+
60
+ function handleContextMenu(e: MouseEvent) {
61
+ if (event !== "contextmenu") return;
62
+ handleEvent(e.currentTarget as HTMLElement, e);
63
+ }
64
+
65
+ function handleMount(el: HTMLElement) {
66
+ context.anchorElement = el;
67
+ }
68
+
69
+ @render {
70
+ @if (tag === "button") {
71
+ <button
72
+ type="button"
73
+ id={$props?.id ?? defaultId}
74
+ class={["torp-popout-trigger", $props?.class]}
75
+ {$props?.style}
76
+ aria-haspopup={$state.contentRole ?? "true"}
77
+ aria-expanded={$state.visible ? "true" : "false"}
78
+ aria-controls={$state.contentId}
79
+ onclick={handleClick}
80
+ onmount={handleMount}
81
+ >
82
+ <slot />
83
+ </button>
84
+ } else {
85
+ <div
86
+ id={$props?.id ?? defaultId}
87
+ class={["torp-popout-trigger", $props?.class]}
88
+ {$props?.style}
89
+ aria-haspopup={$state.contentRole ?? "true"}
90
+ aria-expanded={$state.visible ? "true" : "false"}
91
+ aria-controls={$state.contentId}
92
+ oncontextmenu={handleContextMenu}
93
+ onmount={handleMount}
94
+ >
95
+ <slot />
96
+ </div>
97
+ }
98
+ }
99
+ }
@@ -3,30 +3,77 @@ export const PopoutContextName: unique symbol = Symbol.for("torp.Popout");
3
3
  // TODO: Use this type in more places
4
4
  export type HandleButtonPress = (type: "confirm" | "cancel" | undefined, value?: any) => void;
5
5
 
6
+ /**
7
+ * The shared focus API for popout-style contexts: content can focus its
8
+ * first/last item after being shown.
9
+ *
10
+ * HACK: Deferring the focus call is necessary because if we focus the first
11
+ * element e.g. in a Dialog's onMount, it will scroll the page to the focused
12
+ * element and mess up our careful positioning. We need to be able to manually
13
+ * set the order to
14
+ * 1. set visible (so we have an element with content)
15
+ * 2. set position (so the element is in the right place)
16
+ * 3. set focus (for accessibility)
17
+ * There may be a more elegant way to accomplish this!
18
+ */
19
+ export interface FocusApi {
20
+ focusFirstElement?: () => void;
21
+ focusLastElement?: () => void;
22
+ }
23
+
6
24
  /** The shared context for popout components */
7
- export interface PopoutContext {
25
+ export interface PopoutContext extends FocusApi {
8
26
  handleButton: HandleButtonPress;
9
27
  // HACK: We need to be able to let children (i.e. Dialogs) override the click outside functionality
10
28
  // There may be a more elegant way to accomplish this too
11
- handleClickOutside?: (e: MouseEvent) => void;
29
+ handleClickOutside?: (e: MouseEvent | KeyboardEvent) => void;
12
30
  state: PopoutState;
13
31
  //modal: boolean;
14
32
  anchorElement?: HTMLElement;
15
- // HACK: focusFirstElement is necessary because if we focus the first element e.g. in a Dialog's
16
- // onMount, it will scroll the page to the focused element and mess up our careful positioning
17
- // We need to be able to manually set the order to
18
- // 1. set visible (so we have an element with content)
19
- // 2. set position (so the element is in the right place)
20
- // 3. set focus (for accessibility)
21
- // There may be a more elegant way to accomplish this!
22
- focusFirstElement?: () => void;
23
- focusLastElement?: () => void;
33
+
34
+ /**
35
+ * Called from menu content when an arrow key should move to an adjacent item
36
+ * in a containing MenuBar, opening its menu. Only set by MenuBarItem.
37
+ */
38
+ navigateMenuBar?: (target: "previous" | "next") => void;
39
+
40
+ markElement?: (id: string) => void;
41
+ selectMarkedElement?: () => void;
42
+ searchText?: string;
43
+ searchItems?: (searchText: string) => { id: string; setFocused: () => void } | undefined;
24
44
  }
25
45
 
26
46
  export interface PopoutState {
27
47
  visible: boolean;
28
- //position: Point;
29
48
  contentId?: string;
49
+ triggerId?: string;
50
+ /**
51
+ * The role of this popout's content ("menu", "listbox", "tree", "grid" or
52
+ * "dialog"), set by the content component so that triggers can use it for
53
+ * their aria-haspopup attribute.
54
+ */
55
+ contentRole?: string;
56
+ /** Whether the popout is modal (e.g. it has an overlay) */
57
+ modal?: boolean;
58
+ /** The ID of the active descendant element, for aria-activedescendant */
59
+ activeDescendant?: string;
60
+ }
61
+
62
+ /**
63
+ * The state that a submenu trigger registers with its containing group
64
+ * (Menu, MenuBar, ToolBar or NavMenu). Passed to `registerItem`; the group
65
+ * assigns `index`, and the trigger assigns `text` from its label on mount.
66
+ */
67
+ export interface SubmenuItemState {
68
+ /** Assigned by the group on registration */
69
+ index?: number;
70
+ /** The item's label, set from its text content on mount; used for type-ahead */
71
+ text?: string;
72
+ setFocused: () => void;
73
+ /** Shows or hides the item's submenu */
74
+ setVisible?: (visible: boolean) => void;
75
+ /** Whether the item is disabled; disabled items are skipped by keyboard navigation */
76
+ disabled?: boolean;
30
77
  }
31
78
 
32
79
  export interface Point {