@torpor/ui 0.3.7 → 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 (346) hide show
  1. package/README.md +83 -7
  2. package/dist/Accordion/Accordion.torp +43 -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 +6 -6
  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 +25 -4
  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 +70 -0
  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/{Chart → Charts}/GridLines.torp +7 -4
  46. package/dist/Charts/LineChart.torp +73 -0
  47. package/dist/{Chart → Charts}/PieChart.torp +14 -20
  48. package/dist/{Chart → Charts}/ScatterChart.torp +45 -38
  49. package/dist/{Chart → Charts}/SparkLine.torp +16 -19
  50. package/dist/{Chart → Charts}/XAxis.torp +18 -12
  51. package/dist/{Chart → Charts}/YAxis.torp +15 -9
  52. package/dist/Charts/index.d.ts +469 -0
  53. package/dist/Charts/index.js +17 -0
  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 +39 -52
  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 +5 -18
  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 +33 -30
  91. package/dist/Dialog/DialogBody.torp +5 -9
  92. package/dist/Dialog/DialogButton.torp +14 -11
  93. package/dist/Dialog/DialogFooter.torp +3 -7
  94. package/dist/Dialog/DialogHeader.torp +6 -10
  95. package/dist/Dialog/DialogTypes.ts +2 -2
  96. package/dist/Dialog/index.d.ts +28 -26
  97. package/dist/Dialog/index.js +6 -22
  98. package/dist/Disclosure/Disclosure.torp +18 -18
  99. package/dist/Disclosure/DisclosureContent.torp +5 -6
  100. package/dist/Disclosure/DisclosureHeader.torp +7 -11
  101. package/dist/Disclosure/DisclosureTrigger.torp +4 -5
  102. package/dist/Disclosure/DisclosureTypes.ts +1 -1
  103. package/dist/Disclosure/index.d.ts +14 -16
  104. package/dist/Disclosure/index.js +5 -18
  105. package/dist/Drawer/Drawer.torp +21 -51
  106. package/dist/Drawer/DrawerContent.torp +67 -13
  107. package/dist/Drawer/DrawerOverlay.torp +4 -4
  108. package/dist/Drawer/DrawerTrigger.torp +16 -4
  109. package/dist/Drawer/DrawerTypes.ts +4 -1
  110. package/dist/Drawer/index.d.ts +16 -20
  111. package/dist/Drawer/index.js +5 -18
  112. package/dist/FocusGroup/FocusGroup.torp +70 -0
  113. package/dist/FocusGroup/FocusGroupButton.torp +59 -0
  114. package/dist/FocusGroup/FocusGroupTypes.ts +14 -0
  115. package/dist/FocusGroup/index.d.ts +44 -0
  116. package/dist/FocusGroup/index.js +3 -0
  117. package/dist/Form/CheckBox.torp +28 -20
  118. package/dist/Form/Field.torp +17 -17
  119. package/dist/Form/File.torp +31 -22
  120. package/dist/Form/FileDrop.torp +187 -0
  121. package/dist/Form/Form.torp +24 -22
  122. package/dist/Form/FormTypes.ts +2 -0
  123. package/dist/Form/FormValues.torp +37 -0
  124. package/dist/Form/Hidden.torp +4 -12
  125. package/dist/Form/Input.torp +38 -32
  126. package/dist/Form/Label.torp +3 -3
  127. package/dist/Form/Message.torp +13 -5
  128. package/dist/Form/MessageSummary.torp +39 -0
  129. package/dist/Form/Option.torp +11 -7
  130. package/dist/Form/Select.torp +32 -28
  131. package/dist/Form/TextArea.torp +35 -31
  132. package/dist/Form/Toggle.torp +109 -0
  133. package/dist/Form/index.d.ts +198 -77
  134. package/dist/Form/index.js +16 -46
  135. package/dist/ListBox/ListBox.torp +374 -0
  136. package/dist/ListBox/ListBoxItem.torp +131 -0
  137. package/dist/ListBox/ListBoxSeparator.torp +29 -0
  138. package/dist/ListBox/ListBoxTypes.ts +41 -0
  139. package/dist/ListBox/LoadedListBoxItems.torp +41 -0
  140. package/dist/ListBox/index.d.ts +136 -0
  141. package/dist/ListBox/index.js +4 -0
  142. package/dist/MaskedInput/MaskedInput.torp +143 -0
  143. package/dist/MaskedInput/index.d.ts +52 -0
  144. package/dist/MaskedInput/index.js +2 -0
  145. package/dist/Menu/Menu.torp +90 -70
  146. package/dist/Menu/MenuButton.torp +17 -10
  147. package/dist/Menu/MenuCheck.torp +22 -18
  148. package/dist/Menu/MenuGroup.torp +4 -4
  149. package/dist/Menu/MenuIndicator.torp +5 -13
  150. package/dist/Menu/MenuPopout.torp +20 -50
  151. package/dist/Menu/MenuPopoutContent.torp +15 -66
  152. package/dist/Menu/MenuPopoutTrigger.torp +19 -100
  153. package/dist/Menu/MenuRadio.torp +25 -26
  154. package/dist/Menu/MenuRadioGroup.torp +25 -68
  155. package/dist/Menu/MenuSeparator.torp +3 -2
  156. package/dist/Menu/MenuTypes.ts +12 -21
  157. package/dist/Menu/index.d.ts +45 -51
  158. package/dist/Menu/index.js +12 -46
  159. package/dist/MenuBar/MenuBar.torp +31 -83
  160. package/dist/MenuBar/MenuBarItem.torp +34 -55
  161. package/dist/MenuBar/MenuBarItemContent.torp +15 -101
  162. package/dist/MenuBar/MenuBarItemTrigger.torp +20 -55
  163. package/dist/MenuBar/MenuBarTypes.ts +13 -12
  164. package/dist/MenuBar/index.d.ts +17 -19
  165. package/dist/MenuBar/index.js +5 -18
  166. package/dist/Modal/Modal.torp +28 -48
  167. package/dist/Modal/ModalContent.torp +21 -44
  168. package/dist/Modal/ModalOverlay.torp +4 -4
  169. package/dist/Modal/ModalTrigger.torp +16 -32
  170. package/dist/Modal/ModalTypes.ts +6 -17
  171. package/dist/Modal/index.d.ts +17 -29
  172. package/dist/Modal/index.js +29 -28
  173. package/dist/Modal/index.js.map +1 -1
  174. package/dist/Modal/showPrompt.ts +2 -2
  175. package/dist/NavMenu/NavMenu.torp +22 -104
  176. package/dist/NavMenu/NavMenuButton.torp +10 -8
  177. package/dist/NavMenu/NavMenuElement.torp +6 -7
  178. package/dist/NavMenu/NavMenuGroup.torp +5 -5
  179. package/dist/NavMenu/NavMenuGroupHeader.torp +5 -8
  180. package/dist/NavMenu/NavMenuLink.torp +7 -10
  181. package/dist/NavMenu/NavMenuPopout.torp +16 -61
  182. package/dist/NavMenu/NavMenuPopoutContent.torp +14 -73
  183. package/dist/NavMenu/NavMenuPopoutTrigger.torp +47 -0
  184. package/dist/NavMenu/NavMenuSeparator.torp +3 -6
  185. package/dist/NavMenu/NavMenuTypes.ts +6 -15
  186. package/dist/NavMenu/index.d.ts +55 -55
  187. package/dist/NavMenu/index.js +11 -42
  188. package/dist/Notification/Notification.torp +12 -24
  189. package/dist/Notification/NotificationClose.torp +6 -3
  190. package/dist/Notification/NotificationContainer.torp +3 -7
  191. package/dist/Notification/NotificationContent.torp +3 -7
  192. package/dist/Notification/NotificationTypes.ts +1 -1
  193. package/dist/Notification/index.d.ts +15 -12
  194. package/dist/Notification/index.js +22 -32
  195. package/dist/Notification/index.js.map +1 -1
  196. package/dist/NumberInput/NumberInput.torp +255 -0
  197. package/dist/NumberInput/index.d.ts +44 -0
  198. package/dist/NumberInput/index.js +2 -0
  199. package/dist/Pagination/Pagination.torp +152 -0
  200. package/dist/Pagination/PaginationItem.torp +137 -0
  201. package/dist/Pagination/PaginationTypes.ts +22 -0
  202. package/dist/Pagination/buildPages.ts +61 -0
  203. package/dist/Pagination/index.d.ts +63 -0
  204. package/dist/Pagination/index.js +3 -0
  205. package/dist/Popover/Popover.torp +39 -52
  206. package/dist/Popover/PopoverContent.torp +27 -76
  207. package/dist/Popover/PopoverHover.torp +90 -0
  208. package/dist/Popover/PopoverTrigger.torp +17 -40
  209. package/dist/Popover/PopoverTypes.ts +5 -18
  210. package/dist/Popover/index.d.ts +40 -25
  211. package/dist/Popover/index.js +18 -18
  212. package/dist/Popover/index.js.map +1 -1
  213. package/dist/Progress/Progress.torp +88 -0
  214. package/dist/Progress/index.d.ts +37 -0
  215. package/dist/Progress/index.js +2 -0
  216. package/dist/Rating/Rating.torp +225 -0
  217. package/dist/Rating/index.d.ts +44 -0
  218. package/dist/Rating/index.js +2 -0
  219. package/dist/SegmentedControl/SegmentedControl.torp +233 -0
  220. package/dist/SegmentedControl/SegmentedControlTypes.ts +26 -0
  221. package/dist/SegmentedControl/SegmentedItem.torp +78 -0
  222. package/dist/SegmentedControl/index.d.ts +74 -0
  223. package/dist/SegmentedControl/index.js +3 -0
  224. package/dist/SelectBox/SelectBox.torp +190 -0
  225. package/dist/SelectBox/SelectBoxContent.torp +107 -0
  226. package/dist/SelectBox/SelectBoxTrigger.torp +141 -0
  227. package/dist/SelectBox/SelectBoxTypes.ts +33 -0
  228. package/dist/SelectBox/index.d.ts +112 -0
  229. package/dist/SelectBox/index.js +5 -0
  230. package/dist/Slider/Slider.torp +248 -0
  231. package/dist/Slider/index.d.ts +45 -0
  232. package/dist/Slider/index.js +2 -0
  233. package/dist/Splitter/Splitter.torp +156 -0
  234. package/dist/Splitter/SplitterHandle.torp +161 -0
  235. package/dist/Splitter/SplitterPane.torp +63 -0
  236. package/dist/Splitter/SplitterTypes.ts +31 -0
  237. package/dist/Splitter/index.d.ts +103 -0
  238. package/dist/Splitter/index.js +4 -0
  239. package/dist/Stepper/Stepper.torp +146 -0
  240. package/dist/Stepper/StepperMarker.torp +24 -0
  241. package/dist/Stepper/StepperNext.torp +44 -0
  242. package/dist/Stepper/StepperPrevious.torp +44 -0
  243. package/dist/Stepper/StepperStep.torp +90 -0
  244. package/dist/Stepper/StepperTypes.ts +30 -0
  245. package/dist/Stepper/index.d.ts +149 -0
  246. package/dist/Stepper/index.js +6 -0
  247. package/dist/TabGroup/TabContent.torp +6 -6
  248. package/dist/TabGroup/TabGroup.torp +97 -113
  249. package/dist/TabGroup/TabGroupTypes.ts +3 -3
  250. package/dist/TabGroup/TabHeader.torp +23 -19
  251. package/dist/TabGroup/TabList.torp +8 -21
  252. package/dist/TabGroup/TabTrigger.torp +6 -7
  253. package/dist/TabGroup/index.d.ts +26 -26
  254. package/dist/TabGroup/index.js +6 -22
  255. package/dist/TagInput/TagInput.torp +378 -0
  256. package/dist/TagInput/index.d.ts +48 -0
  257. package/dist/TagInput/index.js +2 -0
  258. package/dist/TimePicker/TimePicker.torp +462 -0
  259. package/dist/TimePicker/index.d.ts +53 -0
  260. package/dist/TimePicker/index.js +2 -0
  261. package/dist/ToolBar/ToolBar.torp +117 -0
  262. package/dist/ToolBar/ToolBarButton.torp +56 -0
  263. package/dist/ToolBar/ToolBarElement.torp +51 -0
  264. package/dist/ToolBar/ToolBarPopout.torp +45 -0
  265. package/dist/ToolBar/ToolBarPopoutContent.torp +34 -0
  266. package/dist/ToolBar/ToolBarPopoutTrigger.torp +47 -0
  267. package/dist/ToolBar/ToolBarSeparator.torp +21 -0
  268. package/dist/ToolBar/ToolBarTypes.ts +28 -0
  269. package/dist/ToolBar/index.d.ts +210 -0
  270. package/dist/ToolBar/index.js +8 -0
  271. package/dist/Tree/Tree.torp +395 -0
  272. package/dist/Tree/TreeItem.torp +176 -0
  273. package/dist/Tree/TreeItemChildren.torp +60 -0
  274. package/dist/Tree/TreeItemContent.torp +46 -0
  275. package/dist/Tree/TreeItemLabel.torp +94 -0
  276. package/dist/Tree/TreeItemTrigger.torp +78 -0
  277. package/dist/Tree/TreeLoadedChildren.torp +122 -0
  278. package/dist/Tree/TreeTypes.ts +63 -0
  279. package/dist/Tree/index.d.ts +262 -0
  280. package/dist/Tree/index.js +7 -0
  281. package/dist/icons/ChevronDoubleLeft.torp +19 -0
  282. package/dist/icons/ChevronDoubleRight.torp +19 -0
  283. package/dist/icons/index.d.ts +61 -1
  284. package/dist/icons/index.js +17 -58
  285. package/dist/loader-DEeG5vFY.js +44 -0
  286. package/dist/loader-DEeG5vFY.js.map +1 -0
  287. package/dist/motion/index.d.ts +12 -8
  288. package/dist/motion/index.d.ts.map +1 -0
  289. package/dist/motion/index.js +72 -88
  290. package/dist/motion/index.js.map +1 -1
  291. package/dist/mount/draggable.ts +63 -0
  292. package/dist/mount/dropTarget.ts +108 -0
  293. package/dist/mount/hoverTrigger.ts +1 -1
  294. package/dist/utils/$handle.ts +23 -0
  295. package/dist/utils/LoadedItems.torp +47 -0
  296. package/dist/utils/PopoutClickTrigger.torp +99 -0
  297. package/dist/utils/PopoutTypes.ts +82 -0
  298. package/dist/utils/SubmenuPopout.torp +89 -0
  299. package/dist/utils/SubmenuPopoutContent.torp +87 -0
  300. package/dist/utils/SubmenuPopoutTrigger.torp +160 -0
  301. package/dist/utils/chartColors.ts +13 -13
  302. package/dist/utils/chartLayout.ts +143 -0
  303. package/dist/utils/chartUtils.ts +1 -1
  304. package/dist/utils/colorUtils.ts +103 -0
  305. package/dist/utils/createItemGroup.ts +152 -0
  306. package/dist/utils/dateUtils.ts +8 -7
  307. package/dist/utils/documentEvents.ts +4 -4
  308. package/dist/utils/dragState.ts +86 -0
  309. package/dist/utils/focusGroup.ts +204 -0
  310. package/dist/utils/focusItem.ts +44 -0
  311. package/dist/utils/formField.ts +70 -0
  312. package/dist/utils/hoverOpen.ts +50 -0
  313. package/dist/utils/hoverReveal.ts +194 -0
  314. package/dist/utils/loader.ts +113 -0
  315. package/dist/utils/maskUtils.ts +98 -0
  316. package/dist/utils/popoutContent.ts +137 -0
  317. package/dist/utils/reorderList.ts +52 -0
  318. package/package.json +116 -25
  319. package/dist/Accordion/index.js.map +0 -1
  320. package/dist/Breadcrumb/index.js.map +0 -1
  321. package/dist/Calendar/index.js.map +0 -1
  322. package/dist/Chart/BarChart.torp +0 -159
  323. package/dist/Chart/LineChart.torp +0 -196
  324. package/dist/Chart/index.d.ts +0 -220
  325. package/dist/Chart/index.js +0 -34
  326. package/dist/Chart/index.js.map +0 -1
  327. package/dist/Contextual/index.js.map +0 -1
  328. package/dist/Dialog/index.js.map +0 -1
  329. package/dist/Disclosure/index.js.map +0 -1
  330. package/dist/Drawer/index.js.map +0 -1
  331. package/dist/Form/index.js.map +0 -1
  332. package/dist/Menu/index.js.map +0 -1
  333. package/dist/MenuBar/index.js.map +0 -1
  334. package/dist/NavMenu/NavMenuPopoutButton.torp +0 -129
  335. package/dist/NavMenu/index.js.map +0 -1
  336. package/dist/TabGroup/index.js.map +0 -1
  337. package/dist/icons/index.js.map +0 -1
  338. package/dist/index.d.ts +0 -19
  339. package/dist/metafile-esm.json +0 -1
  340. package/dist/motion/fade.ts +0 -16
  341. package/dist/motion/grow.ts +0 -23
  342. package/dist/motion/measure.ts +0 -28
  343. package/dist/motion/slide.ts +0 -45
  344. package/dist/mount/index.d.ts +0 -2
  345. package/dist/utils/index.d.ts +0 -2
  346. /package/dist/{Chart → Charts}/DataSeries.ts +0 -0
