@torpor/ui 0.4.0 → 1.0.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 (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 +83 -0
  43. package/dist/Charts/ChartYAxis.torp +105 -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 +11 -11
  51. package/dist/Charts/YAxis.torp +8 -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 +112 -0
  60. package/dist/ComboBox/ComboBoxInput.torp +145 -0
  61. package/dist/ComboBox/ComboBoxTrigger.torp +49 -0
  62. package/dist/ComboBox/ComboBoxTypes.ts +39 -0
  63. package/dist/ComboBox/index.d.ts +152 -0
  64. package/dist/ComboBox/index.js +6 -0
  65. package/dist/CommandPalette/CommandPalette.torp +220 -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 +311 -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 +67 -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 +45 -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 +248 -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 +72 -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
@@ -2,20 +2,38 @@ export const ListBoxContextName: unique symbol = Symbol.for("torp.ListBox");
2
2
  export const ListBoxItemContextName: unique symbol = Symbol.for("torp.ListBoxItem");
3
3
 
4
4
  export interface ListBoxContext {
5
- /** Called from an ListBoxItem when it is added */
6
- registerItem: (state: ItemState, setFocused: () => void) => void;
7
- /** Called from an ListBoxItem when it is removed */
5
+ type: "single" | "multiple";
6
+ state: ListBoxState;
7
+ /** Called from a ListBoxItem when it is added */
8
+ registerItem: (state: ItemState) => void;
9
+ /** Called from a ListBoxItem when it is removed */
8
10
  removeItem: (index: number) => void;
9
- /** Called from an ListBoxItem when it is toggled */
11
+ /** Called from a ListBoxItem when it is toggled */
10
12
  toggleItem: (value: string) => void;
11
- /** Called from an ListBoxItem when it receives a keyboard event */
13
+ /** Called from a ListBoxItem when it receives a keyboard event */
12
14
  handleKey: (index: number, e: KeyboardEvent) => void;
15
+ /** Called from a ListBoxItem when it receives focus */
16
+ setActiveDescendant?: (id: string) => void;
17
+ /** Reads the items loaded from the network loader, when one is set */
18
+ getLoadedItems?: () => any[];
19
+ /** Extracts the display text for a loaded item */
20
+ getItemLabel?: (item: any) => any;
21
+ /** Extracts the value for a loaded item */
22
+ getItemValue?: (item: any) => any;
23
+ }
24
+
25
+ export interface ListBoxState {
26
+ value: any;
13
27
  }
14
28
 
15
29
  export interface ItemState {
30
+ id: string;
16
31
  index: number;
32
+ text: string;
17
33
  value: any;
18
34
  selected: boolean;
35
+ /** Used for styling when item has keyboard focus */
36
+ active: boolean;
19
37
  disabled: boolean;
20
38
  parentDisabled: boolean;
21
39
  /** Called in the ListBox when an item needs to be focused */
@@ -0,0 +1,41 @@
1
+ import ListBoxItem from "./ListBoxItem.torp";
2
+
3
+ interface LoadedListBoxItemsProps {
4
+ /** The loaded items */
5
+ items: any[];
6
+ /** Extracts the display text for an item (defaults to `label ?? text ?? item`) */
7
+ getItemLabel?: (item: any) => any;
8
+ /** Extracts the value for an item (defaults to `value ?? id`) */
9
+ getItemValue?: (item: any) => any;
10
+ }
11
+
12
+ function defaultLabel(item: any): string {
13
+ const label = item?.label ?? item?.text ?? item;
14
+ return typeof label === "string" ? label : String(label);
15
+ }
16
+
17
+ function defaultValue(item: any): any {
18
+ return item?.value ?? item?.id;
19
+ }
20
+
21
+ /**
22
+ * The internally rendered options for a ListBox that loads them from a
23
+ * network loader. Used as the slot fallback when no ListBoxItems are slotted
24
+ * in; not part of the public API.
25
+ */
26
+ export default function LoadedListBoxItems($props?: LoadedListBoxItemsProps) {
27
+ const getLabel = $props?.getItemLabel ?? defaultLabel;
28
+ const getValue = $props?.getItemValue ?? defaultValue;
29
+
30
+ @render {
31
+ @for (let item of $props!.items) {
32
+ @key = getValue(item)
33
+ <ListBoxItem value={getValue(item)}>
34
+ {getLabel(item)}
35
+ </ListBoxItem>
36
+ }
37
+ @if ($props!.items.length === 0) {
38
+ <span class="torp-list-box-empty">No results.</span>
39
+ }
40
+ }
41
+ }
@@ -5,19 +5,39 @@ interface ListBoxProps {
5
5
  /** An ID for the root element */
6
6
  id?: string;
7
7
  /** Classes for the root element */
8
- class?: ClassValue,
8
+ class?: ClassValue;
9
9
  /** Styles for the root element */
10
- style?: StyleValue,
10
+ style?: StyleValue;
11
11
  /** Whether a single ListBoxItem or multiple ListBoxItems can be selected at the same time */
12
- type?: "single" | "multiple",
12
+ type?: "single" | "multiple";
13
13
  /** The value of the selected ListBoxItem, or an array of values if the type is "multiple" */
14
- value?: any | any[],
14
+ value: Bindable<any | any[]>;
15
15
  /** If set to true, the user cannot interact with any items in the ListBox */
16
- disabled?: boolean,
16
+ disabled?: boolean;
17
17
  /** An ARIA label for describing the ListBox to screen readers */
18
- ariaLabel?: string | undefined,
18
+ ariaLabel?: string | undefined;
19
+ /** An ID of an element that labels the ListBox */
20
+ ariaLabelledBy?: string | undefined;
21
+ /** The orientation of the ListBox */
22
+ orientation?: "vertical" | "horizontal";
19
23
  /** Raised when the selected item(s) have changed */
20
- onchange?: (value: any | any[]) => void,
24
+ /** The name of the component's form data field */
25
+ name?: string;
26
+ /**
27
+ * Reads options from the network (or anywhere async), receiving
28
+ * `{ searchText }` whenever the bound `searchText` changes. When set and
29
+ * no ListBoxItems are slotted in, the options are rendered automatically
30
+ */
31
+ load?: Loader;
32
+ /** Called after each successful load with the normalized result */
33
+ onload?: (result: LoadResult) => void;
34
+ /** Extracts the display text for a loaded item (defaults to `label ?? text ?? item`) */
35
+ getItemLabel?: (item: any) => any;
36
+ /** Extracts the value for a loaded item (defaults to `value ?? id`) */
37
+ getItemValue?: (item: any) => any;
38
+ /** Filter text for a `load` function; two-way bindable */
39
+ searchText?: Bindable<string | undefined>;
40
+ onchange?: (value: any | any[]) => void;
21
41
  }
22
42
 
23
43
  /**
@@ -48,17 +68,19 @@ interface ListBoxItemProps {
48
68
  /** An ID for the root element */
49
69
  id?: string;
50
70
  /** Classes for the root element */
51
- class?: ClassValue,
71
+ class?: ClassValue;
52
72
  /** Styles for the root element */
53
- style?: StyleValue,
73
+ style?: StyleValue;
54
74
  /** The index of this item in the ListBox. Set this if you will be inserting, removing or sorting items. If you don't set this, it will be set automatically */
55
- index?: number,
75
+ index?: number;
76
+ /** The text for the item. If not set, this will come from it's text content */
77
+ text?: string;
56
78
  /** A value for the item. Set this if you need more control over which item(s) are selected. If you don't set this, the value will be set to the item's initial index */
57
- value?: string,
79
+ value?: string;
58
80
  /** If set to true, the user cannot interact with this ListBoxItem */
59
- disabled?: boolean,
60
- /** Raised when this item is opened or closed */
61
- ontoggle?: (open: boolean) => void,
81
+ disabled?: boolean;
82
+ /** Raised when this item's selected state has changed */
83
+ onchange?: (selected: boolean) => void;
62
84
  }
63
85
 
64
86
  /**
@@ -78,9 +100,11 @@ interface ListBoxSeparatorProps {
78
100
  /** An ID for the root element */
79
101
  id?: string;
80
102
  /** Classes for the root element */
81
- class?: ClassValue,
103
+ class?: ClassValue;
82
104
  /** Styles for the root element */
83
- style?: StyleValue,
105
+ style?: StyleValue;
106
+ /** The orientation of the separator */
107
+ orientation?: "vertical" | "horizontal";
84
108
  }
