@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,157 @@
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 { defaultPalette, parseHex } from "../utils/colorUtils";
10
+ import createFormField from "../utils/formField";
11
+ import ColorPalette from "./ColorPalette.torp";
12
+
13
+ interface ColorPickerProps {
14
+ /** An ID for the root element */
15
+ id?: string;
16
+ /** Classes for the root element */
17
+ class?: ClassValue;
18
+ /** Styles for the root element */
19
+ style?: StyleValue;
20
+ /** The selected color as "#rrggbb"; undefined if nothing is selected */
21
+ value?: Bindable<string | undefined>;
22
+ /** The colors offered in the palette */
23
+ colors?: string[];
24
+ /**
25
+ * If set to true, a text field for arbitrary hex values ("#ff8800") is
26
+ * shown below the palette
27
+ */
28
+ showInput?: boolean;
29
+ /** If set to true, the user cannot interact with this picker */
30
+ disabled?: boolean;
31
+ /** An accessible name for the picker */
32
+ ariaLabel?: string;
33
+ /** The name of the component's form data field */
34
+ name?: string;
35
+ /** Raised when the color has changed or been cleared */
36
+ onchange?: (value: string | undefined) => void;
37
+ }
38
+
39
+ /**
40
+ * A color input: a ColorPalette with an optional hex text field, sharing a
41
+ * single bound value.
42
+ *
43
+ * ```
44
+ * <ColorPicker name="accent" showInput &value={$state.accent} />
45
+ * ```
46
+ */
47
+ export default function ColorPicker($props: ColorPickerProps | undefined) {
48
+ let hexInput: HTMLInputElement;
49
+
50
+ // Wire up the enclosing Form and Field, if any
51
+ const form = createFormField(
52
+ $props?.name,
53
+ $context[FormContextName] as FormContext | undefined,
54
+ $context[FieldContextName] as FieldContext | undefined,
55
+ );
56
+
57
+ function getDisabled(): boolean {
58
+ return $props?.disabled === true;
59
+ }
60
+
61
+ let $state = $watch({
62
+ value: undefined as string | undefined,
63
+
64
+ // Text while the hex input is being typed into; committed on blur or
65
+ // Enter, invalid text reverting like NumberInput
66
+ text: "",
67
+ editing: false,
68
+ });
69
+
70
+ $bind($state, $props, "value");
71
+
72
+ function handleSelect(value: string | undefined) {
73
+ $state.text = value ?? "";
74
+ form.handleInput();
75
+ $props?.onchange?.(value);
76
+ }
77
+
78
+ function commit() {
79
+ $state.editing = false;
80
+ const next = parseHex($state.text);
81
+ if ($state.text.trim() !== "" && !next) {
82
+ // Not a color: revert to the last committed value
83
+ $state.text = $state.value ?? "";
84
+ return;
85
+ }
86
+ if (next !== $state.value) {
87
+ $state.value = next;
88
+ form.handleInput();
89
+ $props?.onchange?.(next);
90
+ }
91
+ $state.text = $state.value ?? "";
92
+ }
93
+
94
+ function handleInput(e: Event) {
95
+ const el = e.currentTarget as HTMLInputElement;
96
+ $state.editing = true;
97
+ $state.text = el.value;
98
+ }
99
+
100
+ function handleKey(e: KeyboardEvent) {
101
+ if (e.key === "Enter") {
102
+ e.preventDefault();
103
+ commit();
104
+ }
105
+ }
106
+
107
+ function handleChange() {
108
+ commit();
109
+ }
110
+
111
+ // Keep the input's value in sync with the text; typing sets the
112
+ // property directly, so an attribute alone would not update it
113
+ function syncInput() {
114
+ if (hexInput && !$state.editing && hexInput.value !== $state.text) {
115
+ hexInput.value = $state.text;
116
+ }
117
+ }
118
+ $run(() => {
119
+ const text = $state.text;
120
+ const editing = $state.editing;
121
+ if (hexInput && !editing && hexInput.value !== text) {
122
+ hexInput.value = text;
123
+ }
124
+ });
125
+ $onmount(() => syncInput());
126
+
127
+ @render {
128
+ <div class={["torp-color-picker", $props?.class]} {$props?.style}>
129
+ <ColorPalette
130
+ class="torp-color-picker-palette"
131
+ colors={$props?.colors ?? defaultPalette}
132
+ value={$state.value}
133
+ disabled={getDisabled()}
134
+ ariaLabel={$props?.ariaLabel}
135
+ onchange={handleSelect}
136
+ />
137
+ @if ($props?.showInput) {
138
+ <input
139
+ &ref={hexInput}
140
+ type="text"
141
+ class="torp-color-picker-input"
142
+ spellcheck="false"
143
+ placeholder="#rrggbb"
144
+ aria-label={$props?.ariaLabel ? `${$props.ariaLabel} hex value` : "Hex value"}
145
+ value={$state.editing ? $state.text : $state.value ?? ""}
146
+ disabled={getDisabled()}
147
+ oninput={handleInput}
148
+ onchange={handleChange}
149
+ onblur={handleChange}
150
+ onkeydown={handleKey}
151
+ />
152
+ }
153
+ </div>
154
+
155
+ <FormValues name={form.name} value={$state.value} />
156
+ }
157
+ }
@@ -0,0 +1,85 @@
1
+ import { type SlotRender } from "@torpor/view";
2
+
3
+
4
+ interface ColorPaletteProps {
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 selected color as "#rrggbb"; undefined if nothing is selected */
12
+ value?: Bindable<string | undefined>;
13
+ /** The colors to offer (default: a built-in gray + hue palette) */
14
+ colors?: string[];
15
+ /** If set to true, the user cannot interact with this palette */
16
+ disabled?: boolean;
17
+ /** An accessible name for the palette */
18
+ ariaLabel?: string;
19
+ /** The name of the component's form data field */
20
+ name?: string;
21
+ /** Raised when a color has been selected or deselected */
22
+ onchange?: (value: string | undefined) => void;
23
+ }
24
+
25
+ /**
26
+ * A grid of color swatches that behaves like a radio group: one swatch can
27
+ * be selected, clicking it again deselects, and the arrow keys move through
28
+ * the swatches selecting as they go.
29
+ *
30
+ * Use ColorPicker instead when arbitrary hex values should be enterable
31
+ * alongside the palette.
32
+ */
33
+ declare function ColorPalette(
34
+ $parent: ParentNode,
35
+ $anchor: Node | null,
36
+ $props: ColorPaletteProps | undefined,
37
+ $context?: Record<PropertyKey, any>,
38
+ $slots?: Record<string, SlotRender>,
39
+ ): void;
40
+
41
+
42
+
43
+ interface ColorPickerProps {
44
+ /** An ID for the root element */
45
+ id?: string;
46
+ /** Classes for the root element */
47
+ class?: ClassValue;
48
+ /** Styles for the root element */
49
+ style?: StyleValue;
50
+ /** The selected color as "#rrggbb"; undefined if nothing is selected */
51
+ value?: Bindable<string | undefined>;
52
+ /** The colors offered in the palette */
53
+ colors?: string[];
54
+ /**
55
+ * If set to true, a text field for arbitrary hex values ("#ff8800") is
56
+ * shown below the palette
57
+ */
58
+ showInput?: boolean;
59
+ /** If set to true, the user cannot interact with this picker */
60
+ disabled?: boolean;
61
+ /** An accessible name for the picker */
62
+ ariaLabel?: string;
63
+ /** The name of the component's form data field */
64
+ name?: string;
65
+ /** Raised when the color has changed or been cleared */
66
+ onchange?: (value: string | undefined) => void;
67
+ }
68
+
69
+ /**
70
+ * A color input: a ColorPalette with an optional hex text field, sharing a
71
+ * single bound value.
72
+ *
73
+ * ```
74
+ * <ColorPicker name="accent" showInput &value={$state.accent} />
75
+ * ```
76
+ */
77
+ declare function ColorPicker(
78
+ $parent: ParentNode,
79
+ $anchor: Node | null,
80
+ $props: ColorPickerProps | undefined,
81
+ $context?: Record<PropertyKey, any>,
82
+ $slots?: Record<string, SlotRender>,
83
+ ): void;
84
+
85
+ export { ColorPalette, ColorPicker };
@@ -0,0 +1,3 @@
1
+ import ColorPalette from "./ColorPalette.torp";
2
+ import ColorPicker from "./ColorPicker.torp";
3
+ export { ColorPalette, ColorPicker };
@@ -0,0 +1,205 @@
1
+ import type { Bindable, ClassValue, StyleValue } from "@torpor/view";
2
+ import $handle from "../utils/$handle";
3
+ import {
4
+ type FieldContext,
5
+ FieldContextName,
6
+ type FormContext,
7
+ FormContextName,
8
+ } from "../Form/FormTypes";
9
+ import { type LoadResult, type Loader, createItemLoader } from "../utils/loader";
10
+ import { type PopoutContext, PopoutContextName } from "../utils/PopoutTypes";
11
+ import createFormField from "../utils/formField";
12
+ import { type ComboBoxContext, ComboBoxContextName, type ComboBoxState } from "./ComboBoxTypes";
13
+ import FormValues from "../Form/FormValues.torp";
14
+
15
+ interface ComboBoxProps {
16
+ /** An ID for the root element */
17
+ id?: string;
18
+ /** Classes for the root element */
19
+ class?: ClassValue;
20
+ /** Styles for the root element */
21
+ style?: StyleValue;
22
+ /** The name of the input's form data field */
23
+ name?: string;
24
+ /** The data value selected by the user, or an array of values if multiple is set */
25
+ value: Bindable<any>;
26
+ /** Whether multiple values can be selected at the same time */
27
+ multiple?: boolean;
28
+ /**
29
+ * Reads options from the network (or anywhere async) as the user types,
30
+ * receiving `{ searchText }`. When set and no content is slotted in, the
31
+ * options are rendered automatically.
32
+ */
33
+ load?: Loader;
34
+ /** Called after each successful load with the normalized result */
35
+ onload?: (result: LoadResult) => void;
36
+ /** Extracts the display text for a loaded item (defaults to `label ?? text ?? item`) */
37
+ getItemLabel?: (item: any) => any;
38
+ /** Extracts the value for a loaded item (defaults to `value ?? id`) */
39
+ getItemValue?: (item: any) => any;
40
+ /** Text to display when the input value is empty */
41
+ placeholder?: string;
42
+ /** Whether the input's value is required */
43
+ required?: boolean;
44
+ /** An ARIA label for describing the input to screen readers when there is no associated label element */
45
+ ariaLabel?: string;
46
+ /** Whether the popout is visible; only bind this to control it from outside */
47
+ visible?: Bindable<boolean | undefined>;
48
+ /** Raised when the value has changed */
49
+ onchange?: (value: any) => void;
50
+ /** Raised when the popout has opened */
51
+ onopen?: () => void;
52
+ /** Raised when the popout has closed */
53
+ onclose?: (result: any) => void;
54
+ }
55
+
56
+ /**
57
+ * An input box for selecting a value from a popout ListBox or Dialog.
58
+ *
59
+ * See [the WAI ARIA guidelines for ComboBoxes](https://www.w3.org/WAI/ARIA/apg/patterns/combobox/).
60
+ *
61
+ * The structure of a ComboBox is:
62
+ *
63
+ * ```
64
+ * <ComboBox>
65
+ * <ComboBoxInput />
66
+ * <ComboBoxTrigger /> (optional)
67
+ * <ComboBoxContent />
68
+ * </ComboBox>
69
+ * ```
70
+ */
71
+ export default function ComboBox($props: ComboBoxProps | undefined) {
72
+ // Wire up the enclosing Form and Field, if any
73
+ const form = createFormField(
74
+ $props?.name,
75
+ $context[FormContextName] as FormContext | undefined,
76
+ $context[FieldContextName] as FieldContext | undefined,
77
+ );
78
+ let $state: ComboBoxState = $watch({
79
+ visible: false,
80
+ value: $props?.value,
81
+ contentId: undefined,
82
+ triggerId: undefined,
83
+ contentRole: undefined,
84
+ activeDescendant: undefined,
85
+ searchText: undefined,
86
+ });
87
+
88
+ $bind($state, $props, "visible", "value");
89
+
90
+ if ($props?.load !== undefined && typeof $props.load !== "function") {
91
+ throw new Error("ComboBox: `load` must be a function");
92
+ }
93
+ const hasLoader = typeof $props?.load === "function";
94
+
95
+ // Load options from the network as the search text changes
96
+ const $load = hasLoader
97
+ ? createItemLoader({
98
+ load: $props!.load!,
99
+ getRequest: () => ({ searchText: $state.searchText }),
100
+ onload: (r) => $props?.onload?.(r),
101
+ })
102
+ : undefined;
103
+
104
+ let result: any;
105
+
106
+ // Set the context to pass down to items
107
+ let context: ComboBoxContext = {
108
+ handleButton,
109
+ handleClickOutside,
110
+ get placeholder() {
111
+ return $props?.placeholder;
112
+ },
113
+ get required() {
114
+ return $props?.required;
115
+ },
116
+ get ariaLabel() {
117
+ return $props?.ariaLabel;
118
+ },
119
+ get name() {
120
+ return $props?.name;
121
+ },
122
+ get multiple() {
123
+ return $props?.multiple === true;
124
+ },
125
+ inField: () => form.inField,
126
+ valid: () => form.valid,
127
+ messageId: () => form.messageId,
128
+ handleBlur: () => form.handleBlur(),
129
+ state: $state,
130
+ getLoadedItems: $load ? () => $load.items : undefined,
131
+ getItemLabel: $props?.getItemLabel,
132
+ getItemValue: $props?.getItemValue,
133
+ };
134
+ $context[ComboBoxContextName] = context;
135
+
136
+ // Set the context to pass down to items
137
+ let popoutContext: PopoutContext = context;
138
+ $context[PopoutContextName] = popoutContext;
139
+
140
+ // Dispatch the change event when the value changes
141
+ $handle((first) => {
142
+ const value = $state.value;
143
+ if (!first) {
144
+ form.handleInput();
145
+ $props?.onchange?.(value);
146
+ }
147
+ });
148
+
149
+ // Dispatch the open/close events when the popout is opened or closed
150
+ $handle((first) => {
151
+ const visible = $state.visible;
152
+ if (first) return;
153
+ if (visible) {
154
+ $props?.onopen?.();
155
+ } else {
156
+ $props?.onclose?.(result);
157
+ }
158
+ });
159
+
160
+ function handleButton(type: "confirm" | "cancel" | undefined, value?: any) {
161
+ // Get the button's result
162
+ switch (type) {
163
+ case "confirm": {
164
+ result = value ?? true;
165
+ break;
166
+ }
167
+ case "cancel": {
168
+ result = value ?? false;
169
+ break;
170
+ }
171
+ default: {
172
+ result = value;
173
+ break;
174
+ }
175
+ }
176
+
177
+ // Update the value
178
+ if (type !== "cancel") {
179
+ $state.value = result;
180
+ }
181
+
182
+ // Hide the popout and focus input
183
+ if (type === "confirm") {
184
+ $state.visible = false;
185
+ if (context.focusInput) {
186
+ context.focusInput();
187
+ }
188
+ } else if (type === "cancel") {
189
+ $state.visible = false;
190
+ }
191
+ }
192
+
193
+ function handleClickOutside(e: MouseEvent | KeyboardEvent) {
194
+ e.preventDefault();
195
+ $state.visible = false;
196
+ }
197
+
198
+ @render {
199
+ <div {$props?.id} class={["torp-combo-box", $props?.class]} {$props?.style}>
200
+ <slot />
201
+ </div>
202
+
203
+ <FormValues name={form.name} value={$props?.value} />
204
+ }
205
+ }
@@ -0,0 +1,120 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+ import { addDocumentEvent, removeDocumentEvent } from "../utils/documentEvents";
3
+ import LoadedItems from "../utils/LoadedItems.torp";
4
+ import { type ComboBoxContext, ComboBoxContextName } from "./ComboBoxTypes";
5
+
6
+ interface ComboBoxContentProps {
7
+ /** An ID for the root element */
8
+ id?: string;
9
+ /** Classes for the root element */
10
+ class?: ClassValue;
11
+ /** Styles for the root element */
12
+ style?: StyleValue;
13
+ }
14
+
15
+ /**
16
+ * The content that is displayed for a ComboBox when it is open, displayed
17
+ * alongside an element.
18
+ */
19
+ export default function ComboBoxContent($props: ComboBoxContentProps | undefined) {
20
+ let div: HTMLDivElement;
21
+ let shown = false;
22
+ let closeOnClick = false;
23
+
24
+ // Get stuff out of the ComboBoxContext
25
+ const context = $context[ComboBoxContextName] as ComboBoxContext;
26
+ if (!context) {
27
+ throw new Error("ComboBoxContent must be contained within a ComboBox");
28
+ }
29
+ let $state = context.state;
30
+
31
+ $run(() => {
32
+ if ($state.visible) {
33
+ show();
34
+ } else {
35
+ hide();
36
+ }
37
+ });
38
+
39
+ function show() {
40
+ shown = true;
41
+
42
+ // HACK: Because this ComboBox could be shown with a click, we need to wait for another mousedown
43
+ // before we close on click. Otherwise the click immediately bubbles to the document
44
+ closeOnClick = false;
45
+ addDocumentEvent("mousedown", handleDocumentMouseDown);
46
+ addDocumentEvent("click", handleDocumentClick);
47
+ addDocumentEvent("keydown", handleDocumentKeyDown);
48
+ }
49
+
50
+ function hide() {
51
+ if (!shown) return;
52
+
53
+ removeDocumentEvent("mousedown", handleDocumentMouseDown);
54
+ removeDocumentEvent("click", handleDocumentClick);
55
+ removeDocumentEvent("keydown", handleDocumentKeyDown);
56
+ }
57
+
58
+ function handleDocumentMouseDown() {
59
+ closeOnClick = true;
60
+ }
61
+
62
+ function handleDocumentClick(e: MouseEvent) {
63
+ // Don't close if the click is inside the content div OR inside the
64
+ // ComboBox root (which contains the input/trigger). A re-rendered
65
+ // (detached) target came from inside the content -- see DateRangePicker
66
+ const target = e.target as HTMLElement;
67
+ if (
68
+ closeOnClick &&
69
+ div &&
70
+ target.isConnected &&
71
+ !div.contains(target) &&
72
+ !div.parentElement?.contains(target)
73
+ ) {
74
+ e.preventDefault();
75
+ context.handleClickOutside!(e);
76
+ }
77
+ }
78
+
79
+ function handleDocumentKeyDown(e: KeyboardEvent) {
80
+ if (e.key === "Escape") {
81
+ e.preventDefault();
82
+ $state.visible = false;
83
+ }
84
+ }
85
+
86
+ // HACK: We need to keep the items in the document so that we can search through them
87
+ @render {
88
+ <div
89
+ {$props?.id}
90
+ class={["torp-combo-box-content", $props?.class]}
91
+ {$props?.style}
92
+ hidden={!$state.visible}
93
+ aria-hidden={$state.visible ? undefined : "true"}
94
+ &ref={div}
95
+ >
96
+ <slot>
97
+ @if (context.getLoadedItems) {
98
+ @// Options loaded from a network loader, rendered automatically
99
+ @try {
100
+ @await {
101
+ <LoadedItems
102
+ items={context.getLoadedItems!()}
103
+ value={$state.value}
104
+ multiple={context.multiple}
105
+ getItemLabel={context.getItemLabel}
106
+ getItemValue={context.getItemValue}
107
+ />
108
+ } with {
109
+ <span class="torp-combo-box-loading">Loading…</span>
110
+ }
111
+ } catch (err) {
112
+ <span class="torp-combo-box-error" role="alert">
113
+ {err instanceof Error ? err.message : String(err)}
114
+ </span>
115
+ }
116
+ }
117
+ </slot>
118
+ </div>
119
+ }
120
+ }