@@ -1,31 +1,83 @@
1
1
  import type { ClassValue, StyleValue } from "@torpor/view";
2
- import { ReactiveDate } from "@torpor/view";
3
- import { areDatesEqual, dayNames, monthNames } from "../utils/dateUtils";
4
- import CalendarDay from "./CalendarDay.torp";
5
- import { type CalendarContext, type DayState, type CalendarEvent, CalendarContextName } from "./CalendarTypes";
6
- import ChevronLeft from "../icons/ChevronLeft.torp";
7
- import ChevronRight from "../icons/ChevronRight.torp";
8
-
9
- // TODO: Split this out into Calendar, CalendarHeader, CalendarPreviousTrigger, CalendarGrid etc
2
+ import { areDatesEqual } from "../utils/dateUtils";
3
+ import getId from "../utils/getId";
4
+ import { type PopoutContext, PopoutContextName } from "../utils/PopoutTypes";
5
+ import {
6
+ type CalendarContext,
7
+ CalendarContextName,
8
+ type CalendarState,
9
+ type DayState,
10
+ type TriggerType,
11
+ } from "./CalendarTypes";
12
+ import buildDays from "./buildDays";
10
13
 
11
14
  interface CalendarProps {
12
15
  /** An ID for the root element */
13
16
  id?: string;
14
17
  /** Classes for the root element */
15
- class?: ClassValue,
18
+ class?: ClassValue;
16
19
  /** Styles for the root element */
17
- style?: StyleValue,
20
+ style?: StyleValue;
21
+ /** The starting index of the week, where 0 is Sunday */
22
+ startOfWeek?: number;
23
+ /** Whether a date can be selected. Set this to true for use in date pickers etc */
24
+ selectable?: boolean;
25
+ /** The selected date */
26
+ value?: Date;
27
+ // /** Events to show in the calendar */
28
+ // TODO: events?: CalendarEvent[],
29
+ /**
30
+ * Raised when the user selects a date (only when `selectable` is true);
31
+ * use this for the calendar's value
32
+ */
33
+ onchange?: (value: Date) => void;
34
+ /**
35
+ * Raised when the visible date changes, i.e. when the user navigates to a
36
+ * different month via the previous/next triggers or the keyboard
37
+ */
38
+ onchangedate?: (value: Date) => void;
39
+ /** Raised when the user presses Escape, so date pickers can close */
40
+ onclose?: () => void;
41
+ /**
42
+ * Whether a date counts as selected, used for the day gridcells'
43
+ * aria-selected. Defaults to the active date
44
+ */
45
+ isSelected?: (date: Date) => boolean;
18
46
  }