85
109
 
86
110
  /**
@@ -94,4 +118,19 @@ declare function ListBoxSeparator(
94
118
  $slots?: Record<string, SlotRender>,
95
119
  ): void;
96
120
 
97
- export { ListBox, ListBoxItem, ListBoxSeparator };
121
+
122
+
123
+ /**
124
+ * The internally rendered options for a ListBox that loads them from a
125
+ * network loader. Used as the slot fallback when no ListBoxItems are slotted
126
+ * in; not part of the public API.
127
+ */
128
+ declare function LoadedListBoxItems(
129
+ $parent: ParentNode,
130
+ $anchor: Node | null,
131
+ $props?: LoadedListBoxItemsProps,
132
+ $context?: Record<PropertyKey, any>,
133
+ $slots?: Record<string, SlotRender>,
134
+ ): void;
135
+
136
+ export { ListBox, ListBoxItem, ListBoxSeparator, LoadedListBoxItems };
@@ -1,14 +1,4 @@
1
- // src/ListBox/ListBox.torp
2
- import ListBox_default from "./ListBox.torp";
3
-
4
- // src/ListBox/ListBoxItem.torp
5
- import ListBoxItem_default from "./ListBoxItem.torp";
6
-
7
- // src/ListBox/ListBoxSeparator.torp
8
- import ListBoxSeparator_default from "./ListBoxSeparator.torp";
9
- export {
10
- ListBox_default as ListBox,
11
- ListBoxItem_default as ListBoxItem,
12
- ListBoxSeparator_default as ListBoxSeparator
13
- };
14
- //# sourceMappingURL=index.js.map
1
+ import ListBox from "./ListBox.torp";
2
+ import ListBoxItem from "./ListBoxItem.torp";
3
+ import ListBoxSeparator from "./ListBoxSeparator.torp";
4
+ export { ListBox, ListBoxItem, ListBoxSeparator };
@@ -0,0 +1,143 @@
1
+ import type { Bindable, ClassValue, StyleValue } from "@torpor/view";
2
+ import {
3
+ type FieldContext,
4
+ FieldContextName,
5
+ type FormContext,
6
+ FormContextName,
7
+ } from "../Form/FormTypes";
8
+ import FormValues from "../Form/FormValues.torp";
9
+ import { extractRaw, formatMask, parseMask } from "../utils/maskUtils";
10
+ import createFormField from "../utils/formField";
11
+
12
+ interface MaskedInputProps {
13
+ /** An ID for the root element */
14
+ id?: string;
15
+ /** Classes for the root element */
16
+ class?: ClassValue;
17
+ /** Styles for the root element */
18
+ style?: StyleValue;
19
+ /**
20
+ * The input mask: `9` accepts a digit, `L` a letter and `a` an
21
+ * alphanumeric character; any other character is a literal shown as-is.
22
+ * Use `\x` to escape a token character as a literal. e.g. "(999) 999-9999"
23
+ */
24
+ mask: string;
25
+ /** The raw entered characters, without mask literals */
26
+ value?: Bindable<string>;
27
+ /** Text displayed when no value has been entered (defaults to the mask) */
28
+ placeholder?: string;
29
+ /** If set to true, the user cannot interact with this input */
30
+ disabled?: boolean;
31
+ /** An accessible name for the input */
32
+ ariaLabel?: string;
33
+ /** The name of the component's form data field */
34
+ name?: string;
35
+ /** Raised when the value has changed */
36
+ onchange?: (value: string) => void;
37
+ }
38
+
39
+ /**
40
+ * An input that formats its contents as the user types -- phone numbers,
41
+ * credit cards, product codes -- displaying literals automatically while
42
+ * binding only the underlying characters.
43
+ *
44
+ * ```
45
+ * <MaskedInput mask="(999) 999-9999" &value={$state.phone} />
46
+ * <MaskedInput mask="LLL-9999" name="code" />
47
+ * ```
48
+ *
49
+ * Note that a complete value is not required: the bound value grows as the
50
+ * user types, so validate completeness with a schema when needed.
51
+ */
52
+ export default function MaskedInput($props: MaskedInputProps | undefined) {
53
+ let input: HTMLInputElement;
54
+
55
+ const tokens = parseMask($props?.mask ?? "");
56
+
57
+ // Wire up the enclosing Form and Field, if any
58
+ const form = createFormField(
59
+ $props?.name,
60
+ $context[FormContextName] as FormContext | undefined,
61
+ $context[FieldContextName] as FieldContext | undefined,
62
+ );
63
+
64
+ function getDisabled(): boolean {
65
+ return $props?.disabled === true;
66
+ }
67
+
68
+ // The bound value is the raw entered characters, so the state key
69
+ // matches the prop name for $bind
70
+ let $state = $watch({
71
+ value: "",
72
+ });
73
+
74
+ $bind($state, $props, "value");
75
+
76
+ function display(): string {
77
+ return formatMask(tokens, $state.value ?? "");
78
+ }
79
+
80
+ function getPlaceholder(): string | undefined {
81
+ return $props?.placeholder ?? $props?.mask;
82
+ }
83
+
84
+ // Keep the element's text matching the formatted raw value; typing sets
85
+ // the property directly, so an attribute alone would not update it
86
+ function syncInput() {
87
+ if (input && !getDisabled() && input.value !== display()) {
88
+ input.value = display();
89
+ }
90
+ }
91
+ $run(() => {
92
+ if (!input) return;
93
+ const raw = $state.value ?? "";
94
+ const next = formatMask(tokens, raw);
95
+ if (input.value !== next) {
96
+ input.value = next;
97
+ }
98
+ });
99
+ $onmount(() => syncInput());
100
+
101
+ function handleInput(e: Event) {
102
+ if (getDisabled()) return;
103
+ const el = e.currentTarget as HTMLInputElement;
104
+
105
+ const raw = extractRaw(tokens, el.value);
106
+ if (raw !== $state.value) {
107
+ $state.value = raw;
108
+ form.handleInput();
109
+ $props?.onchange?.(raw);
110
+ }
111
+
112
+ // Rewrite the element so rejected characters disappear immediately
113
+ el.value = formatMask(tokens, raw);
114
+ }
115
+
116
+ function handleBlur() {
117
+ form.handleBlur();
118
+ }
119
+
120
+ @render {
121
+ <input
122
+ &ref={input}
123
+ id={$props?.id}
124
+ class={["torp-masked-input", $props?.class]}
125
+ {$props?.style}
126
+ type="text"
127
+ spellcheck="false"
128
+ autocomplete="off"
129
+ value={display()}
130
+ placeholder={getPlaceholder()}
131
+ disabled={getDisabled()}
132
+ tabindex={getDisabled() ? -1 : 0}
133
+ aria-label={$props?.ariaLabel}
134
+ data-valid={form.valid ? "valid" : "invalid"}
135
+ aria-describedby={form.messageId}
136
+ aria-invalid={form.inField && !form.valid ? "true" : undefined}
137
+ oninput={handleInput}
138
+ onblur={handleBlur}
139
+ />
140
+
141
+ <FormValues name={form.name} value={$state.value || undefined} />
142
+ }
143
+ }
@@ -0,0 +1,52 @@
1
+ import { type SlotRender } from "@torpor/view";
2
+
3
+
4
+ interface MaskedInputProps {
5
+ /** An ID for the root element */
6
+ id?: string;
7
+ /** Classes for the root element */
8
+ class?: ClassValue;
9
+ /** Styles for the root element */
10
+ style?: StyleValue;
11
+ /**
12
+ * The input mask: `9` accepts a digit, `L` a letter and `a` an
13
+ * alphanumeric character; any other character is a literal shown as-is.
14
+ * Use `\x` to escape a token character as a literal. e.g. "(999) 999-9999"
15
+ */
16
+ mask: string;
17
+ /** The raw entered characters, without mask literals */
18
+ value?: Bindable<string>;
19
+ /** Text displayed when no value has been entered (defaults to the mask) */
20
+ placeholder?: string;
21
+ /** If set to true, the user cannot interact with this input */
22
+ disabled?: boolean;
23
+ /** An accessible name for the input */
24
+ ariaLabel?: string;
25
+ /** The name of the component's form data field */
26
+ name?: string;
27
+ /** Raised when the value has changed */
28
+ onchange?: (value: string) => void;
29
+ }
30
+
31
+ /**
32
+ * An input that formats its contents as the user types -- phone numbers,
33
+ * credit cards, product codes -- displaying literals automatically while
34
+ * binding only the underlying characters.
35
+ *
36
+ * ```
37
+ * <MaskedInput mask="(999) 999-9999" &value={$state.phone} />
38
+ * <MaskedInput mask="LLL-9999" name="code" />
39
+ * ```
40
+ *
41
+ * Note that a complete value is not required: the bound value grows as the
42
+ * user types, so validate completeness with a schema when needed.
43
+ */
44
+ declare function MaskedInput(
45
+ $parent: ParentNode,
46
+ $anchor: Node | null,
47
+ $props: MaskedInputProps | undefined,
48
+ $context?: Record<PropertyKey, any>,
49
+ $slots?: Record<string, SlotRender>,
50
+ ): void;
51
+
52
+ export { MaskedInput };
@@ -0,0 +1,2 @@
1
+ import MaskedInput from "./MaskedInput.torp";
2
+ export { MaskedInput };
@@ -1,22 +1,17 @@
1
1
  import type { ClassValue, StyleValue } from "@torpor/view";
