@torpor/ui 0.2.1 → 0.3.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 (304) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/Accordion/Accordion.torp +29 -22
  3. package/dist/Accordion/AccordionContent.torp +7 -8
  4. package/dist/Accordion/AccordionHeader.torp +4 -6
  5. package/dist/Accordion/AccordionItem.torp +15 -12
  6. package/dist/Accordion/AccordionTrigger.torp +6 -7
  7. package/dist/Accordion/AccordionTypes.ts +4 -3
  8. package/dist/Accordion/index.d.ts +5 -5
  9. package/dist/Breadcrumb/Breadcrumb.torp +9 -10
  10. package/dist/Breadcrumb/BreadcrumbItem.torp +5 -7
  11. package/dist/Breadcrumb/BreadcrumbSeparator.torp +3 -5
  12. package/dist/Breadcrumb/index.d.ts +8 -7
  13. package/dist/Calendar/Calendar.torp +12 -13
  14. package/dist/Calendar/CalendarDay.torp +3 -3
  15. package/dist/Contextual/Contextual.torp +125 -0
  16. package/dist/{Popover/PopoverContentContextual.torp → Contextual/ContextualContent.torp} +15 -15
  17. package/dist/Contextual/ContextualTrigger.torp +66 -0
  18. package/dist/Contextual/ContextualTypes.ts +30 -0
  19. package/dist/Contextual/index.d.ts +90 -0
  20. package/dist/Contextual/index.js +14 -0
  21. package/dist/Contextual/index.js.map +1 -0
  22. package/dist/Dialog/Dialog.torp +38 -72
  23. package/dist/Dialog/DialogBody.torp +6 -8
  24. package/dist/Dialog/DialogButton.torp +14 -12
  25. package/dist/Dialog/DialogFooter.torp +3 -5
  26. package/dist/Dialog/DialogHeader.torp +6 -8
  27. package/dist/Dialog/DialogTypes.ts +3 -2
  28. package/dist/Dialog/index.d.ts +16 -11
  29. package/dist/Disclosure/Disclosure.torp +22 -23
  30. package/dist/Disclosure/DisclosureContent.torp +7 -8
  31. package/dist/Disclosure/DisclosureHeader.torp +5 -7
  32. package/dist/Disclosure/DisclosureTrigger.torp +7 -8
  33. package/dist/Disclosure/DisclosureTypes.ts +0 -1
  34. package/dist/Disclosure/index.d.ts +12 -12
  35. package/dist/Drawer/Drawer.torp +101 -70
  36. package/dist/Drawer/DrawerContent.torp +80 -0
  37. package/dist/Drawer/DrawerOverlay.torp +38 -0
  38. package/dist/Drawer/DrawerTrigger.torp +35 -0
  39. package/dist/Drawer/DrawerTypes.ts +24 -0
  40. package/dist/Drawer/index.d.ts +90 -3
  41. package/dist/Drawer/index.js +13 -1
  42. package/dist/Form/CheckBox.torp +91 -0
  43. package/dist/Form/Field.torp +2 -4
  44. package/dist/Form/File.torp +106 -0
  45. package/dist/Form/Form.torp +17 -10
  46. package/dist/Form/FormTypes.ts +5 -0
  47. package/dist/Form/Input.torp +28 -17
  48. package/dist/Form/Label.torp +1 -1
  49. package/dist/Form/Message.torp +1 -1
  50. package/dist/Form/Option.torp +24 -0
  51. package/dist/Form/Select.torp +97 -0
  52. package/dist/Form/TextArea.torp +101 -0
  53. package/dist/Form/index.d.ts +192 -5
  54. package/dist/Form/index.js +21 -1
  55. package/dist/Menu/Menu.torp +16 -15
  56. package/dist/Menu/MenuButton.torp +19 -13
  57. package/dist/Menu/MenuCheck.torp +18 -14
  58. package/dist/Menu/MenuGroup.torp +4 -6
  59. package/dist/Menu/MenuIndicator.torp +5 -7
  60. package/dist/Menu/MenuPopout.torp +12 -15
  61. package/dist/Menu/MenuPopoutContent.torp +6 -8
  62. package/dist/Menu/MenuPopoutTrigger.torp +12 -14
  63. package/dist/Menu/MenuRadio.torp +14 -14
  64. package/dist/Menu/MenuRadioGroup.torp +22 -14
  65. package/dist/Menu/MenuSeparator.torp +3 -5
  66. package/dist/Menu/MenuTypes.ts +7 -5
  67. package/dist/Menu/index.d.ts +28 -22
  68. package/dist/MenuBar/MenuBar.torp +13 -14
  69. package/dist/MenuBar/MenuBarItem.torp +13 -16
  70. package/dist/MenuBar/MenuBarItemContent.torp +7 -9
  71. package/dist/MenuBar/MenuBarItemTrigger.torp +6 -9
  72. package/dist/MenuBar/index.d.ts +16 -16
  73. package/dist/Modal/Modal.torp +118 -0
  74. package/dist/Modal/ModalContent.torp +77 -0
  75. package/dist/Modal/ModalOverlay.torp +38 -0
  76. package/dist/Modal/ModalTrigger.torp +50 -0
  77. package/dist/Modal/ModalTypes.ts +22 -0
  78. package/dist/Modal/index.d.ts +108 -0
  79. package/dist/Modal/index.js +33 -0
  80. package/dist/Modal/index.js.map +1 -0
  81. package/dist/Modal/showModal.ts +19 -0
  82. package/dist/Modal/showPrompt.ts +23 -0
  83. package/dist/NavMenu/NavMenu.torp +7 -8
  84. package/dist/NavMenu/NavMenuButton.torp +6 -8
  85. package/dist/NavMenu/NavMenuElement.torp +8 -8
  86. package/dist/NavMenu/NavMenuGroup.torp +4 -6
  87. package/dist/NavMenu/NavMenuGroupHeader.torp +5 -6
  88. package/dist/NavMenu/NavMenuLink.torp +8 -11
  89. package/dist/NavMenu/NavMenuPopout.torp +25 -17
  90. package/dist/NavMenu/NavMenuPopoutButton.torp +12 -13
  91. package/dist/NavMenu/NavMenuPopoutContent.torp +12 -12
  92. package/dist/NavMenu/NavMenuSeparator.torp +3 -5
  93. package/dist/NavMenu/index.d.ts +17 -11
  94. package/dist/Notification/Notification.torp +22 -13
  95. package/dist/Notification/NotificationClose.torp +3 -5
  96. package/dist/Notification/NotificationContainer.torp +3 -5
  97. package/dist/Notification/NotificationContent.torp +3 -5
  98. package/dist/Notification/index.d.ts +4 -4
  99. package/dist/Popover/Popover.torp +31 -25
  100. package/dist/Popover/PopoverContent.torp +35 -10
  101. package/dist/Popover/PopoverTrigger.torp +24 -4
  102. package/dist/Popover/PopoverTypes.ts +1 -1
  103. package/dist/Popover/index.d.ts +16 -124
  104. package/dist/Popover/index.js +1 -163
  105. package/dist/Popover/index.js.map +1 -1
  106. package/dist/TabGroup/TabContent.torp +12 -9
  107. package/dist/TabGroup/TabGroup.torp +41 -35
  108. package/dist/TabGroup/TabGroupTypes.ts +10 -5
  109. package/dist/TabGroup/TabHeader.torp +15 -8
  110. package/dist/TabGroup/TabList.torp +4 -6
  111. package/dist/TabGroup/TabTrigger.torp +8 -9
  112. package/dist/TabGroup/index.d.ts +14 -6
  113. package/dist/icons/ArrowDown.torp +3 -1
  114. package/dist/icons/ArrowLeft.torp +3 -1
  115. package/dist/icons/ArrowRight.torp +3 -1
  116. package/dist/icons/ArrowUp.torp +3 -1
  117. package/dist/icons/Bars.torp +3 -1
  118. package/dist/icons/Check.torp +3 -1
  119. package/dist/icons/ChevronDown.torp +3 -1
  120. package/dist/icons/ChevronLeft.torp +3 -1
  121. package/dist/icons/ChevronRight.torp +3 -1
  122. package/dist/icons/ChevronUp.torp +3 -1
  123. package/dist/icons/Cross.torp +3 -1
  124. package/dist/icons/IconTypes.ts +6 -0
  125. package/dist/icons/Loading.torp +3 -1
  126. package/dist/icons/Minus.torp +3 -1
  127. package/dist/icons/Plus.torp +3 -1
  128. package/dist/icons/index.d.ts +271 -14
  129. package/dist/index.d.ts +17 -4
  130. package/dist/metafile-esm.json +1 -1
  131. package/dist/motion/fade.ts +15 -6
  132. package/dist/motion/grow.ts +23 -0
  133. package/dist/motion/index.d.ts +19 -2
  134. package/dist/motion/index.js +93 -3
  135. package/dist/motion/index.js.map +1 -1
  136. package/dist/motion/measure.ts +28 -0
  137. package/dist/motion/slide.ts +45 -0
  138. package/dist/mount/clickPopover.ts +51 -0
  139. package/dist/mount/contextPopover.ts +51 -0
  140. package/dist/mount/hoverPopover.ts +58 -0
  141. package/package.json +21 -14
  142. package/scripts/postbuild.ts +11 -1
  143. package/src/Accordion/Accordion.torp +29 -22
  144. package/src/Accordion/AccordionContent.torp +7 -8
  145. package/src/Accordion/AccordionHeader.torp +4 -6
  146. package/src/Accordion/AccordionItem.torp +15 -12
  147. package/src/Accordion/AccordionTrigger.torp +6 -7
  148. package/src/Accordion/AccordionTypes.ts +4 -3
  149. package/src/Breadcrumb/Breadcrumb.torp +9 -10
  150. package/src/Breadcrumb/BreadcrumbItem.torp +5 -7
  151. package/src/Breadcrumb/BreadcrumbSeparator.torp +3 -5
  152. package/src/Calendar/Calendar.torp +12 -13
  153. package/src/Calendar/CalendarDay.torp +3 -3
  154. package/src/Contextual/Contextual.torp +125 -0
  155. package/src/{Popover/PopoverContentContextual.torp → Contextual/ContextualContent.torp} +15 -15
  156. package/src/Contextual/ContextualTrigger.torp +66 -0
  157. package/src/Contextual/ContextualTypes.ts +30 -0
  158. package/src/Contextual/index.ts +5 -0
  159. package/src/Dialog/Dialog.torp +38 -72
  160. package/src/Dialog/DialogBody.torp +6 -8
  161. package/src/Dialog/DialogButton.torp +14 -12
  162. package/src/Dialog/DialogFooter.torp +3 -5
  163. package/src/Dialog/DialogHeader.torp +6 -8
  164. package/src/Dialog/DialogTypes.ts +3 -2
  165. package/src/Disclosure/Disclosure.torp +22 -23
  166. package/src/Disclosure/DisclosureContent.torp +7 -8
  167. package/src/Disclosure/DisclosureHeader.torp +5 -7
  168. package/src/Disclosure/DisclosureTrigger.torp +7 -8
  169. package/src/Disclosure/DisclosureTypes.ts +0 -1
  170. package/src/Drawer/Drawer.torp +101 -70
  171. package/src/Drawer/DrawerContent.torp +80 -0
  172. package/src/Drawer/DrawerOverlay.torp +38 -0
  173. package/src/Drawer/DrawerTrigger.torp +35 -0
  174. package/src/Drawer/DrawerTypes.ts +24 -0
  175. package/src/Drawer/index.ts +4 -1
  176. package/src/Form/CheckBox.torp +91 -0
  177. package/src/Form/Field.torp +2 -4
  178. package/src/Form/File.torp +106 -0
  179. package/src/Form/Form.torp +17 -10
  180. package/src/Form/FormTypes.ts +5 -0
  181. package/src/Form/Input.torp +28 -17
  182. package/src/Form/Label.torp +1 -1
  183. package/src/Form/Message.torp +1 -1
  184. package/src/Form/Option.torp +24 -0
  185. package/src/Form/Select.torp +97 -0
  186. package/src/Form/TextArea.torp +101 -0
  187. package/src/Form/index.ts +6 -1
  188. package/src/Menu/Menu.torp +16 -15
  189. package/src/Menu/MenuButton.torp +19 -13
  190. package/src/Menu/MenuCheck.torp +18 -14
  191. package/src/Menu/MenuGroup.torp +4 -6
  192. package/src/Menu/MenuIndicator.torp +5 -7
  193. package/src/Menu/MenuPopout.torp +12 -15
  194. package/src/Menu/MenuPopoutContent.torp +6 -8
  195. package/src/Menu/MenuPopoutTrigger.torp +12 -14
  196. package/src/Menu/MenuRadio.torp +14 -14
  197. package/src/Menu/MenuRadioGroup.torp +22 -14
  198. package/src/Menu/MenuSeparator.torp +3 -5
  199. package/src/Menu/MenuTypes.ts +7 -5
  200. package/src/MenuBar/MenuBar.torp +13 -14
  201. package/src/MenuBar/MenuBarItem.torp +13 -16
  202. package/src/MenuBar/MenuBarItemContent.torp +7 -9
  203. package/src/MenuBar/MenuBarItemTrigger.torp +6 -9
  204. package/src/Modal/Modal.torp +118 -0
  205. package/src/Modal/ModalContent.torp +77 -0
  206. package/src/Modal/ModalOverlay.torp +38 -0
  207. package/src/Modal/ModalTrigger.torp +50 -0
  208. package/src/Modal/ModalTypes.ts +22 -0
  209. package/src/Modal/index.ts +10 -0
  210. package/src/Modal/showModal.ts +19 -0
  211. package/src/Modal/showPrompt.ts +23 -0
  212. package/src/NavMenu/NavMenu.torp +7 -8
  213. package/src/NavMenu/NavMenuButton.torp +6 -8
  214. package/src/NavMenu/NavMenuElement.torp +8 -8
  215. package/src/NavMenu/NavMenuGroup.torp +4 -6
  216. package/src/NavMenu/NavMenuGroupHeader.torp +5 -6
  217. package/src/NavMenu/NavMenuLink.torp +8 -11
  218. package/src/NavMenu/NavMenuPopout.torp +25 -17
  219. package/src/NavMenu/NavMenuPopoutButton.torp +12 -13
  220. package/src/NavMenu/NavMenuPopoutContent.torp +12 -12
  221. package/src/NavMenu/NavMenuSeparator.torp +3 -5
  222. package/src/Notification/Notification.torp +22 -13
  223. package/src/Notification/NotificationClose.torp +3 -5
  224. package/src/Notification/NotificationContainer.torp +3 -5
  225. package/src/Notification/NotificationContent.torp +3 -5
  226. package/src/Popover/Popover.torp +31 -25
  227. package/src/Popover/PopoverContent.torp +35 -10
  228. package/src/Popover/PopoverTrigger.torp +24 -4
  229. package/src/Popover/PopoverTypes.ts +1 -1
  230. package/src/Popover/index.ts +1 -24
  231. package/src/Slider/Slider.torp +3 -3
  232. package/src/TabGroup/TabContent.torp +12 -9
  233. package/src/TabGroup/TabGroup.torp +41 -35
  234. package/src/TabGroup/TabGroupTypes.ts +10 -5
  235. package/src/TabGroup/TabHeader.torp +15 -8
  236. package/src/TabGroup/TabList.torp +4 -6
  237. package/src/TabGroup/TabTrigger.torp +8 -9
  238. package/src/icons/ArrowDown.torp +3 -1
  239. package/src/icons/ArrowLeft.torp +3 -1
  240. package/src/icons/ArrowRight.torp +3 -1
  241. package/src/icons/ArrowUp.torp +3 -1
  242. package/src/icons/Bars.torp +3 -1
  243. package/src/icons/Check.torp +3 -1
  244. package/src/icons/ChevronDown.torp +3 -1
  245. package/src/icons/ChevronLeft.torp +3 -1
  246. package/src/icons/ChevronRight.torp +3 -1
  247. package/src/icons/ChevronUp.torp +3 -1
  248. package/src/icons/Cross.torp +3 -1
  249. package/src/icons/IconTypes.ts +6 -0
  250. package/src/icons/Loading.torp +3 -1
  251. package/src/icons/Minus.torp +3 -1
  252. package/src/icons/Plus.torp +3 -1
  253. package/src/motion/fade.ts +15 -6
  254. package/src/motion/grow.ts +23 -0
  255. package/src/motion/index.ts +4 -1
  256. package/src/motion/measure.ts +28 -0
  257. package/src/motion/slide.ts +45 -0
  258. package/src/mount/clickPopover.ts +51 -0
  259. package/src/mount/contextPopover.ts +51 -0
  260. package/src/mount/hoverPopover.ts +58 -0
  261. package/test/Accordion/components/AccordionAccessibility.torp +1 -3
  262. package/test/Accordion/components/AccordionKeyboard.torp +1 -3
  263. package/test/Accordion/components/AccordionList.torp +1 -3
  264. package/test/Accordion/components/AccordionMultiple.torp +2 -4
  265. package/test/Accordion/components/AccordionSingle.torp +2 -4
  266. package/test/Dialog/accessibility-modal.test.ts +2 -2
  267. package/test/Dialog/components/DialogAccessibility.torp +8 -14
  268. package/test/Dialog/components/DialogFunction.torp +20 -4
  269. package/test/Dialog/components/DialogModal.torp +30 -0
  270. package/test/Dialog/components/DialogVariable.torp +7 -7
  271. package/test/Disclosure/components/DisclosureTest.torp +1 -3
  272. package/test/Menu/components/MenuAccessibility.torp +5 -5
  273. package/test/Menu/components/MenuBasic.torp +5 -5
  274. package/test/Notification/components/NotificationFunction.torp +0 -3
  275. package/test/Notification/components/NotificationVariable.torp +1 -1
  276. package/test/Popover/components/PopoverFunction.torp +37 -0
  277. package/test/Popover/components/PopoverTrigger.torp +36 -0
  278. package/test/Popover/components/{PromptVariable.torp → PopoverVariable.torp} +5 -3
  279. package/test/Popover/function.test.ts +2 -7
  280. package/test/Popover/trigger.test.ts +27 -0
  281. package/test/Popover/variable.test.ts +2 -2
  282. package/test/TabGroup/components/TabGroupAccessibility.torp +1 -3
  283. package/test/TabGroup/components/TabGroupKeyboard.torp +1 -3
  284. package/test/TabGroup/components/TabGroupList.torp +1 -3
  285. package/test/TabGroup/components/TabGroupTrigger.torp +1 -3
  286. package/tsup.config.ts +2 -0
  287. package/dist/Popover/PopoverContentAnchored.torp +0 -113
  288. package/dist/Popover/PopoverOverlay.torp +0 -39
  289. package/dist/Popover/PopoverTriggerContextual.torp +0 -46
  290. package/dist/Popover/PopoverTriggerHover.torp +0 -47
  291. package/dist/Popover/mountClickPopover.ts +0 -50
  292. package/dist/Popover/mountContextPopover.ts +0 -50
  293. package/dist/Popover/mountHoverPopover.ts +0 -57
  294. package/dist/Popover/showPopoverPrompt.ts +0 -23
  295. package/src/Popover/PopoverContentAnchored.torp +0 -113
  296. package/src/Popover/PopoverOverlay.torp +0 -39
  297. package/src/Popover/PopoverTriggerContextual.torp +0 -46
  298. package/src/Popover/PopoverTriggerHover.torp +0 -47
  299. package/src/Popover/mountClickPopover.ts +0 -50
  300. package/src/Popover/mountContextPopover.ts +0 -50
  301. package/src/Popover/mountHoverPopover.ts +0 -57
  302. package/src/Popover/showPopoverPrompt.ts +0 -23
  303. package/test/Dialog/components/CustomDialog.torp +0 -20
  304. package/test/Popover/components/PromptFunction.torp +0 -19