19
47
 
48
+ /**
49
+ * A basic calendar.
50
+ *
51
+ * The structure of a Calendar is:
52
+ *
53
+ * ```
54
+ * <Calendar>
55
+ * <CalendarHeader>
56
+ * <CalendarHeaderTrigger type="previous" />
57
+ * <h4>{$slot.monthName} {$slot.year}</h4>
58
+ * <CalendarHeaderTrigger type="next" />
59
+ * </CalendarHeader>
60
+ * <CalendarGridHeader>
61
+ * <CalendarDayHeader />
62
+ * </CalendarGridHeader>
63
+ * <CalendarGrid>
64
+ * <CalendarDay />
65
+ * </CalendarGrid>
66
+ * </Calendar>
67
+ * ```
68
+ *
69
+ * The CalendarGrid slot is rendered once per day, with the day passed back
70
+ * as `$slot.day`.
71
+ */
20
72
  export default function Calendar($props: CalendarProps) {
73
+ let defaultId = getId();
74
+
21
75
  $props ??= $watch({});
22
- $props.startOfWeek ??= 1;
23
- $props.selectable ??= false;
24
- $props.value ??= new Date();
25
- $props.events ??= [];
26
76
 
27
- // Ensure the value is a reactive date
28
- $props.value = new ReactiveDate($unwrap($props.value));
77
+ // Ensure the value is a reactive date -- assigning a plain date to
78
+ // watched props/state wraps it automatically
79
+ $props.value = new Date($unwrap($props.value ?? new Date()));
80
+ let reactiveValue = $props.value;
29
81
 
30
82
  // A note on dates:
31
83
  // * value is the selected value
@@ -33,22 +85,42 @@ export default function Calendar($props: CalendarProps) {
33
85
  // * visibleDate is the date that is currently being displayed in the calendar (really only the month part is important here)
34
86
 
35
87
  let $state = $watch({
36
- activeDate: $props.value,
37
- visibleDate: $props.value,
38
- get days() {
88
+ activeDate: reactiveValue,
89
+ visibleDate: reactiveValue,
90
+ visibleStartDate: reactiveValue,
91
+ visibleEndDate: reactiveValue,
92
+ get days(): DayState[] {
39
93
  return $cache(() => {
40
- return buildDays($state.visibleDate, $props.startOfWeek)
94
+ return buildDays($state, $props.startOfWeek ?? 1);
41
95
  });
42
96
  },
43
- });
97
+ } satisfies CalendarState);
44
98
 
45
- let visibleStartDate = $props.value;
46
- let visibleEndDate = $props.value;
47
99
  let container: HTMLElement;
48
100
  let refocus = false;
49
101
 
102
+ // Maybe get stuff out of a popout context
103
+ const popoutContext = $context[PopoutContextName] as PopoutContext | undefined;
104
+ if (popoutContext) {
105
+ // Set the content ID and role so that triggers can use them with
106
+ // aria-controls / aria-haspopup
107
+ popoutContext.state.contentId = $props?.id ?? defaultId;
108
+ popoutContext.state.contentRole = "grid";
109
+ }
110
+
50
111
  const context: CalendarContext = {
51
- registerDay
112
+ get selectable() {
113
+ return $props.selectable === true;
114
+ },
115
+ startOfWeek: $props.startOfWeek ?? 1,
116
+ registerDay,
117
+ handleTrigger,
118
+ handleDay,
119
+ handleKey,
120
+ isSelected: (date: Date) => {
121
+ return $props.isSelected?.(date) ?? areDatesEqual(date, $state.activeDate);
122
+ },
123
+ state: $state,
52
124
  };
53
125
  $context[CalendarContextName] = context;
54
126
 
@@ -63,75 +135,35 @@ export default function Calendar($props: CalendarProps) {
63
135
  }
64
136
  });