2
- import { PopoutContextName, type PopoutContext } from "../utils/PopoutTypes";
3
- import {
4
- MenuContextName,
5
- type MenuContext,
6
- type ItemState,
7
- MenuPopoutContextName,
8
- type MenuPopoutContext
9
- } from "./MenuTypes";
2
+ import { type PopoutContext, PopoutContextName } from "../utils/PopoutTypes";
3
+ import { createFocusGroup } from "../utils/focusGroup";
4
+ import { type ItemState, type MenuContext, MenuContextName } from "./MenuTypes";
10
5
 
11
6
  interface MenuProps {
12
7
  /** An ID for the root element */
13
8
  id?: string;
14
9
  /** Classes for the root element */
15
- class?: ClassValue,
10
+ class?: ClassValue;
16
11
  /** Styles for the root element */
17
- style?: StyleValue,
12
+ style?: StyleValue;
18
13
  /** An ARIA label for describing the menu to screen readers */
19
- ariaLabel?: string,
14
+ ariaLabel?: string;
20
15
  }
21
16
 
22
17
  /**
@@ -39,92 +34,80 @@ interface MenuProps {
39
34
  */
40
35
  export default function Menu($props: MenuProps | undefined) {
41
36
  // A collection containing the state and some functions for each item
42
- let itemStates: ItemState[] = [];
43
- let focusIndex = -1;
37
+ const group = createFocusGroup<ItemState>();
38
+ const { itemStates } = group;
44
39
 
45
- // Get stuff out of the PopoverContext
46
- // HACK: share state in PopupState and extend in context/modal/popover
40
+ // The text typed for type-ahead, which is reset after a short pause between key presses
41
+ let searchText = "";
42
+ let searchTimer: ReturnType<typeof setTimeout> | undefined;
43
+
44
+ // Get stuff out of the PopoutContext
47
45
  const popoutContext = $context[PopoutContextName] as PopoutContext;
48
46
  if (!popoutContext) {
49
47
  throw new Error("Menu must be contained within a popout component");
50
48
  }
51
- const { setVisible, handleButton, state } = popoutContext;
49
+ const { handleButton, state } = popoutContext;
52
50
 
53
- // Check whether this is a menu in a popout
54
- const menuPopoutContext = $context[MenuPopoutContextName] as MenuPopoutContext;
55
- const inPopout = !!menuPopoutContext;
56
- const setPopoutVisible = menuPopoutContext?.setVisible;
51
+ const inPopout = state.contentRole === "menu";
52
+ state.contentRole = "menu";
57
53
 
58
54
  // Set the focusFirstElement method in the PopoverContext(s) so that it can be called after everything has been shown
59
- popoutContext.focusFirstElement = focusFirstElement;
60
- if (menuPopoutContext) {
61
- menuPopoutContext.focusFirstElement = focusFirstElement;
62
- menuPopoutContext.focusLastElement = focusLastElement;
63
- }
55
+ popoutContext.focusFirstElement = group.focusFirstItem;
56
+ popoutContext.focusLastElement = group.focusLastItem;
64
57
 
65
58
  // Set the context to pass down to items
66
59
  let context: MenuContext = {
67
- setVisible,
68
60
  handleButton,
69
61
  handleItemFocus,
70
62
  handleItemKey,
63
+ handlePopout,
71
64
  state,
72
- registerItem
65
+ registerItem,
73
66
  };
74
67
  $context[MenuContextName] = context;
75
68
 
76
- function focusFirstElement() {
77
- if (itemStates.length) {
78
- itemStates[0].setFocused();
79
- }
80
- }
81
-
82
- function focusLastElement() {
83
- if (itemStates.length > 0) {
84
- itemStates.at(-1)!.setFocused();
85
- }
86
- }
87
-
88
- function registerItem(setFocused: () => void) {
89
- // Add the item's state to the array and return its index
90
- const newItemState: ItemState = {
91
- setFocused
92
- };
93
- itemStates.push(newItemState);
94
- itemStates = itemStates;
95
- return { index: itemStates.length - 1 };
69
+ function registerItem(item: ItemState) {
70
+ return group.registerItem(item);
96
71
  }
97
72
 
98
73
  function handleItemFocus(index: number) {
99
- focusIndex = index;
74
+ group.handleItemFocus(index);
100
75
  }
101
76
 
102
77
  function handleItemKey(e: KeyboardEvent) {
103
78
  switch (e.key) {
104
- case "Esc":
105
79
  case "Escape": {
106
80
  e.preventDefault();
107
- setVisible(false);
81
+ state.visible = false;
108
82
  break;
109
83
  }
110
- case "Down":
111
84
  case "ArrowDown": {
112
85
  e.preventDefault();
113
86
  focusItem("next");
114
87
  break;
115
88
  }
116
- case "Up":
117
89
  case "ArrowUp": {
118
90
  e.preventDefault();
119
91
  focusItem("previous");
120
92
  break;
121
93
  }
122
- case "Left":
123
94
  case "ArrowLeft": {
124
- // TODO: This should be based on what side the menu shows on
125
- if (inPopout) {
95
+ if (popoutContext.navigateMenuBar) {
96
+ // In a menu under a menubar item: move to the previous item and open its menu
126
97
  e.preventDefault();
127
- setPopoutVisible(false);
98
+ popoutContext.navigateMenuBar("previous");
99
+ } else if (inPopout) {
100
+ // TODO: This should be based on what side the menu shows on
101
+ e.preventDefault();
102
+ state.visible = false;
103
+ }
104
+ break;
105
+ }
106
+ case "ArrowRight": {
107
+ if (popoutContext.navigateMenuBar) {
108
+ // In a menu under a menubar item: move to the next item and open its menu
109
+ e.preventDefault();
110
+ popoutContext.navigateMenuBar("next");
128
111
  }
129
112
  break;
130
113
  }
@@ -138,29 +121,60 @@ export default function Menu($props: MenuProps | undefined) {
138
121
  focusItem("end");
139
122
  break;
140
123
  }
141
- }
142
- }
143
-
144
- function focusItem(target: "start" | "previous" | "next" | "end") {
145
- switch (target) {
146
- case "start": {
147
- focusIndex = 0;
124
+ case "Tab": {
125
+ state.visible = false;
148
126
  break;
149
127
  }
150
- case "previous": {
151
- focusIndex = Math.max(0, focusIndex - 1);
128
+ default: {
129
+ // Type-ahead: typing a character focuses the next item whose label starts with it
130
+ if (e.key.length === 1 && e.key !== " ") {
131
+ e.preventDefault();
132
+ search(e.key);
133
+ }
152
134
  break;
153
135
  }
154
- case "next": {
155
- focusIndex = Math.min(itemStates.length - 1, focusIndex + 1);
156
- break;
136
+ }
137
+ }
138
+
139
+ function search(key: string) {
140
+ const character = key.toLocaleLowerCase();
141
+ if (searchTimer) {
142
+ clearTimeout(searchTimer);
143
+ // Typing the same character repeatedly cycles through the items that
144
+ // start with it, instead of searching for a repeated-character string
145
+ if (searchText.length !== 1 || character !== searchText) {
146
+ searchText += character;
157
147
  }
158
- case "end": {
159
- focusIndex = itemStates.length - 1;
148
+ } else {
149
+ searchText = character;
150
+ }
151
+ searchTimer = setTimeout(() => {
152
+ searchTimer = undefined;
153
+ searchText = "";
154
+ }, 1000);
155
+
156
+ // Focus the next item whose label starts with the search text, wrapping
157
+ // around to the start and skipping disabled items
158
+ for (let offset = 1; offset <= itemStates.length; offset++) {
159
+ const item = itemStates[(group.getFocusIndex() + offset) % itemStates.length];
160
+ if (!item.disabled && item.text?.toLocaleLowerCase().startsWith(searchText)) {
161
+ item.setFocused();
160
162
  break;
161
163
  }
162
164
  }
163
- itemStates[focusIndex]?.setFocused();
165
+ }
166
+
167
+ function focusItem(target: "start" | "previous" | "next" | "end") {
168
+ group.moveFocus(group.getFocusIndex(), target);
169
+ }
170
+
171
+ function handlePopout(index: number) {
172
+ // Hide all other submenus
173
+ for (let item of itemStates) {
174
+ if (item.index !== index) {
175
+ item.setVisible?.(false);
176
+ }
177
+ }
164
178
  }
165
179
 
166
180
  @render {
@@ -170,6 +184,7 @@ export default function Menu($props: MenuProps | undefined) {
170
184
  {$props?.style}
171
185
  tabindex="-1"
172
186
  role="menu"
187
+ aria-labelledby={state.triggerId}
173
188
  aria-label={$props?.ariaLabel}
174
189
  aria-orientation="vertical"
175
190
  >