@torpor/ui 0.2.0 → 0.3.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 (312) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/Accordion/Accordion.torp +44 -25
  3. package/dist/Accordion/AccordionContent.torp +18 -12
  4. package/dist/Accordion/AccordionHeader.torp +15 -8
  5. package/dist/Accordion/AccordionItem.torp +34 -17
  6. package/dist/Accordion/AccordionTrigger.torp +17 -10
  7. package/dist/Accordion/AccordionTypes.ts +6 -3
  8. package/dist/Accordion/index.d.ts +100 -35
  9. package/dist/Breadcrumb/Breadcrumb.torp +18 -10
  10. package/dist/Breadcrumb/BreadcrumbItem.torp +14 -7
  11. package/dist/Breadcrumb/BreadcrumbSeparator.torp +10 -3
  12. package/dist/Breadcrumb/index.d.ts +50 -21
  13. package/dist/Calendar/Calendar.torp +21 -14
  14. package/dist/Calendar/CalendarDay.torp +12 -4
  15. package/dist/Calendar/index.d.ts +16 -18
  16. package/dist/Contextual/Contextual.torp +125 -0
  17. package/dist/{Popover/PopoverContentContextual.torp → Contextual/ContextualContent.torp} +21 -12
  18. package/dist/Contextual/ContextualTrigger.torp +66 -0
  19. package/dist/Contextual/ContextualTypes.ts +30 -0
  20. package/dist/Contextual/index.d.ts +90 -0
  21. package/dist/Contextual/index.js +14 -0
  22. package/dist/Contextual/index.js.map +1 -0
  23. package/dist/Dialog/Dialog.torp +49 -73
  24. package/dist/Dialog/DialogBody.torp +15 -9
  25. package/dist/Dialog/DialogButton.torp +27 -13
  26. package/dist/Dialog/DialogFooter.torp +11 -3
  27. package/dist/Dialog/DialogHeader.torp +15 -8
  28. package/dist/Dialog/DialogTypes.ts +3 -2
  29. package/dist/Dialog/index.d.ts +83 -35
  30. package/dist/Disclosure/Disclosure.torp +34 -25
  31. package/dist/Disclosure/DisclosureContent.torp +18 -12
  32. package/dist/Disclosure/DisclosureHeader.torp +16 -9
  33. package/dist/Disclosure/DisclosureTrigger.torp +15 -8
  34. package/dist/Disclosure/DisclosureTypes.ts +0 -1
  35. package/dist/Disclosure/index.d.ts +67 -28
  36. package/dist/Drawer/Drawer.torp +109 -68
  37. package/dist/Drawer/DrawerContent.torp +80 -0
  38. package/dist/Drawer/DrawerOverlay.torp +38 -0
  39. package/dist/Drawer/DrawerTrigger.torp +35 -0
  40. package/dist/Drawer/DrawerTypes.ts +24 -0
  41. package/dist/Drawer/index.d.ts +96 -8
  42. package/dist/Drawer/index.js +13 -1
  43. package/dist/Form/Field.torp +91 -0
  44. package/dist/Form/Form.torp +129 -0
  45. package/dist/Form/FormTypes.ts +30 -0
  46. package/dist/Form/Input.torp +97 -0
  47. package/dist/Form/Label.torp +31 -0
  48. package/dist/Form/Message.torp +35 -0
  49. package/dist/Form/StandardSchemaV1.ts +70 -0
  50. package/dist/Form/index.d.ts +131 -0
  51. package/dist/Form/index.js +22 -0
  52. package/dist/Form/index.js.map +1 -0
  53. package/dist/Menu/Menu.torp +25 -15
  54. package/dist/Menu/MenuButton.torp +30 -13
  55. package/dist/Menu/MenuCheck.torp +29 -14
  56. package/dist/Menu/MenuGroup.torp +14 -6
  57. package/dist/Menu/MenuIndicator.torp +14 -7
  58. package/dist/Menu/MenuPopout.torp +23 -15
  59. package/dist/Menu/MenuPopoutContent.torp +17 -10
  60. package/dist/Menu/MenuPopoutTrigger.torp +23 -16
  61. package/dist/Menu/MenuRadio.torp +27 -16
  62. package/dist/Menu/MenuRadioGroup.torp +34 -15
  63. package/dist/Menu/MenuSeparator.torp +11 -3
  64. package/dist/Menu/MenuTypes.ts +7 -5
  65. package/dist/Menu/index.d.ts +176 -77
  66. package/dist/MenuBar/MenuBar.torp +24 -16
  67. package/dist/MenuBar/MenuBarItem.torp +24 -16
  68. package/dist/MenuBar/MenuBarItemContent.torp +18 -11
  69. package/dist/MenuBar/MenuBarItemTrigger.torp +15 -9
  70. package/dist/MenuBar/index.d.ts +79 -28
  71. package/dist/Modal/Modal.torp +118 -0
  72. package/dist/Modal/ModalContent.torp +77 -0
  73. package/dist/Modal/ModalOverlay.torp +38 -0
  74. package/dist/Modal/ModalTrigger.torp +50 -0
  75. package/dist/Modal/ModalTypes.ts +22 -0
  76. package/dist/Modal/index.d.ts +108 -0
  77. package/dist/Modal/index.js +33 -0
  78. package/dist/Modal/index.js.map +1 -0
  79. package/dist/Modal/showModal.ts +19 -0
  80. package/dist/Modal/showPrompt.ts +23 -0
  81. package/dist/NavMenu/NavMenu.torp +18 -10
  82. package/dist/NavMenu/NavMenuButton.torp +15 -10
  83. package/dist/NavMenu/NavMenuElement.torp +19 -11
  84. package/dist/NavMenu/NavMenuGroup.torp +13 -6
  85. package/dist/NavMenu/NavMenuGroupHeader.torp +15 -8
  86. package/dist/NavMenu/NavMenuLink.torp +21 -16
  87. package/dist/NavMenu/NavMenuPopout.torp +34 -18
  88. package/dist/NavMenu/NavMenuPopoutButton.torp +23 -18
  89. package/dist/NavMenu/NavMenuPopoutContent.torp +23 -13
  90. package/dist/NavMenu/NavMenuSeparator.torp +10 -3
  91. package/dist/NavMenu/index.d.ts +153 -70
  92. package/dist/Notification/Notification.torp +35 -16
  93. package/dist/Notification/NotificationClose.torp +10 -3
  94. package/dist/Notification/NotificationContainer.torp +11 -3
  95. package/dist/Notification/NotificationContent.torp +11 -3
  96. package/dist/Notification/index.d.ts +46 -28
  97. package/dist/Popover/Popover.torp +48 -28
  98. package/dist/Popover/PopoverContent.torp +42 -8
  99. package/dist/Popover/PopoverTrigger.torp +32 -3
  100. package/dist/Popover/PopoverTypes.ts +1 -1
  101. package/dist/Popover/index.d.ts +48 -111
  102. package/dist/Popover/index.js +1 -163
  103. package/dist/Popover/index.js.map +1 -1
  104. package/dist/TabGroup/TabContent.torp +20 -11
  105. package/dist/TabGroup/TabGroup.torp +58 -40
  106. package/dist/TabGroup/TabGroupTypes.ts +10 -5
  107. package/dist/TabGroup/TabHeader.torp +26 -10
  108. package/dist/TabGroup/TabList.torp +14 -7
  109. package/dist/TabGroup/TabTrigger.torp +17 -10
  110. package/dist/TabGroup/index.d.ts +101 -35
  111. package/dist/icons/ArrowDown.torp +5 -3
  112. package/dist/icons/ArrowLeft.torp +5 -3
  113. package/dist/icons/ArrowRight.torp +5 -3
  114. package/dist/icons/ArrowUp.torp +5 -3
  115. package/dist/icons/Bars.torp +5 -3
  116. package/dist/icons/Check.torp +5 -3
  117. package/dist/icons/ChevronDown.torp +5 -3
  118. package/dist/icons/ChevronLeft.torp +5 -3
  119. package/dist/icons/ChevronRight.torp +5 -3
  120. package/dist/icons/ChevronUp.torp +5 -3
  121. package/dist/icons/Cross.torp +5 -3
  122. package/dist/icons/IconTypes.ts +6 -0
  123. package/dist/icons/Loading.torp +5 -3
  124. package/dist/icons/Minus.torp +5 -3
  125. package/dist/icons/Plus.torp +5 -3
  126. package/dist/icons/index.d.ts +271 -126
  127. package/dist/index.d.ts +17 -4
  128. package/dist/metafile-esm.json +1 -1
  129. package/dist/motion/fade.ts +15 -6
  130. package/dist/motion/grow.ts +23 -0
  131. package/dist/motion/index.d.ts +19 -2
  132. package/dist/motion/index.js +93 -3
  133. package/dist/motion/index.js.map +1 -1
  134. package/dist/motion/measure.ts +28 -0
  135. package/dist/motion/slide.ts +45 -0
  136. package/dist/mount/clickPopover.ts +51 -0
  137. package/dist/mount/contextPopover.ts +51 -0
  138. package/dist/mount/hoverPopover.ts +58 -0
  139. package/package.json +28 -12
  140. package/scripts/postbuild.ts +11 -1
  141. package/src/Accordion/Accordion.torp +44 -25
  142. package/src/Accordion/AccordionContent.torp +18 -12
  143. package/src/Accordion/AccordionHeader.torp +15 -8
  144. package/src/Accordion/AccordionItem.torp +34 -17
  145. package/src/Accordion/AccordionTrigger.torp +17 -10
  146. package/src/Accordion/AccordionTypes.ts +6 -3
  147. package/src/Breadcrumb/Breadcrumb.torp +18 -10
  148. package/src/Breadcrumb/BreadcrumbItem.torp +14 -7
  149. package/src/Breadcrumb/BreadcrumbSeparator.torp +10 -3
  150. package/src/Calendar/Calendar.torp +21 -14
  151. package/src/Calendar/CalendarDay.torp +12 -4
  152. package/src/Contextual/Contextual.torp +125 -0
  153. package/src/{Popover/PopoverContentContextual.torp → Contextual/ContextualContent.torp} +21 -12
  154. package/src/Contextual/ContextualTrigger.torp +66 -0
  155. package/src/Contextual/ContextualTypes.ts +30 -0
  156. package/src/Contextual/index.ts +5 -0
  157. package/src/Dialog/Dialog.torp +49 -73
  158. package/src/Dialog/DialogBody.torp +15 -9
  159. package/src/Dialog/DialogButton.torp +27 -13
  160. package/src/Dialog/DialogFooter.torp +11 -3
  161. package/src/Dialog/DialogHeader.torp +15 -8
  162. package/src/Dialog/DialogTypes.ts +3 -2
  163. package/src/Disclosure/Disclosure.torp +34 -25
  164. package/src/Disclosure/DisclosureContent.torp +18 -12
  165. package/src/Disclosure/DisclosureHeader.torp +16 -9
  166. package/src/Disclosure/DisclosureTrigger.torp +15 -8
  167. package/src/Disclosure/DisclosureTypes.ts +0 -1
  168. package/src/Drawer/Drawer.torp +109 -68
  169. package/src/Drawer/DrawerContent.torp +80 -0
  170. package/src/Drawer/DrawerOverlay.torp +38 -0
  171. package/src/Drawer/DrawerTrigger.torp +35 -0
  172. package/src/Drawer/DrawerTypes.ts +24 -0
  173. package/src/Drawer/index.ts +4 -1
  174. package/src/Form/Field.torp +91 -0
  175. package/src/Form/Form.torp +129 -0
  176. package/src/Form/FormTypes.ts +30 -0
  177. package/src/Form/Input.torp +97 -0
  178. package/src/Form/Label.torp +31 -0
  179. package/src/Form/Message.torp +35 -0
  180. package/src/Form/StandardSchemaV1.ts +70 -0
  181. package/src/Form/index.ts +7 -0
  182. package/src/Menu/Menu.torp +25 -15
  183. package/src/Menu/MenuButton.torp +30 -13
  184. package/src/Menu/MenuCheck.torp +29 -14
  185. package/src/Menu/MenuGroup.torp +14 -6
  186. package/src/Menu/MenuIndicator.torp +14 -7
  187. package/src/Menu/MenuPopout.torp +23 -15
  188. package/src/Menu/MenuPopoutContent.torp +17 -10
  189. package/src/Menu/MenuPopoutTrigger.torp +23 -16
  190. package/src/Menu/MenuRadio.torp +27 -16
  191. package/src/Menu/MenuRadioGroup.torp +34 -15
  192. package/src/Menu/MenuSeparator.torp +11 -3
  193. package/src/Menu/MenuTypes.ts +7 -5
  194. package/src/MenuBar/MenuBar.torp +24 -16
  195. package/src/MenuBar/MenuBarItem.torp +24 -16
  196. package/src/MenuBar/MenuBarItemContent.torp +18 -11
  197. package/src/MenuBar/MenuBarItemTrigger.torp +15 -9
  198. package/src/Modal/Modal.torp +118 -0
  199. package/src/Modal/ModalContent.torp +77 -0
  200. package/src/Modal/ModalOverlay.torp +38 -0
  201. package/src/Modal/ModalTrigger.torp +50 -0
  202. package/src/Modal/ModalTypes.ts +22 -0
  203. package/src/Modal/index.ts +10 -0
  204. package/src/Modal/showModal.ts +19 -0
  205. package/src/Modal/showPrompt.ts +23 -0
  206. package/src/NavMenu/NavMenu.torp +18 -10
  207. package/src/NavMenu/NavMenuButton.torp +15 -10
  208. package/src/NavMenu/NavMenuElement.torp +19 -11
  209. package/src/NavMenu/NavMenuGroup.torp +13 -6
  210. package/src/NavMenu/NavMenuGroupHeader.torp +15 -8
  211. package/src/NavMenu/NavMenuLink.torp +21 -16
  212. package/src/NavMenu/NavMenuPopout.torp +34 -18
  213. package/src/NavMenu/NavMenuPopoutButton.torp +23 -18
  214. package/src/NavMenu/NavMenuPopoutContent.torp +23 -13
  215. package/src/NavMenu/NavMenuSeparator.torp +10 -3
  216. package/src/Notification/Notification.torp +35 -16
  217. package/src/Notification/NotificationClose.torp +10 -3
  218. package/src/Notification/NotificationContainer.torp +11 -3
  219. package/src/Notification/NotificationContent.torp +11 -3
  220. package/src/Popover/Popover.torp +48 -28
  221. package/src/Popover/PopoverContent.torp +42 -8
  222. package/src/Popover/PopoverTrigger.torp +32 -3
  223. package/src/Popover/PopoverTypes.ts +1 -1
  224. package/src/Popover/index.ts +1 -24
  225. package/src/Slider/Slider.torp +3 -3
  226. package/src/TabGroup/TabContent.torp +20 -11
  227. package/src/TabGroup/TabGroup.torp +58 -40
  228. package/src/TabGroup/TabGroupTypes.ts +10 -5
  229. package/src/TabGroup/TabHeader.torp +26 -10
  230. package/src/TabGroup/TabList.torp +14 -7
  231. package/src/TabGroup/TabTrigger.torp +17 -10
  232. package/src/icons/ArrowDown.torp +5 -3
  233. package/src/icons/ArrowLeft.torp +5 -3
  234. package/src/icons/ArrowRight.torp +5 -3
  235. package/src/icons/ArrowUp.torp +5 -3
  236. package/src/icons/Bars.torp +5 -3
  237. package/src/icons/Check.torp +5 -3
  238. package/src/icons/ChevronDown.torp +5 -3
  239. package/src/icons/ChevronLeft.torp +5 -3
  240. package/src/icons/ChevronRight.torp +5 -3
  241. package/src/icons/ChevronUp.torp +5 -3
  242. package/src/icons/Cross.torp +5 -3
  243. package/src/icons/IconTypes.ts +6 -0
  244. package/src/icons/Loading.torp +5 -3
  245. package/src/icons/Minus.torp +5 -3
  246. package/src/icons/Plus.torp +5 -3
  247. package/src/motion/fade.ts +15 -6
  248. package/src/motion/grow.ts +23 -0
  249. package/src/motion/index.ts +4 -1
  250. package/src/motion/measure.ts +28 -0
  251. package/src/motion/slide.ts +45 -0
  252. package/src/mount/clickPopover.ts +51 -0
  253. package/src/mount/contextPopover.ts +51 -0
  254. package/src/mount/hoverPopover.ts +58 -0
  255. package/test/Accordion/components/AccordionAccessibility.torp +1 -1
  256. package/test/Accordion/components/AccordionKeyboard.torp +1 -1
  257. package/test/Accordion/components/AccordionList.torp +1 -1
  258. package/test/Accordion/components/AccordionMultiple.torp +2 -2
  259. package/test/Accordion/components/AccordionSingle.torp +2 -2
  260. package/test/Dialog/accessibility-modal.test.ts +2 -2
  261. package/test/Dialog/components/DialogAccessibility.torp +8 -14
  262. package/test/Dialog/components/DialogFunction.torp +20 -4
  263. package/test/Dialog/components/DialogModal.torp +30 -0
  264. package/test/Dialog/components/DialogVariable.torp +7 -7
  265. package/test/Disclosure/accessibility.test.ts +3 -2
  266. package/test/Disclosure/components/DisclosureTest.torp +1 -1
  267. package/test/Disclosure/toggle.test.ts +3 -2
  268. package/test/Form/components/FieldTest.torp +25 -0
  269. package/test/Form/components/FormTest.torp +31 -0
  270. package/test/Form/components/InputTest.torp +9 -0
  271. package/test/Form/field.test.ts +34 -0
  272. package/test/Form/form.test.ts +34 -0
  273. package/test/Form/input.test.ts +19 -0
  274. package/test/Menu/accessibility.test.ts +3 -2
  275. package/test/Menu/basic.test.ts +11 -10
  276. package/test/Menu/components/MenuAccessibility.torp +5 -5
  277. package/test/Menu/components/MenuBasic.torp +5 -5
  278. package/test/MenuBar/accessibility.test.ts +3 -2
  279. package/test/MenuBar/basic.test.ts +3 -2
  280. package/test/NavMenu/basic.test.ts +1 -1
  281. package/test/NavMenu/components/{NavMenu.torp → NavMenuBasic.torp} +1 -1
  282. package/test/Notification/components/NotificationFunction.torp +0 -3
  283. package/test/Notification/components/NotificationVariable.torp +1 -1
  284. package/test/Popover/components/PopoverFunction.torp +37 -0
  285. package/test/Popover/components/PopoverTrigger.torp +36 -0
  286. package/test/Popover/components/{PromptVariable.torp → PopoverVariable.torp} +5 -3
  287. package/test/Popover/function.test.ts +2 -7
  288. package/test/Popover/trigger.test.ts +27 -0
  289. package/test/Popover/variable.test.ts +2 -2
  290. package/test/TabGroup/components/TabGroupAccessibility.torp +1 -1
  291. package/test/TabGroup/components/TabGroupKeyboard.torp +1 -1
  292. package/test/TabGroup/components/TabGroupList.torp +1 -1
  293. package/test/TabGroup/components/TabGroupTrigger.torp +1 -1
  294. package/tsup.config.ts +3 -1
  295. package/dist/Popover/PopoverContentAnchored.torp +0 -106
  296. package/dist/Popover/PopoverOverlay.torp +0 -30
  297. package/dist/Popover/PopoverTriggerContextual.torp +0 -37
  298. package/dist/Popover/PopoverTriggerHover.torp +0 -38
  299. package/dist/Popover/mountClickPopover.ts +0 -50
  300. package/dist/Popover/mountContextPopover.ts +0 -50
  301. package/dist/Popover/mountHoverPopover.ts +0 -57
  302. package/dist/Popover/showPopoverPrompt.ts +0 -23
  303. package/src/Popover/PopoverContentAnchored.torp +0 -106
  304. package/src/Popover/PopoverOverlay.torp +0 -30
  305. package/src/Popover/PopoverTriggerContextual.torp +0 -37
  306. package/src/Popover/PopoverTriggerHover.torp +0 -38
  307. package/src/Popover/mountClickPopover.ts +0 -50
  308. package/src/Popover/mountContextPopover.ts +0 -50
  309. package/src/Popover/mountHoverPopover.ts +0 -57
  310. package/src/Popover/showPopoverPrompt.ts +0 -23
  311. package/test/Dialog/components/CustomDialog.torp +0 -20
  312. package/test/Popover/components/PromptFunction.torp +0 -19