@@ -15,10 +15,8 @@ interface DialogHeaderProps {
15
15
  * readers when the Dialog is opened, unless ariaAnnounce is false.
16
16
  *
17
17
  */
18
- export default function DialogHeader($props: DialogHeaderProps) {
19
- $props ??= $watch({});
20
- $props.id ??= getId();
21
- $props.ariaAnnounce ??= true;
18
+ export default function DialogHeader($props: DialogHeaderProps | undefined) {
19
+ let defaultId = getId();
22
20
 
23
21
  // Get stuff out of the DialogContext
24
22
  const context = $context[DialogContextName] as DialogContext;
@@ -28,14 +26,14 @@ export default function DialogHeader($props: DialogHeaderProps) {
28
26
  let $state = context.state;
29
27
 
30
28
  // Set the header id for using in the Dialog's ARIA attributes
31
- if ($props.ariaAnnounce) {
32
- $state.headerId = $props.id;
29
+ if ($props?.ariaAnnounce !== false) {
30
+ $state.headerId = $props?.id ?? defaultId;
33
31
  }
34
32
 
35
33
  @render {
36
34
  <div
37
- {$props.id}
38
- class={`torp-dialog-footer ${$props.class ?? ""}`.trim()}
35
+ id={$props?.id ?? defaultId}
36
+ class={`torp-dialog-footer ${$props?.class ?? ""}`.trim()}
39
37
  >
40
38
  <slot />
41
39
  </div>
@@ -1,7 +1,9 @@
1
1
  export const DialogContextName = "Dialog";
2
2
 
3
+ export type HandleButtonPress = (type: "confirm" | "cancel" | undefined, value?: any) => void;
4
+
3
5
  export interface DialogContext {
4
- handleButton: (type: "confirm" | "cancel" | undefined, value?: any) => void;
6
+ handleButton?: HandleButtonPress;
5
7
  state: DialogState;
6
8
  anchorElement?: HTMLElement;
7
9
  confirmButton?: HTMLButtonElement;
@@ -12,5 +14,4 @@ export interface DialogState {
12
14
  dialogId: string;
13
15
  headerId: string;
14
16
  bodyId: string;
15
- visible: boolean;
16
17
  }
@@ -5,11 +5,11 @@ interface DisclosureProps {
5
5
  id?: string;
6
6
  /** Class name(s) for the root element */
7
7
  class?: string,
8
- /** Whether the Disclosure is expanded and its content visible */
8
+ /** Whether the disclosure is expanded and its content visible */
9
9
  expanded?: boolean,
10
- /** If set to true, the user cannot interact with this Disclosure */
10
+ /** If set to true, the user cannot interact with this disclosure */
11
11
  disabled?: boolean,
12
- /** Raised when this item is opened or closed */
12
+ /** Raised when the disclosure is opened or closed */
13
13
  ontoggle?: (open: boolean) => void,
14
14
  }
15
15
 
@@ -22,30 +22,29 @@ interface DisclosureProps {
22
22
  *
23
23
  * ```
24
24
  * <Disclosure>
25
- * <DisclosureHeader>
26
- * <DisclosureTrigger />
27
- * </DisclosureHeader>
28
- * <DisclosureContent />
25
+ * <DisclosureHeader>
26
+ * <DisclosureTrigger />
27
+ * </DisclosureHeader>
28
+ * <DisclosureContent />
29
29
  * </Disclosure>
30
30
  * ```
31
31
  */
32
- export default function Disclosure($props: DisclosureProps) {
33
- $props ??= $watch({});
34
- $props.expanded ??= false;
35
- $props.disabled ??= false;
36
-
32
+ export default function Disclosure($props: DisclosureProps | undefined) {
37
33
  let $state: DisclosureState = $watch({
38
- expanded: $props.expanded && $props.expanded !== "false",
39
- disabled: $props.disabled,
40
- get dataState() {
41
- return this.expanded ? "open" : "closed";
42
- },
34
+ expanded: false,
35
+ disabled: false,
36
+ headerId: "",
37
+ contentId: "",
43
38
  });
44
39
 
45
40
  // Update $state with $props
46
41
  $run(() => {
47
- $state.expanded = $props.expanded && $props.expanded !== "false";
48
- $state.disabled = $props.disabled;
42
+ $state.expanded = $props?.expanded === true ||
43
+ // @ts-ignore
44
+ $props?.expanded === "true";
45
+ $state.disabled = $props?.disabled === true ||
46
+ // @ts-ignore
47
+ $props?.disabled === "true";
49
48
  });
50
49
 
51
50
  // Put stuff into a DisclosureContext
@@ -57,7 +56,7 @@ export default function Disclosure($props: DisclosureProps) {
57
56
  // Dispatch the toggle event when the value of expanded changes
58
57
  let firstToggle = true;
59
58
  $run(() => {
60
- const ev = $props.ontoggle;
59
+ const ev = $props?.ontoggle;
61
60
  const expanded = $state.expanded;
62
61
  if (firstToggle) {
63
62
  firstToggle = false;
@@ -68,9 +67,9 @@ export default function Disclosure($props: DisclosureProps) {
68
67
 
69
68
  @render {
70
69
  <div
71
- {$props.id}
72
- class={`torp-disclosure-item ${$props.class ?? ""}`.trim()}
73
- data-state={$state.dataState}
70
+ {$props?.id}
71
+ class={`torp-disclosure-item ${$props?.class ?? ""}`.trim()}
72
+ data-state={$state.expanded ? "open" : "closed"}
74
73
  data-disabled={$state.disabled ? "true" : undefined}
75
74
  >
76
75
  <slot />
@@ -13,9 +13,8 @@ interface DisclosureContentProps {
13
13
  /**
14
14
  * Content for a Disclosure, which can be revealed or hidden by an associated DisclosureTrigger.
15
15
  */
16
- export default function DisclosureContent($props: DisclosureContentProps) {
17
- $props ??= $watch({});
18
- $props.id ||= getId();
16
+ export default function DisclosureContent($props: DisclosureContentProps | undefined) {
17
+ let defaultId = getId();
19
18
 
20
19
  const context = $context[DisclosureContextName] as DisclosureContext;
21
20
  if (!context) {
@@ -24,15 +23,15 @@ export default function DisclosureContent($props: DisclosureContentProps) {
24
23
  let $state = context.state
25
24
 
26
25
  // Set the content ID so that it can be used with aria-controls in DisclosureTrigger
27
- $state.contentId = $props.id;
26
+ $state.contentId = $props?.id ?? defaultId;
28
27
 
29
28
  @render {
30
29
  <div
31
- {$props.id}
32
- class={`torp-disclosure-content ${$props.class ?? ""}`.trim()}
33
- role={$props.ariaRegion ? "region" : undefined}
30
+ id={$props?.id ?? defaultId}
31
+ class={`torp-disclosure-content ${$props?.class ?? ""}`.trim()}
32
+ role={$props?.ariaRegion ? "region" : undefined}
34
33
  aria-labelledby={$state.headerId}
35
- data-state={$state.dataState}
34
+ data-state={$state.expanded ? "open" : "closed"}
36
35
  data-disabled={$state.disabled ? "true" : undefined}
37
36
  >
38
37
  @if ($state.expanded) {
@@ -16,13 +16,11 @@ interface DisclosureHeaderProps {
16
16
  *
17
17
  * ```
18
18
  * <DisclosureHeader>
19
- * <DisclosureTrigger />
19
+ * <DisclosureTrigger />
20
20
  * </DisclosureHeader>
21
21
  * ```
22
22
  */
23
- export default function DisclosureHeader($props: DisclosureHeaderProps) {
24
- $props ??= $watch({});
25
-
23
+ export default function DisclosureHeader($props: DisclosureHeaderProps | undefined) {
26
24
  const context = $context[DisclosureContextName] as DisclosureContext;
27
25
  if (!context) {
28
26
  throw new Error("DisclosureHeader must be contained within a Disclosure");
@@ -32,9 +30,9 @@ export default function DisclosureHeader($props: DisclosureHeaderProps) {
32
30
  @render {
33
31
  @// TODO: $props.as
34
32
  <h4
35
- {$props.id}
36
- class={`torp-disclosure-header ${$props.class ?? ""}`.trim()}
37
- data-state={$state.dataState}
33
+ {$props?.id}
34
+ class={`torp-disclosure-header ${$props?.class ?? ""}`.trim()}
35
+ data-state={$state.expanded ? "open" : "closed"}
38
36
  data-disabled={$state.disabled ? "true" : undefined}
39
37
  >
40
38
  <slot />
@@ -11,9 +11,8 @@ interface DisclosureTriggerProps {
11
11
  /**
12
12
  * A header button for a Disclosure, which can be used to reveal or hide an associated DisclosureContent.
13
13
  */
14
- export default function DisclosureTrigger($props: DisclosureTriggerProps) {
15
- $props ??= $watch({});
16
- $props.id ||= getId();
14
+ export default function DisclosureTrigger($props: DisclosureTriggerProps | undefined) {
15
+ let defaultId = getId();
17
16
 
18
17
  // Get stuff out of the DisclosureContext
19
18
  const context = $context[DisclosureContextName] as DisclosureContext;
@@ -23,18 +22,18 @@ export default function DisclosureTrigger($props: DisclosureTriggerProps) {
23
22
  let $state = context.state;
24
23
 
25
24
  // Set the header ID so that it can be used with aria-labelledby in DisclosureContent
26
- $state.headerId = $props.id;
25
+ $state.headerId = $props?.id ?? defaultId;
27
26
 
28
27
  @render {
29
28
  <button
30
29
  type="button"
31
- {$props.id}
32
- class={`torp-disclosure-trigger ${$props.class ?? ""}`.trim()}
33
- disabled={$state.disabled || $state.parentDisabled}
30
+ id={$props?.id ?? defaultId}
31
+ class={`torp-disclosure-trigger ${$props?.class ?? ""}`.trim()}
32
+ disabled={$state.disabled}
34
33
  aria-expanded={$state.expanded.toString()}
35
34
  aria-disabled={$state.disabled}
36
35
  aria-controls={$state.contentId}
37
- data-state={$state.dataState}
36
+ data-state={$state.expanded ? "open" : "closed"}
38
37
  data-disabled={$state.disabled}
39
38
  onclick={() => $state.expanded = !$state.expanded}
40
39
  >
@@ -10,5 +10,4 @@ export interface DisclosureState {
10
10
  contentId: string;
11
11
  expanded: boolean;
12
12
  disabled: boolean;
13
- dataState: "open" | "closed";
14
13
  }
@@ -1,92 +1,123 @@
1
+ import { DrawerContextName, type DrawerContext, type DrawerState } from "./DrawerTypes";
1
2
 
2
3
  interface DrawerProps {
3
4
  /** An ID for the root element */
4
5
  id?: string;
5
6
  /** Class name(s) for the root element */
6
7
  class?: string,
8
+ /** Whether the drawer is modal. If true, an overlay should be supplied to obscure outside content, and only the drawer content will be visible to screen readers */
9
+ modal?: boolean,
10
+ /** Whether the drawer is visible */
7
11
  visible?: boolean,
8
- position?: "left" | "right",
12
+ /** Which side of the window to show the drawer from */
13
+ position?: "left" | "right" | "top" | "bottom",
14
+ /** A function to be called when the user selects a response */
15
+ callback?: ((value: any) => void),
16
+ /** Raised when the drawer is opened or closed */
17
+ ontoggle?: (open: boolean) => void,
18
+ /** Raised when the drawer has opened */
19
+ onopen?: () => void,
20
+ /** Raised when the drawer has closed */
21
+ onclose?: (result: any) => void,
9
22
  }
10
23
 
11
- export default function Drawer($props: DrawerProps) {
12
- $props ??= $watch({});
13
- $props.visible ??= true;
14
- $props.position ||= "left";
24
+ /**
25
+ * A drawer that can be used to show rich content or obtain information from a user.
26
+ *
27
+ * See [the WAI ARIA guidelines for Dialogs](https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/).
28
+ *
29
+ * The structure of a Drawer is:
30
+ *
31
+ * ```
32
+ * <Drawer>
33
+ * <DrawerTrigger /> (optional)
34
+ * <DrawerContent />
35
+ * </Drawer>
36
+ * ```
37
+ */
38
+ export default function Drawer($props: DrawerProps | undefined) {
39
+ let $state: DrawerState = $watch({
40
+ visible: false,
41
+ modal: $props?.modal ?? false,
42
+ position: $props?.position ?? "left",
43
+ });
15
44
 
16
- let offscreen: HTMLElement | undefined;
45
+ // Sync props and state
46
+ $run(() => {
47
+ $state.visible = $props?.visible ?? false;
48
+ });
49
+ $run(() => {
50
+ if ($props !== undefined) {
51
+ $props.visible = $state.visible;
52
+ }
53
+ });
17
54
 
18
- // From https://stackoverflow.com/a/46707458
19
- function measure(el, fn) {
20
- let oldVisibility = el.style.visibility;
21
- let oldPosition = el.style.position;
55
+ let result: any;
22
56
 
23
- let oldParent = el.parentNode;
24
- let oldBefore = el.nextNode;
57
+ // Set the context to pass down to items
58
+ let context: DrawerContext = {
59
+ handleButton,
60
+ handleClickOutside,
61
+ state: $state,
62
+ };
63
+ $context[DrawerContextName] = context;
25
64
 
26
- el.style.visibility = "hidden";
27
- el.style.position = "absolute";
65
+ // Dispatch the toggle event when the drawer is opened or closed
66
+ let firstToggle = true;
67
+ $run(() => {
68
+ const ontoggle = $props?.ontoggle;
69
+ const onopen = $props?.onopen;
70
+ const onclose = $props?.onclose;
71
+ const visible = $state.visible;
72
+ if (firstToggle) {
73
+ firstToggle = false;
74
+ } else {
75
+ if (ontoggle) ontoggle(visible);
76
+ if (visible) {
77
+ if (onopen) onopen()
78
+ } else {
79
+ if (onclose) onclose(result);
80
+ }
81
+ }
82
+ });
28
83
 
29
- document.body.appendChild(el);
30
- let result = fn(el);
31
- el.parentNode.removeChild(el);
84
+ function handleButton(type: "confirm" | "cancel" | undefined, value?: any) {
85
+ // Get the button's result
86
+ switch (type) {
87
+ case "confirm": {
88
+ result = value || true;
89
+ break;
90
+ }
91
+ case "cancel": {
92
+ result = value || false;
93
+ break;
94
+ }
95
+ default: {
96
+ result = value;
97
+ break;
98
+ }
99
+ }
32
100
 
33
- oldParent.appendChild(el, oldBefore);
34
- el.style.visibility = oldVisibility;
35
- el.style.position = oldPosition;
101
+ // Hide the drawer
102
+ $state.visible = false;
36
103
 
37
- return result;
104
+ // Call the callback
105
+ if ($props?.callback) {
106
+ $props?.callback(result);
107
+ }
38
108
  }
39
109
 
40
- function transitionArgs() {
41
- if (offscreen) {
42
- switch ($props.position) {
43
- case "left": {
44
- offscreen.style.left = 0;
45
- const width = measure(offscreen, (el) => el.offsetWidth);
46
- return [
47
- { transform: `translateX(-${width}px)` },
48
- { transform: "translateX(0px)" }
49
- ];
50
- }
51
- case "top": {
52
- offscreen.style.top = 0;
53
- const height = measure(offscreen, (el) => el.offsetHeight);
54
- return [
55
- { transform: `translateY(-${height}px)` },
56
- { transform: "translateY(0px)" }
57
- ];
58
- }
59
- case "right": {
60
- offscreen.style.right = 0;
61
- const width = measure(offscreen, (el) => el.offsetWidth);
62
- return [
63
- { transform: `translateX(${width}px)` },
64
- { transform: "translateX(0px)" }
65
- ];
66
- }
67
- case "bottom": {
68
- offscreen.style.bottom = 0;
69
- const height = measure(offscreen, (el) => el.offsetHeight);
70
- return [
71
- { transform: `translateY(${height}px)` },
72
- { transform: "translateY(0px)" }
73
- ];
74
- }
75
- }
76
- }
110
+ function handleClickOutside(e: MouseEvent) {
111
+ e.preventDefault();
112
+ $state.visible = false;
77
113
  }
78
114
 
79
115
  @render {
80
- @if ($props.visible) {
81
- <div
82
- {$props.id}
83
- class={`torp-offscreen ${$props.class ?? ""}`.trim()}
84
- style="position: fixed;"
85
- transition={transitionArgs()}
86
- &ref={offscreen}
87
- >
88
- <slot />
89
- </div>
90
- }
116
+ <div
117
+ {$props?.id}
118
+ class={`torp-drawer ${$props?.class ?? ""}`.trim()}
119
+ >
120
+ <slot />
121
+ </div>
91
122
  }
92
- }
123
+ }
@@ -0,0 +1,80 @@
1
+ import { type Animation } from "@torpor/view";
2
+ import { slide } from "../motion";
3
+ import { addDocumentEvent, removeDocumentEvent } from "../utils/documentEvents";
4
+ import { DrawerContextName, type DrawerContext } from "./DrawerTypes";
5
+
6
+ interface DrawerContentProps {
7
+ /** An ID for the root element */
8
+ id?: string;
9
+ /** Class name(s) for the root element */
10
+ class?: string,
11
+ }
12
+
13
+ /**
14
+ * The content that is displayed for a Drawer when it is open.
15
+ */
16
+ export default function DrawerContent($props: DrawerContentProps | undefined) {
17
+ let drawer: HTMLElement;
18
+ let shown = false;
19
+ let closeOnClick = false;
20
+
21
+ // Get stuff out of the DrawerContext
22
+ const context = $context[DrawerContextName] as DrawerContext;
23
+ if (!context) {
24
+ throw new Error("DrawerContent must be contained within a Drawer");
25
+ }
26
+ let $state = context.state;
27
+
28
+ $run(() => {
29
+ if (!$state.visible) {
30
+ hide();
31
+ }
32
+ });
33
+
34
+ function show() {
35
+ shown = true;
36
+
37
+ // HACK: Because this Drawer could be shown with a click, we need to wait for another mousedown
38
+ // before we close on click. Otherwise the click immediately bubbles to the document
39
+ closeOnClick = false;
40
+ addDocumentEvent("mousedown", handleDocumentMouseDown);
41
+ addDocumentEvent("click", handleDocumentClick);
42
+ }
43
+
44
+ function hide() {
45
+ if (!shown) return;
46
+
47
+ removeDocumentEvent("mousedown", handleDocumentMouseDown);
48
+ removeDocumentEvent("click", handleDocumentClick);
49
+ }
50
+
51
+ function handleDocumentMouseDown() {
52
+ closeOnClick = true;
53
+ }
54
+
55
+ function handleDocumentClick(e: MouseEvent) {
56
+ if (
57
+ closeOnClick &&
58
+ drawer &&
59
+ !drawer.contains(e.target as HTMLElement)
60
+ ) {
61
+ e.preventDefault();
62
+ context.handleClickOutside!(e);
63
+ }
64
+ }
65
+
66
+ @render {
67
+ @if ($state.visible) {
68
+ <div
69
+ {$props?.id}
70
+ class={`torp-drawer-content ${$props?.class ?? ""}`.trim()}
71
+ style="position: fixed;"
72
+ transition={(e) => slide(e, { side: $state.position })}
73
+ &ref={drawer}
74
+ onmount={show}
75
+ >
76
+ <slot />
77
+ </div>
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,38 @@
1
+ import { disableScroll } from "../mount/disableScroll";
2
+ import { DrawerContextName, type DrawerContext } from "./DrawerTypes";
3
+
4
+ interface DrawerOverlayProps {
5
+ /** An ID for the root element */
6
+ id?: string;
7
+ /** Class name(s) for the root element */
8
+ class?: string,
9
+ }
10
+
11
+ /**
12
+ * The background overlay for a Drawer component.
13
+ * Adding an overlay automatically sets the component's `modal` value to true.
14
+ */
15
+ export default function DrawerOverlay($props: DrawerOverlayProps | undefined) {
16
+ // Get stuff out of the DrawerContext
17
+ const context = $context[DrawerContextName] as DrawerContext;
18
+ if (!context) {
19
+ throw new Error("DrawerOverlay must be contained within a Drawer");
20
+ }
21
+ let $state = context.state;
22
+
23
+ // Any drawer with an overlay is modal
24
+ $state.modal = true;
25
+
26
+ @render {
27
+ @if ($state.visible) {
28
+ <div
29
+ {$props?.id}
30
+ class={`torp-drawer-overlay ${$props?.class ?? ""}`.trim()}
31
+ tabindex="-1"
32
+ onmount={(el) => disableScroll(el)}
33
+ >
34
+ <slot />
35
+ </div>
36
+ }
37
+ }
38
+ }
@@ -0,0 +1,35 @@
1
+ import { DrawerContextName, type DrawerContext } from "./DrawerTypes";
2
+
3
+ interface DrawerTriggerProps {
4
+ /** An ID for the root element */
5
+ id?: string;
6
+ /** Class name(s) for the root element */
7
+ class?: string,
8
+ }
9
+
10
+ /**
11
+ * The button that causes a Drawer to appear or disappear.
12
+ */
13
+ export default function DrawerTrigger($props: DrawerTriggerProps | undefined) {
14
+ // Get stuff out of the DrawerContext
15
+ const context = $context[DrawerContextName] as DrawerContext;
16
+ if (!context) {
17
+ throw new Error("DrawerTrigger must be contained within a Drawer");
18
+ }
19
+ let $state = context.state;
20
+
21
+ function handleClick() {
22
+ $state.visible = !$state.visible;
23
+ }
24
+
25
+ @render {
26
+ <button
27
+ type="button"
28
+ {$props?.id}
29
+ class={`torp-drawer-trigger ${$props?.class ?? ""}`.trim()}
30
+ onclick={handleClick}
31
+ >
32
+ <slot />
33
+ </button>
34
+ }
35
+ }
@@ -0,0 +1,24 @@
1
+ export const DrawerContextName = "Drawer";
2
+
3
+ /** The shared context for drawer components (Contextual, Prompt and Drawer) */
4
+ export interface DrawerContext {
5
+ handleButton: (type: "confirm" | "cancel" | undefined, value?: any) => void;
6
+ // HACK: We need to be able to let children (i.e. Dialogs) override the click outside functionality
7
+ // There may be a more elegant way to accomplish this too
8
+ handleClickOutside?: (e: MouseEvent) => void;
9
+ state: DrawerState;
10
+ // HACK: focusFirstElement is necessary because if we focus the first element e.g. in a Dialog's
11
+ // onMount, it will scroll the page to the focused element and mess up our careful positioning
12
+ // We need to be able to manually set the order to
13
+ // 1. set visible (so we have an element with content)
14
+ // 2. set position (so the element is in the right place)
15
+ // 3. set focus (for accessibility)
16
+ // There may be a more elegant way to accomplish this!
17
+ focusFirstElement?: () => void;
18
+ }
19
+
20
+ export interface DrawerState {
21
+ visible: boolean;
22
+ modal: boolean;
23
+ position: "left" | "right" | "top" | "bottom";
24
+ }
@@ -1,3 +1,6 @@
1
1
  import Drawer from "./Drawer.torp";
2
+ import DrawerContent from "./DrawerContent.torp";
3
+ import DrawerOverlay from "./DrawerOverlay.torp";
4
+ import DrawerTrigger from "./DrawerTrigger.torp";
2
5
 
3
- export { Drawer };
6
+ export { Drawer, DrawerContent, DrawerOverlay, DrawerTrigger };