65
137
 
66
- function registerDay(date: ReactiveDate, setActive: (value: boolean) => void) {
67
- const day = $state.days.find((day) => areDatesEqual(day.date, date));
138
+ function registerDay(date: Date, setActive: (value: boolean) => void) {
139
+ const day = $state.days.find((d) => areDatesEqual(d.date, date));
68
140
  if (day) {
69
141
  day.setActive = setActive;
70
142
  }
71
143
  }
72
144
 
73
- function buildDays(date: ReactiveDate, start: number): DayState[] {
74
- const newDays = [];
75
-
76
- // Set the first day to the start of the week before the first day of
77
- // the month (e.g. Monday the 28th of the previous month)
78
- visibleStartDate = new Date();
79
- visibleStartDate.setFullYear(date.getFullYear(), date.getMonth(), 1);
80
- visibleStartDate.setDate(
81
- visibleStartDate.getDate() - ((visibleStartDate.getDay() + 7 - start) % 7)
82
- );
83
-
84
- // Set the last day to the end of the week after the last day of the
85
- // month (e.g. Sunday the 6th of the next month)
86
- visibleEndDate = new Date();
87
- visibleEndDate.setFullYear(date.getFullYear(), date.getMonth() + 1, 0);
88
- visibleEndDate.setDate(
89
- visibleEndDate.getDate() + ((start - 1 - visibleEndDate.getDay() + 7) % 7)
90
- );
91
-
92
- const dayDiff =
93
- Math.round((visibleEndDate.getTime() - visibleStartDate.getTime()) / (1000 * 60 * 60 * 24)) +
94
- 1;
95
-
96
- for (let i = 0; i < dayDiff; i++) {
97
- const dayDate = new ReactiveDate();
98
- dayDate.setFullYear(
99
- visibleStartDate.getFullYear(),
100
- visibleStartDate.getMonth(),
101
- visibleStartDate.getDate() + i
102
- );
103
- dayDate.setHours(0);
104
- dayDate.setMinutes(0);
105
- dayDate.setSeconds(0);
106
- dayDate.setMilliseconds(0);
107
- const newDay: DayState = {
108
- date: dayDate,
109
- muted: dayDate.getMonth() !== date.getMonth(),
110
- active: areDatesEqual(dayDate, $state.activeDate)
111
- };
112
- newDays.push(newDay);
113
- }
114
-
115
- return newDays;
116
- }
117
-
118
145
  function setValue(date: Date) {
119
- $state.value = new ReactiveDate(date);
146
+ // TODO: for date pickers etc
147
+ // $state.value = new Date(date);
120
148
 
121
149
  // Also set the active date so that the user knows where they are
122
150
  setActiveDate(date);
123
151
 
124
- if ($props.onchange) $props.onchange(value);
152
+ if ($props.onchange) {
153
+ $props.onchange(date);
154
+ }
125
155
  }
126
156
 
127
- function setActiveDate(date: Date) {
128
- $state.activeDate = new ReactiveDate(date);
157
+ function setActiveDate(date: Date, moveRange = false) {
158
+ $state.activeDate = new Date(date);
129
159
 
130
160
  // If the selected date is outside the visible date range, move the date range
131
- if (date < visibleStartDate || date > visibleEndDate) {
161
+ if (moveRange || date < $state.visibleStartDate || date > $state.visibleEndDate) {
132
162
  refocus = true;
133
- $state.visibleDate = new ReactiveDate(date);
134
- if ($props.onchangedate) $props.onchangedate(date);
163
+ $state.visibleDate = new Date(date);
164
+ if ($props.onchangedate) {
165
+ $props.onchangedate(date);
166
+ }
135
167
  }
136
168
 
137
169
  $state.days.forEach((day) => {
@@ -139,31 +171,22 @@ export default function Calendar($props: CalendarProps) {
139
171
  if (day.setActive) {
140
172
  day.setActive(active);
141
173
  }
142
- day.active = active;
143
174
  });
144
175
  }
145
176
 
146
- function handleFocus(e: FocusEvent & { currentTarget: EventTarget & HTMLElement }) {
147
- const el = e.currentTarget.getElementsByClassName("active")[0];
148
- if (el && el.children[0] instanceof HTMLElement) {
149
- el.children[0].focus();
150
- e.preventDefault();
177
+ function handleTrigger(type: TriggerType) {
178
+ if (type === "previous") {
179
+ $state.visibleDate.setMonth($state.visibleDate.getMonth() - 1);
180
+ } else if (type === "next") {
181
+ $state.visibleDate.setMonth($state.visibleDate.getMonth() + 1);
151
182
  }
152
- }
153
183
 
154
- function handlePrevMonth(e: Event) {
155
- e.preventDefault();
156
- $state.visibleDate.setMonth($state.visibleDate.getMonth() - 1);
157
- if ($props.onchangedate) $props.onchangedate(visibleDate);
158
- }
159
-
160
- function handleNextMonth(e: Event) {
161
- e.preventDefault();
162
- $state.visibleDate.setMonth($state.visibleDate.getMonth() + 1);
163
- if ($props.onchangedate) $props.onchangedate(visibleDate);
184
+ if ($props.onchangedate) {
185
+ $props.onchangedate($state.visibleDate);
186
+ }
164
187
  }
165
188
 
166
- async function handleDayClick(date: ReactiveDate) {
189
+ async function handleDay(date: Date) {
167
190
  if (!$props.selectable) return;
168
191
 
169
192
  setValue(date);
@@ -178,44 +201,73 @@ export default function Calendar($props: CalendarProps) {
178
201
  setValue($state.activeDate);
179
202
  break;
180
203
  }
181
- case "Esc":
182
204
  case "Escape": {
183
205
  e.preventDefault();
184
- if ($props.onclose) $props.onclose();
206
+ if ($props.onclose) {
207
+ $props.onclose();
208
+ }
185
209
  break;
186
210
  }
187
- case "Left":
188
211
  case "ArrowLeft": {
189
212
  e.preventDefault();
190
- // Move to the date one day before
191
- const newDate = new Date($state.activeDate.getTime() - 1 * 86400000)
213
+ const newDate = new Date($state.activeDate);
214
+ newDate.setDate(newDate.getDate() - 1);
192
215
  setActiveDate(newDate);
193
216
  break;
194
217
  }
195
- case "Up":
196
218
  case "ArrowUp": {
197
219
  e.preventDefault();
198
- // Move to the date seven days before
199
- const newDate = new Date($state.activeDate.getTime() - 7 * 86400000)
220
+ const newDate = new Date($state.activeDate);
221
+ newDate.setDate(newDate.getDate() - 7);
200
222
  setActiveDate(newDate);
201
223
  break;
202
224
  }
203
- case "Right":
204
225
  case "ArrowRight": {
205
226
  e.preventDefault();
206
- // Move to the date one day after
207
- const newDate = new Date($state.activeDate.getTime() + 1 * 86400000)
227
+ const newDate = new Date($state.activeDate);
228
+ newDate.setDate(newDate.getDate() + 1);
208
229
  setActiveDate(newDate);
209
230
  break;
210
231
  }
211
- case "Down":
212
232
  case "ArrowDown": {
213
233
  e.preventDefault();
214
- // Move to the date seven days after
215
- const newDate = new Date($state.activeDate.getTime() + 7 * 86400000)
234
+ const newDate = new Date($state.activeDate);
235
+ newDate.setDate(newDate.getDate() + 7);
236
+ setActiveDate(newDate);
237
+ break;
238
+ }
239
+ case "Home": {
240
+ e.preventDefault();
241
+ const newDate = new Date($state.activeDate);
242
+ const dayOfWeek = newDate.getDay();
243
+ const daysToSubtract = (dayOfWeek - context.startOfWeek + 7) % 7;
244
+ newDate.setDate(newDate.getDate() - daysToSubtract);
216
245
  setActiveDate(newDate);
217
246
  break;
218
247
  }
248
+ case "End": {
249
+ e.preventDefault();
250
+ const newDate = new Date($state.activeDate);
251
+ const dayOfWeek = newDate.getDay();
252
+ const daysToAdd = (context.startOfWeek - 1 - dayOfWeek + 7) % 7;
253
+ newDate.setDate(newDate.getDate() + daysToAdd);
254
+ setActiveDate(newDate);
255
+ break;
256
+ }
257
+ case "PageUp": {
258
+ e.preventDefault();
259
+ const newDate = new Date($state.activeDate);
260
+ newDate.setMonth(newDate.getMonth() - 1);
261
+ setActiveDate(newDate, true);
262
+ break;
263
+ }
264
+ case "PageDown": {
265
+ e.preventDefault();
266
+ const newDate = new Date($state.activeDate);
267
+ newDate.setMonth(newDate.getMonth() + 1);
268
+ setActiveDate(newDate, true);
269
+ break;
270
+ }
219
271
  }
220
272
  }
221
273
 
@@ -226,52 +278,7 @@ export default function Calendar($props: CalendarProps) {
226
278
  {$props?.style}
227
279
  &ref={container}
228
280
  >
229
- <div class={`torp-calendar-header ${$props?.class ?? ""}`.trim()}>
230
- <button class={`torp-calendar-previous-trigger ${$props?.class ?? ""}`.trim()} onclick={handlePrevMonth}>
231
- <slot name="prev-button">
232
- <ChevronLeft />
233
- </slot>
234
- </button>
235
- <span class={`torp-calendar-month-name ${$props?.class ?? ""}`.trim()}>
236
- {monthNames[$state.visibleDate.getMonth()] + " " + $state.visibleDate.getFullYear()}
237
- </span>
238
- <button class={`torp-calendar-next-trigger ${$props?.class ?? ""}`.trim()} onclick={handleNextMonth}>
239
- <slot name="next-button">
240
- <ChevronRight />
241
- </slot>
242
- </button>
243
- </div>
244
- <div
245
- class={["torp-calendar-grid", $props?.class]}
246
- {$props?.style}
247
- tabindex={$props.selectable ? 0 : -1}
248
- onfocus={handleFocus}
249
- onkeydown={handleKey}
250
- >
251
- @for (let index of [0, 1, 2, 3, 4, 5, 6]) {
252
- <span>
253
- {dayNames[(Math.abs($props.startOfWeek) + index) % 7].substring(0, 2)}
254
- </span>
255
- }
256
- @for (let day of $state.days) {
257
- @key = day.date;
258
- <CalendarDay
259
- {day.date}
260
- {day.muted}
261
- {day.active}
262
- {$props.selectable}
263
- events={$props.events.filter((ev) => areDatesEqual(new Date(ev.date), day.date))}
264
- onclick={handleDayClick}
265
- />
266
- }
267
- </div>
281
+ <slot />
268
282
  </div>
269
283
  }
270
-
271
- @style {
272
- .torp-calendar-grid {
273
- display: grid;
274
- grid-template-columns: repeat(7, 1fr);
275
- }
276
- }
277
284
  }
@@ -1,78 +1,124 @@
1
1
  import type { ClassValue, StyleValue } from "@torpor/view";
2
2
  import { areDatesEqual } from "../utils/dateUtils";
3
- import { type CalendarContext, type CalendarEvent, CalendarContextName } from "./CalendarTypes";
3
+ import { type CalendarContext, CalendarContextName } from "./CalendarTypes";
4
+
5
+ // TODO: Internationalization?? On the server and/or the client...
6
+ const formatDate = (date: Date): string => {
7
+ return new Intl.DateTimeFormat("en-US", {
8
+ year: "numeric",
9
+ month: "long",
10
+ day: "numeric",
11
+ }).format(date);
12
+ };
4
13
 
5
14
  interface CalendarDayProps {
6
15
  /** An ID for the root element */
7
16
  id?: string;
8
17
  /** Classes for the root element */
9
- class?: ClassValue,
18
+ class?: ClassValue;
10
19
  /** Styles for the root element */
11
- style?: StyleValue,
20
+ style?: StyleValue;
21
+ /** The date to display */
22
+ date: Date;
23
+ /** Whether the date is muted (i.e. not in the currently displayed month) */
24
+ muted?: boolean;
25
+ /** Whether the date is active */
26
+ active?: boolean;
27
+ /** An ARIA label for describing the day to screen readers */
28
+ ariaLabel?: string | undefined;
29
+ onclick?: () => void;
30
+ onkeydown?: () => void;
12
31
  }
13
32
 
14
33
  export default function CalendarDay($props: CalendarDayProps) {
15
- $props ??= $watch({});
16
- $props.date ??= new Date();
17
- $props.selectable ??= false;
18
- $props.muted ??= false;
19
- $props.active ??= false;
20
- $props.events ??= [];
34
+ // Ensure the value is a reactive date -- assigning a plain date to
35
+ // watched props/state wraps it automatically
36
+ $props.date = new Date($unwrap($props.date ?? new Date()));
37
+ let reactiveDate = $props.date;
21
38
 
22
- // HACK: can't unwrap in @render
23
- let date = $unwrap($props.date);
39
+ // Get stuff out of the Calendar context
40
+ const context = $context[CalendarContextName] as CalendarContext;
41
+ if (!context) {
42
+ throw new Error("CalendarDay must be contained within a Calendar");
43
+ }
44
+ const { registerDay, handleDay } = context;
24
45
 
25
46
  // Register this item with the parent Calendar, which will handle toggling active for all days
26
- const { registerDay } = $context[CalendarContextName] as CalendarContext;
27
- registerDay($props.date, setActive);
47
+ registerDay(reactiveDate, setActive);
28
48
 
29
49
  // This function is called by the parent Calendar to set this item's active value
30
50
  function setActive(value: boolean) {
31
- //if (active !== value) {
32
- // active = value;
33
- // dispatch("activeChange", value);
34
- //}
51
+ $props.active = value;
35
52
  }
36
53
 
37
54
  function isToday() {
38
55
  const today = new Date();
39
- return areDatesEqual(date, today);
56
+ return areDatesEqual($props.date, today);
40
57
  }
41
58
 
42
59
  async function handleClick() {
43
- //dispatch("click", date);
44
- if ($props.onclick) $props.onclick($props.date);
60
+ handleDay(reactiveDate);
61
+ if ($props.onclick) {
62
+ $props.onclick();
63
+ }
45
64
  }
46
65
 
47
66
  async function handleKey() {
48
- //dispatch("click", date);
49
- if ($props.onkeydown) $props.onkeydown();
67
+ if ($props.onkeydown) {
68
+ $props.onkeydown();
69
+ }
70
+ }
71
+
72
+ function buildClass() {
73
+ return [
74
+ "torp-calendar-day",
75
+ $props?.class,
76
+ {
77
+ muted: $props.muted,
78
+ today: isToday(),
79
+ active: context.selectable && $props.active,
80
+ },
81
+ ];
50
82
  }
51
83
 
52
84
  @render {
53
- <div
54
- {$props?.id}
55
- class={[
56
- `torp-calendar-day ${$props?.class ?? ""}`.trim(),
57
- {
58
- muted: $props.muted,
59
- today: isToday(),
60
- active: $props.selectable && $props.active
61
- }
62
- ]}
63
- >
64
- @if ($props.selectable) {
65
- <button type="button" tabindex="-1" onclick={handleClick} onkeydown={handleKey}>
66
- <span>{date.getDate()}</span>
67
- </button>
68
- } else {
69
- <span>{date.getDate()}</span>
85
+ @if (context.selectable) {
86
+ <button
87
+ {$props?.id}
88
+ class={buildClass()}
89
+ {$props?.style}
90
+ type="button"
91
+ tabindex="-1"
92
+ onclick={handleClick}
93
+ onkeydown={handleKey}
94
+ aria-label={$props?.ariaLabel ?? formatDate($props.date)}
95
+ aria-current={isToday() ? "date" : undefined}
96
+ aria-disabled={$props.muted ? "true" : undefined}
97
+ >
98
+ <slot>
99
+ {$props.date.getDate()}
100
+ </slot>
101
+ </button>
102
+ } else {
103
+ <span
104
+ {$props?.id}
105
+ class={buildClass()}
106
+ {$props?.style}
107
+ aria-label={$props?.ariaLabel ?? formatDate($props.date)}
108
+ aria-current={isToday() ? "date" : undefined}
109
+ >
110
+ <slot>
111
+ {$props.date.getDate()}
112
+ </slot>
113
+ </span>
114
+ }
115
+ @// TODO:
116
+ @/*
117
+ <ul class={`torp-calendar-day-events ${$props?.class ?? ""}`.trim()}>
118
+ @for (ev of $props.events) {
119
+ <li title={ev.content} />
70
120
  }
71
- <ul class={`torp-calendar-day-events ${$props?.class ?? ""}`.trim()}>
72
- @for (ev of $props.events) {
73
- <li title={ev.content} />
74
- }
75
- </ul>
76
- </div>
121
+ </ul>
122
+ */
77
123
  }
78
124
  }
@@ -0,0 +1,36 @@
1
+ import type { ClassValue, StyleValue } from "@torpor/view";
2
+
3
+ interface CalendarDayHeaderProps {
4
+ /** An ID for the root element */
5
+ id?: string;
6
+ /** Classes for the root element */
7
+ class?: ClassValue;
8
+ /** Styles for the root element */
9
+ style?: StyleValue;
10
+ /** The day to display */
11
+ dayName: string;
12
+ /** The short day to display */
13
+ shortDayName: string;
14
+ /** An ARIA label for describing the day header to screen readers */
15
+ ariaLabel?: string | undefined;
16
+ }
17
+
18
+ /**
19
+ * The calendar grid header.
20
+ */
21
+ export default function CalendarDayHeader($props: CalendarDayHeaderProps | undefined) {
22
+ @render {
23
+ <div
24
+ {$props?.id}
25
+ class={["torp-calendar-day-header", $props?.class]}
26
+ {$props?.style}
27
+ role="columnheader"
28
+ aria-label={$props?.ariaLabel ?? $props?.dayName}
29
+ abbr={$props?.shortDayName}
30
+ >
31
+ <slot>
32
+ {$props?.shortDayName}
33
+ </slot>
34
+ </div>
35
+ }
36
+ }