@@ -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,20 +1,108 @@
1
1
  import { type SlotRender } from "@torpor/view";
2
2
 
3
3
 
4
+ interface DrawerProps {
5
+ /** An ID for the root element */
6
+ id?: string;
7
+ /** Class name(s) for the root element */
8
+ class?: string,
9
+ /** 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 */
10
+ modal?: boolean,
11
+ /** Whether the drawer is visible */
12
+ visible?: boolean,
13
+ /** Which side of the window to show the drawer from */
14
+ position?: "left" | "right" | "top" | "bottom",
15
+ /** A function to be called when the user selects a response */
16
+ callback?: ((value: any) => void),
17
+ /** Raised when the drawer is opened or closed */
18
+ ontoggle?: (open: boolean) => void,
19
+ /** Raised when the drawer has opened */
20
+ onopen?: () => void,
21
+ /** Raised when the drawer has closed */
22
+ onclose?: (result: any) => void,
23
+ }
24
+
4
25
  /**
5
- * Mounts or hydrates the component into the supplied parent node.
6
- * @param $parent -- The parent node.
7
- * @param $anchor -- The node to mount the component before.
8
- * @param $props -- The values that have been passed into the component as properties.
9
- * @param $context -- Values that have been passed into the component from its ancestors.
10
- * @param $slots -- Functions for rendering children into slot nodes within the component.
26
+ * A drawer that can be used to show rich content or obtain information from a user.
27
+ *
28
+ * See [the WAI ARIA guidelines for Dialogs](https://www.w3.org/WAI/ARIA/apg/patterns/dialogmodal/).
29
+ *
30
+ * The structure of a Drawer is:
31
+ *
32
+ * ```
33
+ * <Drawer>
34
+ * <DrawerTrigger /> (optional)
35
+ * <DrawerContent />
36
+ * </Drawer>
37
+ * ```
11
38
  */
