@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
@@ -0,0 +1,161 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+ import getId from "../utils/getId";
3
+ import { type ComboBoxContext, ComboBoxContextName } from "./ComboBoxTypes";
4
+
5
+ interface ComboBoxInputProps {
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
+
13
+ // TODO: Get these from the parent
14
+ /** The name of the input's form data field */
15
+ name?: string;
16
+ /** The value displayed in the input */
17
+ value?: any;
18
+ /** The text to display in the input (e.g. the selected item's label), instead of the raw value */
19
+ text?: string;
20
+ /** Text to display when the input value is empty */
21
+ placeholder?: string;
22
+ /** Whether the input's value is required */
23
+ required?: boolean;
24
+
25
+ /** An ARIA label for describing the input to screen readers when there is no associated label element */
26
+ ariaLabel?: string;
27
+ /** Raised on change */
28
+ onchange?: (e: Event) => void;
29
+ /** Raised on input */
30
+ oninput?: (e: InputEvent) => void;
31
+ }
32
+
33
+ /**
34
+ * The input that causes a ComboBox to appear or disappear.
35
+ */
36
+ export default function ComboBoxInput($props: ComboBoxInputProps | undefined) {
37
+ let defaultId = getId();
38
+ let input: HTMLInputElement;
39
+
40
+ // Get stuff out of the ComboBoxContext
41
+ const context = $context[ComboBoxContextName] as ComboBoxContext;
42
+ if (!context) {
43
+ throw new Error("ComboBoxInput must be contained within a ComboBox");
44
+ }
45
+ let $state = context.state;
46
+ context.focusInput = focusInput;
47
+
48
+ // Set the trigger ID so that it can be used with aria-labelledby
49
+ $state.triggerId = $props?.id ?? defaultId;
50
+
51
+ function focusInput() {
52
+ input.focus();
53
+ }
54
+
55
+ // The text shown in the input: the consumer-supplied label for the
56
+ // selected value if given, otherwise the raw value itself. One-way: what
57
+ // the user types is search text, not the value (that's updated on select)
58
+ function displayValue(): string {
59
+ if ($props?.text !== undefined) {
60
+ return $props.text;
61
+ }
62
+ const value = $state.value;
63
+ if (value === undefined || value === null || value === "") {
64
+ return "";
65
+ }
66
+ return Array.isArray(value) ? value.join(", ") : String(value);
67
+ }
68
+
69
+ function handleClick() {
70
+ $state.visible = true;
71
+ }
72
+
73
+ function handleInput(e: InputEvent) {
74
+ if (context.getLoadedItems) {
75
+ // Loaded from a network loader: refetch with the current text
76
+ $state.searchText = input.value;
77
+ $state.visible = true;
78
+ } else if (context.searchItems) {
79
+ context.searchText = input.value;
80
+ const found = context.searchItems(context.searchText);
81
+ if (found !== undefined) {
82
+ $state.visible = true;
83
+ $state.activeDescendant = found.id;
84
+ if (context.markElement) {
85
+ context.markElement(found.id);
86
+ }
87
+ }
88
+ }
89
+
90
+ if ($props?.oninput) {
91
+ $props.oninput(e);
92
+ }
93
+ }
94
+
95
+ function handleKey(e: KeyboardEvent) {
96
+ switch (e.key) {
97
+ case "ArrowDown": {
98
+ e.preventDefault();
99
+ $state.visible = true;
100
+ if (context.focusFirstElement) {
101
+ context.focusFirstElement();
102
+ }
103
+ break;
104
+ }
105
+ case "ArrowUp": {
106
+ e.preventDefault();
107
+ $state.visible = true;
108
+ if (context.focusLastElement) {
109
+ context.focusLastElement();
110
+ }
111
+ break;
112
+ }
113
+ case "Enter": {
114
+ if ($state.visible) {
115
+ e.preventDefault();
116
+ if (context.selectMarkedElement) {
117
+ context.selectMarkedElement();
118
+ }
119
+ $state.visible = false;
120
+ }
121
+ break;
122
+ }
123
+ case "Escape": {
124
+ if ($state.visible) {
125
+ e.preventDefault();
126
+ $state.visible = false;
127
+ }
128
+ break;
129
+ }
130
+ }
131
+ }
132
+
133
+ @render {
134
+ <input
135
+ role="combobox"
136
+ aria-autocomplete="list"
137
+ id={$props?.id ?? defaultId}
138
+ class={["torp-combo-box-input", $props?.class]}
139
+ {$props?.style}
140
+ name={$props?.name !== undefined ? $props.name : context.name}
141
+ value={displayValue()}
142
+ placeholder={$props?.placeholder !== undefined ? $props.placeholder : context.placeholder}
143
+ required={$props?.required !== undefined ? $props.required : context.required}
144
+ aria-readonly
145
+ aria-controls={$state.contentId}
146
+ aria-haspopup={$state.contentRole}
147
+ aria-activedescendant={$state.activeDescendant}
148
+ aria-expanded={$state.visible ? "true" : "false"}
149
+ aria-label={$props?.ariaLabel !== undefined ? $props.ariaLabel : context.ariaLabel}
150
+ data-valid={context.valid?.() ? "valid" : "invalid"}
151
+ aria-describedby={context.messageId?.()}
152
+ aria-invalid={context.inField?.() && !context.valid?.() ? "true" : undefined}
153
+ onblur={() => context.handleBlur?.()}
154
+ {$props?.onchange}
155
+ onclick={handleClick}
156
+ oninput={handleInput}
157
+ onkeydown={handleKey}
158
+ &ref={input}
159
+ />
160
+ }
161
+ }
@@ -0,0 +1,49 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+ import getId from "../utils/getId";
3
+ import { type ComboBoxContext, ComboBoxContextName } from "./ComboBoxTypes";
4
+
5
+ interface ComboBoxTriggerProps {
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
+ }
13
+
14
+ /**
15
+ * The button that causes a ComboBox to appear or disappear.
16
+ */
17
+ export default function ComboBoxTrigger($props: ComboBoxTriggerProps | undefined) {
18
+ let defaultId = getId();
19
+
20
+ // Get stuff out of the ComboBoxContext
21
+ const context = $context[ComboBoxContextName] as ComboBoxContext;
22
+ if (!context) {
23
+ throw new Error("ComboBoxTrigger must be contained within a ComboBox");
24
+ }
25
+ let $state = context.state;
26
+
27
+ // Set the trigger ID so that it can be used with aria-labelledby
28
+ $state.triggerId = $props?.id ?? defaultId;
29
+
30
+ function handleClick() {
31
+ $state.visible = !$state.visible;
32
+ }
33
+
34
+ @render {
35
+ <button
36
+ type="button"
37
+ id={$props?.id ?? defaultId}
38
+ class={["torp-combo-box-trigger", $props?.class]}
39
+ {$props?.style}
40
+ aria-haspopup={$state.contentRole}
41
+ aria-expanded={$state.visible ? "true" : "false"}
42
+ aria-controls={$state.contentId}
43
+ onclick={handleClick}
44
+ &ref={context.anchorElement}
45
+ >
46
+ <slot />
47
+ </button>
48
+ }
49
+ }
@@ -0,0 +1,39 @@
1
+ import { type LoadResult, type Loader } from "../utils/loader";
2
+ import { type PopoutContext, type PopoutState } from "../utils/PopoutTypes";
3
+
4
+ export const ComboBoxContextName: unique symbol = Symbol.for("torp.ComboBox");
5
+
6
+ /** The shared context for ComboBox components */
7
+ export interface ComboBoxContext extends PopoutContext {
8
+ placeholder?: string;
9
+ required?: boolean;
10
+ ariaLabel?: string;
11
+ name?: string;
12
+ multiple?: boolean;
13
+ state: ComboBoxState;
14
+ focusInput?: () => void;
15
+ /** Whether the component is contained within a Form Field */
16
+ inField?: () => boolean;
17
+ /** Whether the Field's value is valid, for data-valid / aria-invalid */
18
+ valid?: () => boolean;
19
+ /** The ID of the Field's Message component, for aria-describedby */
20
+ messageId?: () => string | undefined;
21
+ /** Called by the input when it loses focus, to run Field validation */
22
+ handleBlur?: () => void;
23
+ /** Returns the items loaded from the network loader, when one is set */
24
+ getLoadedItems?: () => any[];
25
+ /** Extracts the display text for a loaded item */
26
+ getItemLabel?: (item: any) => any;
27
+ /** Extracts the value for a loaded item */
28
+ getItemValue?: (item: any) => any;
29
+ }
30
+
31
+ export interface ComboBoxState extends PopoutState {
32
+ value: any;
33
+ name?: string;
34
+ activeDescendant?: string;
35
+ /** The current search text, kept up to date by the input when loading */
36
+ searchText?: string;
37
+ }
38
+
39
+ export type { LoadResult, Loader };
@@ -0,0 +1,154 @@
1
+ import { type SlotRender } from "@torpor/view";
2
+
3
+
4
+ interface ComboBoxProps {
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
+ /** The name of the input's form data field */
12
+ name?: string;
13
+ /** The data value selected by the user, or an array of values if multiple is set */
14
+ value: Bindable<any>;
15
+ /** Whether multiple values can be selected at the same time */
16
+ multiple?: boolean;
17
+ /**
18
+ * Reads options from the network (or anywhere async) as the user types,
19
+ * receiving `{ searchText }`. When set and no content is slotted in, the
20
+ * options are rendered automatically.
21
+ */
22
+ load?: Loader;
23
+ /** Called after each successful load with the normalized result */
24
+ onload?: (result: LoadResult) => void;
25
+ /** Extracts the display text for a loaded item (defaults to `label ?? text ?? item`) */
26
+ getItemLabel?: (item: any) => any;
27
+ /** Extracts the value for a loaded item (defaults to `value ?? id`) */
28
+ getItemValue?: (item: any) => any;
29
+ /** Text to display when the input value is empty */
30
+ placeholder?: string;
31
+ /** Whether the input's value is required */
32
+ required?: boolean;
33
+ /** An ARIA label for describing the input to screen readers when there is no associated label element */
34
+ ariaLabel?: string;
35
+ /** Whether the popout is visible; only bind this to control it from outside */
36
+ visible?: Bindable<boolean | undefined>;
37
+ /** Raised when the value has changed */
38
+ onchange?: (value: any) => void;
39
+ /** Raised when the popout has opened */
40
+ onopen?: () => void;
41
+ /** Raised when the popout has closed */
42
+ onclose?: (result: any) => void;
43
+ }
44
+
45
+ /**
46
+ * An input box for selecting a value from a popout ListBox or Dialog.
47
+ *
48
+ * See [the WAI ARIA guidelines for ComboBoxes](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).
49
+ *
50
+ * The structure of a ComboBox is:
51
+ *
52
+ * ```
53
+ * <ComboBox>
54
+ * <ComboBoxInput />
55
+ * <ComboBoxTrigger /> (optional)
56
+ * <ComboBoxContent />
57
+ * </ComboBox>
58
+ * ```
59
+ */
60
+ declare function ComboBox(
61
+ $parent: ParentNode,
62
+ $anchor: Node | null,
63
+ $props: ComboBoxProps | undefined,
64
+ $context?: Record<PropertyKey, any>,
65
+ $slots?: Record<string, SlotRender>,
66
+ ): void;
67
+
68
+
69
+
70
+ interface ComboBoxContentProps {
71
+ /** An ID for the root element */
72
+ id?: string;
73
+ /** Classes for the root element */
74
+ class?: ClassValue;
75
+ /** Styles for the root element */
76
+ style?: StyleValue;
77
+ }
78
+
79
+ /**
80
+ * The content that is displayed for a ComboBox when it is open, displayed
81
+ * alongside an element.
82
+ */
83
+ declare function ComboBoxContent(
84
+ $parent: ParentNode,
85
+ $anchor: Node | null,
86
+ $props: ComboBoxContentProps | undefined,
87
+ $context?: Record<PropertyKey, any>,
88
+ $slots?: Record<string, SlotRender>,
89
+ ): void;
90
+
91
+
92
+
93
+ interface ComboBoxInputProps {
94
+ /** An ID for the root element */
95
+ id?: string;
96
+ /** Classes for the root element */
97
+ class?: ClassValue;
98
+ /** Styles for the root element */
99
+ style?: StyleValue;
100
+
101
+ // TODO: Get these from the parent
102
+ /** The name of the input's form data field */
103
+ name?: string;
104
+ /** The value displayed in the input */
105
+ value?: any;
106
+ /** The text to display in the input (e.g. the selected item's label), instead of the raw value */
107
+ text?: string;
108
+ /** Text to display when the input value is empty */
109
+ placeholder?: string;
110
+ /** Whether the input's value is required */
111
+ required?: boolean;
112
+
113
+ /** An ARIA label for describing the input to screen readers when there is no associated label element */
114
+ ariaLabel?: string;
115
+ /** Raised on change */
116
+ onchange?: (e: Event) => void;
117
+ /** Raised on input */
118
+ oninput?: (e: InputEvent) => void;
119
+ }
120
+
121
+ /**
122
+ * The input that causes a ComboBox to appear or disappear.
123
+ */
124
+ declare function ComboBoxInput(
125
+ $parent: ParentNode,
126
+ $anchor: Node | null,
127
+ $props: ComboBoxInputProps | undefined,
128
+ $context?: Record<PropertyKey, any>,
129
+ $slots?: Record<string, SlotRender>,
130
+ ): void;
131
+
132
+
133
+
134
+ interface ComboBoxTriggerProps {
135
+ /** An ID for the root element */
136
+ id?: string;
137
+ /** Classes for the root element */
138
+ class?: ClassValue;
139
+ /** Styles for the root element */
140
+ style?: StyleValue;
141
+ }
142
+
143
+ /**
144
+ * The button that causes a ComboBox to appear or disappear.
145
+ */
146
+ declare function ComboBoxTrigger(
147
+ $parent: ParentNode,
148
+ $anchor: Node | null,
149
+ $props: ComboBoxTriggerProps | undefined,
150
+ $context?: Record<PropertyKey, any>,
151
+ $slots?: Record<string, SlotRender>,
152
+ ): void;
153
+
154
+ export { ComboBox, ComboBoxContent, ComboBoxInput, ComboBoxTrigger };
@@ -0,0 +1,6 @@
1
+ import { n as normalizeLoadResult, t as createItemLoader } from "../loader-DEeG5vFY.js";
2
+ import ComboBox from "./ComboBox.torp";
3
+ import ComboBoxContent from "./ComboBoxContent.torp";
4
+ import ComboBoxInput from "./ComboBoxInput.torp";
5
+ import ComboBoxTrigger from "./ComboBoxTrigger.torp";
6
+ export { ComboBox, ComboBoxContent, ComboBoxInput, ComboBoxTrigger, createItemLoader, normalizeLoadResult };
@@ -0,0 +1,223 @@
1
+ import type { Bindable, ClassValue, StyleValue } from "@torpor/view";
2
+ import Modal from "../Modal/Modal.torp";
3
+ import ModalContent from "../Modal/ModalContent.torp";
4
+ import ModalOverlay from "../Modal/ModalOverlay.torp";
5
+ import getId from "../utils/getId";
6
+ import type { Command } from "./CommandTypes";
7
+
8
+ interface CommandPaletteProps {
9
+ /** An ID for the root element */
10
+ id?: string;
11
+ /** Classes for the root element */
12
+ class?: ClassValue;
13
+ /** Styles for the root element */
14
+ style?: StyleValue;
15
+ /** Whether the palette is visible */
16
+ visible: Bindable<boolean | undefined>;
17
+ /** The commands that the user can choose from */
18
+ commands: Command[];
19
+ /** Text to display in the input when it is empty */
20
+ placeholder?: string;
21
+ /**
22
+ * A keyboard shortcut that toggles the palette, e.g. "mod+k", where "mod"
23
+ * means the Cmd key on Mac and the Ctrl key elsewhere
24
+ */
25
+ hotkey?: string;
26
+ /** An accessible name for the input */
27
+ ariaLabel?: string;
28
+ /** Text to display when no commands match the search */
29
+ emptyText?: string;
30
+ /** Raised when a command has been run */
31
+ onrun?: (command: Command) => void;
32
+ }
33
+
34
+ /**
35
+ * A modal input for searching and running commands, opened with a keyboard
36
+ * shortcut or programmatically.
37
+ *
38
+ * The structure of a CommandPalette is a Modal containing a search input and
39
+ * a filtered list of commands.
40
+ */
41
+ export default function CommandPalette($props: CommandPaletteProps | undefined) {
42
+ let defaultId = getId();
43
+ let input: HTMLInputElement;
44
+
45
+ function getDisabled(command: Command): boolean {
46
+ return command.disabled === true;
47
+ }
48
+
49
+ let $state = $watch({
50
+ visible: false,
51
+ search: "",
52
+ activeIndex: 0,
53
+ });
54
+
55
+ $bind($state, $props, "visible");
56
+
57
+ // Reset the active item whenever the search changes or the palette opens
58
+ let lastSearch = "";
59
+ let lastVisible = false;
60
+ $run(() => {
61
+ const search = $state.search;
62
+ const visible = $state.visible;
63
+ if (search !== lastSearch || (visible && !lastVisible)) {
64
+ $state.activeIndex = 0;
65
+ }
66
+ lastSearch = search;
67
+ lastVisible = visible;
68
+ if (!visible) {
69
+ $state.search = "";
70
+ if (input) {
71
+ input.value = "";
72
+ }
73
+ } else {
74
+ // Focus the input once the modal content has rendered
75
+ setTimeout(() => input?.focus());
76
+ }
77
+ });
78
+
79
+ // The commands that match the current search text
80
+ function filteredCommands(): Command[] {
81
+ const search = $state.search.trim().toLowerCase();
82
+ if (search === "") return $props?.commands ?? [];
83
+ return ($props?.commands ?? []).filter(
84
+ (command) =>
85
+ command.label.toLowerCase().includes(search) ||
86
+ (command.keywords ?? "").toLowerCase().includes(search),
87
+ );
88
+ }
89
+
90
+ function activeCommand(): Command | undefined {
91
+ return filteredCommands()[$state.activeIndex];
92
+ }
93
+
94
+ function optionId(index: number): string {
95
+ return `${$props?.id ?? defaultId}-option-${index}`;
96
+ }
97
+
98
+ function runCommand(command: Command | undefined) {
99
+ if (!command || getDisabled(command)) return;
100
+ $state.visible = false;
101
+ command.run?.();
102
+ $props?.onrun?.(command);
103
+ }
104
+
105
+ function handleInput(e: Event) {
106
+ $state.search = (e.currentTarget as HTMLInputElement).value;
107
+ }
108
+
109
+ function handleKey(e: KeyboardEvent) {
110
+ switch (e.key) {
111
+ case "ArrowDown": {
112
+ e.preventDefault();
113
+ const count = filteredCommands().length;
114
+ $state.activeIndex = Math.min(count - 1, $state.activeIndex + 1);
115
+ break;
116
+ }
117
+ case "ArrowUp": {
118
+ e.preventDefault();
119
+ $state.activeIndex = Math.max(0, $state.activeIndex - 1);
120
+ break;
121
+ }
122
+ case "Enter": {
123
+ e.preventDefault();
124
+ runCommand(activeCommand());
125
+ break;
126
+ }
127
+ case "Escape": {
128
+ e.preventDefault();
129
+ $state.visible = false;
130
+ break;
131
+ }
132
+ }
133
+ }
134
+
135
+ // Toggle the palette with a keyboard shortcut, e.g. mod+k
136
+ $onmount(() => {
137
+ if (!$props?.hotkey) return;
138
+ const [modifier, key] = parseHotkey($props.hotkey);
139
+ if (!key) return;
140
+ const handler = (e: KeyboardEvent) => {
141
+ const modOk =
142
+ modifier === "mod" ? e.metaKey || e.ctrlKey : modifier === "shift" ? e.shiftKey : true;
143
+ if (modOk && e.key.toLowerCase() === key.toLowerCase()) {
144
+ e.preventDefault();
145
+ $state.visible = !$state.visible;
146
+ }
147
+ };
148
+ document.addEventListener("keydown", handler);
149
+ return () => document.removeEventListener("keydown", handler);
150
+ });
151
+
152
+ function parseHotkey(hotkey: string): [string | undefined, string | undefined] {
153
+ const parts = hotkey.split("+");
154
+ if (parts.length === 2) {
155
+ return [parts[0].toLowerCase(), parts[1]];
156
+ }
157
+ return [undefined, hotkey];
158
+ }
159
+
160
+ @render {
161
+ <div {$props?.id} class={["torp-command-palette", $props?.class]} {$props?.style}>
162
+ <Modal {$state.visible}>
163
+ <ModalOverlay />
164
+ <ModalContent class="torp-command-palette-content">
165
+ <input
166
+ class="torp-command-palette-input"
167
+ type="text"
168
+ role="combobox"
169
+ aria-expanded="true"
170
+ aria-controls={`${$props?.id ?? defaultId}-list`}
171
+ aria-activedescendant={optionId($state.activeIndex)}
172
+ aria-autocomplete="list"
173
+ aria-label={$props?.ariaLabel}
174
+ placeholder={$props?.placeholder}
175
+ &ref={input}
176
+ oninput={handleInput}
177
+ onkeydown={handleKey}
178
+ />
179
+ <ul class="torp-command-palette-list" role="listbox" id={`${$props?.id ?? defaultId}-list`}>
180
+ @for (let [index, command] of filteredCommands().entries()) {
181
+ @key = command.value
182
+ <li
183
+ class="torp-command-palette-item"
184
+ role="option"
185
+ id={optionId(index)}
186
+ aria-selected={$state.activeIndex === index ? "true" : "false"}
187
+ aria-disabled={getDisabled(command) ? "true" : undefined}
188
+ data-state={$state.activeIndex === index ? "active" : "inactive"}
189
+ onclick={() => runCommand(command)}
190
+ >
191
+ <span class="torp-command-palette-label">{command.label}</span>
192
+ @if (command.shortcut) {
193
+ <span class="torp-command-palette-shortcut" aria-hidden="true">
194
+ {command.shortcut}
195
+ </span>
196
+ }
197
+ </li>
198
+ }
199
+ @if (filteredCommands().length === 0) {
200
+ <li class="torp-command-palette-empty">
201
+ {$props?.emptyText ?? "No results"}
202
+ </li>
203
+ }
204
+ </ul>
205
+ </ModalContent>
206
+ </Modal>
207
+ </div>
208
+ }
209
+
210
+ @style {
211
+ /* Headless: layout only, so the input sits above the list. All
212
+ appearance is up to the consuming theme */
213
+ .torp-command-palette-content {
214
+ display: flex;
215
+ flex-direction: column;
216
+ }
217
+ .torp-command-palette-list {
218
+ list-style: none;
219
+ margin: 0;
220
+ padding: 0;
221
+ }
222
+ }
223
+ }
@@ -0,0 +1,14 @@
1
+ export interface Command {
2
+ /** A value identifying the command */
3
+ value: any;
4
+ /** The display label for the command */
5
+ label: string;
6
+ /** Extra text that is matched when searching, but isn't displayed */
7
+ keywords?: string;
8
+ /** A keyboard shortcut hint to display, e.g. "⌘N" */
9
+ shortcut?: string;
10
+ /** If set to true, the command can't be run */
11
+ disabled?: boolean;
12
+ /** The function to call when the command is run */
13
+ run?: () => void;
14
+ }
@@ -0,0 +1,45 @@
1
+ import { type SlotRender } from "@torpor/view";
2
+
3
+
4
+ interface CommandPaletteProps {
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
+ /** Whether the palette is visible */
12
+ visible: Bindable<boolean | undefined>;
13
+ /** The commands that the user can choose from */
14
+ commands: Command[];
15
+ /** Text to display in the input when it is empty */
16
+ placeholder?: string;
17
+ /**
18
+ * A keyboard shortcut that toggles the palette, e.g. "mod+k", where "mod"
19
+ * means the Cmd key on Mac and the Ctrl key elsewhere
20
+ */
21
+ hotkey?: string;
22
+ /** An accessible name for the input */
23
+ ariaLabel?: string;
24
+ /** Text to display when no commands match the search */
25
+ emptyText?: string;
26
+ /** Raised when a command has been run */
27
+ onrun?: (command: Command) => void;
28
+ }
29
+
30
+ /**
31
+ * A modal input for searching and running commands, opened with a keyboard
32
+ * shortcut or programmatically.
33
+ *
34
+ * The structure of a CommandPalette is a Modal containing a search input and
35
+ * a filtered list of commands.
36
+ */
37
+ declare function CommandPalette(
38
+ $parent: ParentNode,
39
+ $anchor: Node | null,
40
+ $props: CommandPaletteProps | undefined,
41
+ $context?: Record<PropertyKey, any>,
42
+ $slots?: Record<string, SlotRender>,
43
+ ): void;
44
+
45
+ export { CommandPalette };
@@ -0,0 +1,2 @@
1
+ import CommandPalette from "./CommandPalette.torp";
2
+ export { CommandPalette };