12
39
  declare function Drawer(
13
40
  $parent: ParentNode,
14
41
  $anchor: Node | null,
15
- $props: any,
42
+ $props: DrawerProps | undefined,
43
+ $context?: Record<PropertyKey, any>,
44
+ $slots?: Record<string, SlotRender>,
45
+ ): void;
46
+
47
+
48
+
49
+ interface DrawerContentProps {
50
+ /** An ID for the root element */
51
+ id?: string;
52
+ /** Class name(s) for the root element */
53
+ class?: string,
54
+ }
55
+
56
+ /**
57
+ * The content that is displayed for a Drawer when it is open.
58
+ */
59
+ declare function DrawerContent(
60
+ $parent: ParentNode,
61
+ $anchor: Node | null,
62
+ $props: DrawerContentProps | undefined,
63
+ $context?: Record<PropertyKey, any>,
64
+ $slots?: Record<string, SlotRender>,
65
+ ): void;
66
+
67
+
68
+
69
+ interface DrawerOverlayProps {
70
+ /** An ID for the root element */
71
+ id?: string;
72
+ /** Class name(s) for the root element */
73
+ class?: string,
74
+ }
75
+
76
+ /**
77
+ * The background overlay for a Drawer component.
78
+ * Adding an overlay automatically sets the component's `modal` value to true.
79
+ */
80
+ declare function DrawerOverlay(
81
+ $parent: ParentNode,
82
+ $anchor: Node | null,
83
+ $props: DrawerOverlayProps | undefined,
84
+ $context?: Record<PropertyKey, any>,
85
+ $slots?: Record<string, SlotRender>,
86
+ ): void;
87
+
88
+
89
+
90
+ interface DrawerTriggerProps {
91
+ /** An ID for the root element */
92
+ id?: string;
93
+ /** Class name(s) for the root element */
94
+ class?: string,
95
+ }
96
+
97
+ /**
98
+ * The button that causes a Drawer to appear or disappear.
99
+ */
100
+ declare function DrawerTrigger(
101
+ $parent: ParentNode,
102
+ $anchor: Node | null,
103
+ $props: DrawerTriggerProps | undefined,
16
104
  $context?: Record<PropertyKey, any>,
17
105
  $slots?: Record<string, SlotRender>,
18
106
  ): void;
19
107
 
20
- export { Drawer };
108
+ export { Drawer, DrawerContent, DrawerOverlay, DrawerTrigger };
@@ -1,6 +1,18 @@
1
1
  // src/Drawer/Drawer.torp
2
2
  import Drawer_default from "./Drawer.torp";
3
+
4
+ // src/Drawer/DrawerContent.torp
5
+ import DrawerContent_default from "./DrawerContent.torp";
6
+
7
+ // src/Drawer/DrawerOverlay.torp
8
+ import DrawerOverlay_default from "./DrawerOverlay.torp";
9
+
10
+ // src/Drawer/DrawerTrigger.torp
11
+ import DrawerTrigger_default from "./DrawerTrigger.torp";
3
12
  export {
4
- Drawer_default as Drawer
13
+ Drawer_default as Drawer,
14
+ DrawerContent_default as DrawerContent,
15
+ DrawerOverlay_default as DrawerOverlay,
16
+ DrawerTrigger_default as DrawerTrigger
5
17
  };
6
18
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,91 @@
1
+ import {
2
+ FormContextName,
3
+ FieldContextName,
4
+ type ValidationIssue,
5
+ type FormContext,
6
+ type FieldContext,
7
+ } from "./FormTypes";
8
+ import { StandardSchemaV1 } from "./StandardSchemaV1"
9
+
10
+ interface FieldProps {
11
+ /** An ID for the root element */
12
+ id?: string;
13
+ /** Class name(s) for the root element */
14
+ class?: string,
15
+ /** The name of the data that this field contains */
16
+ name: string,
17
+ /** The data value that this field is bound to */
18
+ value?: any,
19
+ /** The schema validator to use for this form */
20
+ schema?: StandardSchemaV1,
21
+ };
22
+
23
+ /**
24
+ * A field in a form which automatically links up a Label and/or an input
25
+ * component and/or a Message.
26
+ */
27
+ export default function Field($props: FieldProps) {
28
+ let $state = $watch({
29
+ inputId: "-1",
30
+ value: $props.value,
31
+ issues: [] as ValidationIssue[],
32
+ get valid() {
33
+ return this.issues.find((i) => i.path === $props.name) === undefined;
34
+ },
35
+ get message() {
36
+ return this.issues.filter((i) => i.path === $props.name).map((i) => i.message).join("\n");
37
+ },
38
+ });
39
+
40
+ // Binding
41
+ $run(() => {
42
+ $props.value = $state.value;
43
+ });
44
+
45
+ // Get stuff out of the FormContext, if applicable
46
+ const formContext = $context[FormContextName] as FormContext;
47
+ if (formContext) {
48
+ $run(() => {
49
+ $state.issues = formContext.state.issues;
50
+ });
51
+ }
52
+
53
+ // Set the context to pass down to Labels, Inputs and Messages
54
+ let context: FieldContext = {
55
+ name: $props.name,
56
+ state: $state,
57
+ validate: handleValidate
58
+ };
59
+ $context[FieldContextName] = context;
60
+
61
+ async function validate() {
62
+ if ($props.schema) {
63
+ const validator = $props.schema["~standard"];
64
+ let result = validator.validate($props.value);
65
+ if (result instanceof Promise) {
66
+ result = await result;
67
+ }
68
+ let issues: ValidationIssue[] = [];
69
+ if (result.issues) {
70
+ for (let issue of result.issues) {
71
+ issues.push({ path: $props.name, message: issue.message });
72
+ }
73
+ }
74
+ $state.issues = $state.issues.filter((e) => e.path !== $props.name).concat(issues);
75
+ }
76
+ }
77
+
78
+ async function handleValidate() {
79
+ await validate();
80
+ }
81
+
82
+ @render {
83
+ <div
84
+ {$props?.id}
85
+ class={`torp-field ${$props?.class ?? ""}`.trim()}
86
+ data-valid={$state.valid ? "valid" : "invalid"}
87
+ >
88
+ <slot />
89
+ </div>
90
+ }
91
+ }
@@ -0,0 +1,129 @@
1
+ import { FormContextName, type ValidationIssue, type FormContext } from "./FormTypes";
2
+ import { StandardSchemaV1 } from "./StandardSchemaV1"
3
+
4
+ interface FormProps {
5
+ /** An ID for the root element */
6
+ id?: string;
7
+ /** Class name(s) for the root element */
8
+ class?: string,
9
+ /** The data to display in the form */
10
+ data?: any,
11
+ /** Where to post the form's data **/
12
+ action?: string,
13
+ /** The schema validator to use for this form */
14
+ schema?: StandardSchemaV1,
15
+ onsubmit?: (e: SubmitEvent) => boolean | void | Promise<boolean | void>,
16
+ };
17
+
18
+ /**
19
+ * A form for submitting values.
20
+ */
21
+ export default function Form($props: FormProps | undefined) {
22
+ let $state = $watch({
23
+ data: $props?.data ?? {},
24
+ issues: [] as ValidationIssue[],
25
+ get valid() {
26
+ return this.issues.length === 0;
27
+ }
28
+ });
29
+
30
+ let submitted = false;
31
+
32
+ // TODO: Load context from build with a submit method that submits to a form action
33
+
34
+ // Set the context to pass down to Fields
35
+ let context: FormContext = {
36
+ schema: $props?.schema,
37
+ state: $state,
38
+ validate: handleValidate
39
+ };
40
+
41
+ $context[FormContextName] = context;
42
+
43
+ async function validate() {
44
+ if ($props?.schema) {
45
+ const validator = $props.schema["~standard"];
46
+ let result = validator.validate($props.data);
47
+ if (result instanceof Promise) {
48
+ result = await result;
49
+ }
50
+ let issues: ValidationIssue[] = [];
51
+ if (result.issues) {
52
+ for (let issue of result.issues) {
53
+ if (issue.path) {
54
+ // TODO: arrays with `[0]`
55
+ issues.push({ path: issue.path.join("."), message: issue.message });
56
+ }
57
+ }
58
+ }
59
+ $state.issues = issues;
60
+ }
61
+ }
62
+
63
+ async function handleSubmit(e: SubmitEvent) {
64
+ // Validate, and proceed with submission if there are no errors
65
+ await validate();
66
+ let proceed = $state.valid;
67
+
68
+ // Changing inputs from now on will cause revalidation
69
+ submitted = true;
70
+
71
+ // If validation failed, don't continue
72
+ if (!proceed) {
73
+ e.preventDefault();
74
+ return false;
75
+ }
76
+
77
+ // Dispatch the submit event for the user to handle
78
+ if ($props?.onsubmit) {
79
+ let userSubmit = $props.onsubmit(e);
80
+ if (userSubmit instanceof Promise) {
81
+ userSubmit = await userSubmit;
82
+ }
83
+ proceed = userSubmit !== false && !e.defaultPrevented;
84
+ }
85
+
86
+ // If the user handled the submit, don't continue
87
+ if (!proceed) {
88
+ e.preventDefault();
89
+ return false;
90
+ }
91
+
92
+ // If there's a @torpor/build context, call its submit event
93
+ let buildContext = $context["TorporBuildContext"];
94
+ if (buildContext?.onformsubmit) {
95
+ let buildSubmit = buildContext.onformsubmit(e);
96
+ if (buildSubmit instanceof Promise) {
97
+ buildSubmit = await buildSubmit;
98
+ }
99
+ proceed = buildSubmit !== false && !e.defaultPrevented;
100
+ }
101
+
102
+ // If @torpor/build handled the submit, don't continue
103
+ if (!proceed) {
104
+ e.preventDefault();
105
+ return false;
106
+ }
107
+
108
+ // Otherwise just let normal form submission go ahead...
109
+ }
110
+
111
+ async function handleValidate() {
112
+ if (submitted) {
113
+ await validate();
114
+ }
115
+ }
116
+
117
+ @render {
118
+ <form
119
+ {$props?.id}
120
+ class={`torp-form ${$props?.class ?? ""}`.trim()}
121
+ method="POST"
122
+ onsubmit={handleSubmit}
123
+ @// Set novalidate only if JS is enabled (to override HTML validation)
124
+ onmount={(e) => e.novalidate = true }
125
+ >
126
+ <slot />
127
+ </form>
128
+ }
129
+ }
@@ -0,0 +1,30 @@
1
+ import { type StandardSchemaV1 } from "./StandardSchemaV1";
2
+
3
+ export const FormContextName: unique symbol = Symbol("Form");
4
+ export const FieldContextName: unique symbol = Symbol("Field");
5
+
6
+ export interface ValidationIssue {
7
+ path: string;
8
+ message: string;
9
+ }
10
+
11
+ export interface FormContext {
12
+ schema?: StandardSchemaV1;
13
+ state: {
14
+ issues: ValidationIssue[];
15
+ };
16
+ validate: () => void;
17
+ }
18
+
19
+ export interface FieldContext {
20
+ name: string;
21
+ schema?: StandardSchemaV1;
22
+ state: {
23
+ inputId: string;
24
+ value?: any;
25
+ issues: ValidationIssue[];
26
+ valid: boolean;
27
+ message: string;
28
+ };
29
+ validate: () => void;
30
+ }
@@ -0,0 +1,97 @@
1
+ import getId from "../utils/getId";
2
+ import { FormContextName, FieldContextName, type FormContext, type FieldContext } from "./FormTypes";
3
+
4
+ interface InputProps {
5
+ /** An ID for the root element */
6
+ id?: string;
7
+ /** Class name(s) for the root element */
8
+ class?: string,
9
+ /** The input type */
10
+ type?: "text" | "number" | "password" | "email" | "url" | "tel",
11
+ /** The name of the input's form data field */
12
+ name?: string,
13
+ /** The data value that this field is bound to */
14
+ value?: any,
15
+ /** Text to display when the input value is empty */
16
+ placeholder?: string,
17
+ /** Whether the input should be readonly */
18
+ readonly?: boolean,
19
+ /** The maximum number of characters allowed for the input value */
20
+ maxlength?: number,
21
+ /** An ARIA label for describing the input to screen readers when there is no associated label element */
22
+ ariaLabel?: string,
23
+ };
24
+
25
+ /**
26
+ * A standard input in a form.
27
+ */
28
+ export default function Input($props: InputProps | undefined) {
29
+ let defaultId = getId();
30
+
31
+ let type = $props?.type ?? "text";
32
+ let name = $props?.name
33
+
34
+ let blurred = false;
35
+
36
+ // Get stuff out of the FormContext and FieldContext
37
+ const formContext = $context[FormContextName] as FormContext;
38
+ const fieldContext = $context[FieldContextName] as FieldContext;
39
+ if (fieldContext) {
40
+ name ??= fieldContext.name;
41
+ }
42
+
43
+ // Use the FieldContext's state, or create a new one
44
+ let $state = fieldContext?.state ?? $watch({
45
+ inputId: $props?.id ?? defaultId,
46
+ value: $props?.value,
47
+ errors: {} as Record<string, string>,
48
+ valid: false,
49
+ message: "",
50
+ });
51
+
52
+ // Binding
53
+ $run(() => {
54
+ if ($props !== undefined) {
55
+ $props.value = $state.value;
56
+ }
57
+ });
58
+
59
+ // Set the input ID now that we know it and it will get linked with the associated label
60
+ $state.inputId = $props?.id ?? defaultId;
61
+
62
+ // NOTE: Adapted this from https://stackoverflow.com/a/57393751,
63
+ // not sure if it's still a good way to do things
64
+ function handleInput(e: Event & { currentTarget: EventTarget & HTMLInputElement }) {
65
+ $state.value = $props!.type?.match(/^(number|range)$/) ? +e.currentTarget.value : e.currentTarget.value;
66
+ if (formContext) {
67
+ formContext.validate();
68
+ }
69
+ if (fieldContext && blurred) {
70
+ fieldContext.validate();
71
+ }
72
+ }
73
+
74
+ function handleBlur() {
75
+ if (fieldContext) {
76
+ fieldContext.validate();
77
+ }
78
+ blurred = true;
79
+ }
80
+
81
+ @render {
82
+ <input
83
+ id={$props?.id ?? defaultId}
84
+ class={`torp-input ${$props?.class ?? ""}`.trim()}
85
+ {type}
86
+ {name}
87
+ &value={$state.value}
88
+ {$props?.placeholder}
89
+ {$props?.readonly}
90
+ {$props?.maxlength}
91
+ aria-label={$props?.ariaLabel}
92
+ data-valid={$state.valid ? "valid" : "invalid"}
93
+ oninput={handleInput}
94
+ onblur={handleBlur}
95
+ />
96
+ }
97
+ }
@@ -0,0 +1,31 @@
1
+ import { FieldContextName, type FieldContext } from "./FormTypes";
2
+
3
+ interface LabelProps {
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
+ * A label to describe the contents of an input in a form.
12
+ */
13
+ export default function Label($props: LabelProps | undefined) {
14
+ // Get stuff out of the FieldContext
15
+ const context = $context[FieldContextName] as FieldContext;
16
+ if (!context) {
17
+ throw new Error("Label must be contained within a Field");
18
+ }
19
+ let { state: $state } = context;
20
+
21
+ @render {
22
+ <label
23
+ {$props?.id}
24
+ class={`torp-label ${$props?.class ?? ""}`.trim()}
25
+ for={$state.inputId}
26
+ data-valid={$state.valid ? "valid" : "invalid"}
27
+ >
28
+ <slot />
29
+ </label>
30
+ }
31
+ }
@@ -0,0 +1,35 @@
1
+ import { FieldContextName, type FieldContext } from "./FormTypes";
2
+
3
+ interface MessageProps {
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
+ * A validation message to show when the contents of an input component have
12
+ * problems that need to be fixed.
13
+ */
14
+ export default function Message($props: MessageProps | undefined) {
15
+ // Get stuff out of the FieldContext
16
+ const context = $context[FieldContextName] as FieldContext;
17
+ if (!context) {
18
+ throw new Error("Message must be contained within a Field");
19
+ }
20
+ const { state: $state } = context;
21
+
22
+ @render {
23
+ @if ($state.message) {
24
+ <div
25
+ {$props?.id}
26
+ class={`torp-message ${$props?.class ?? ""}`.trim()}
27
+ data-valid={$state.valid ? "valid" : "invalid"}
28
+ >
29
+ <slot name="message">
30
+ {$state.message}
31
+ </slot>
32
+ </div>
33
+ }
34
+ }
35
+ }