shelving 1.199.2 → 1.200.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 (394) hide show
  1. package/index.js +1 -0
  2. package/package.json +10 -5
  3. package/ui/app/App.d.ts +11 -0
  4. package/ui/app/App.js +21 -0
  5. package/ui/app/App.module.css +168 -0
  6. package/ui/app/App.tsx +26 -0
  7. package/ui/app/index.d.ts +1 -0
  8. package/ui/app/index.js +1 -0
  9. package/ui/app/index.ts +1 -0
  10. package/ui/block/Address.d.ts +20 -0
  11. package/ui/block/Address.js +17 -0
  12. package/ui/block/Address.module.css +20 -0
  13. package/ui/block/Address.tsx +47 -0
  14. package/ui/block/Blockquote.d.ts +5 -0
  15. package/ui/block/Blockquote.js +5 -0
  16. package/ui/block/Blockquote.module.css +21 -0
  17. package/ui/block/Blockquote.tsx +10 -0
  18. package/ui/block/Card.d.ts +10 -0
  19. package/ui/block/Card.js +7 -0
  20. package/ui/block/Card.module.css +32 -0
  21. package/ui/block/Card.tsx +18 -0
  22. package/ui/block/Divider.d.ts +6 -0
  23. package/ui/block/Divider.js +5 -0
  24. package/ui/block/Divider.module.css +19 -0
  25. package/ui/block/Divider.tsx +11 -0
  26. package/ui/block/Element.d.ts +9 -0
  27. package/ui/block/Element.js +7 -0
  28. package/ui/block/Element.module.css +12 -0
  29. package/ui/block/Element.tsx +14 -0
  30. package/ui/block/Elements.d.ts +27 -0
  31. package/ui/block/Elements.js +10 -0
  32. package/ui/block/Elements.module.css +70 -0
  33. package/ui/block/Elements.tsx +44 -0
  34. package/ui/block/Figure.d.ts +6 -0
  35. package/ui/block/Figure.js +5 -0
  36. package/ui/block/Figure.module.css +27 -0
  37. package/ui/block/Figure.tsx +16 -0
  38. package/ui/block/Heading.d.ts +6 -0
  39. package/ui/block/Heading.js +7 -0
  40. package/ui/block/Heading.module.css +23 -0
  41. package/ui/block/Heading.tsx +13 -0
  42. package/ui/block/Image.d.ts +6 -0
  43. package/ui/block/Image.js +5 -0
  44. package/ui/block/Image.module.css +20 -0
  45. package/ui/block/Image.tsx +11 -0
  46. package/ui/block/List.d.ts +6 -0
  47. package/ui/block/List.js +6 -0
  48. package/ui/block/List.module.css +30 -0
  49. package/ui/block/List.tsx +12 -0
  50. package/ui/block/Paragraph.d.ts +15 -0
  51. package/ui/block/Paragraph.js +7 -0
  52. package/ui/block/Paragraph.module.css +36 -0
  53. package/ui/block/Paragraph.tsx +21 -0
  54. package/ui/block/Preformatted.d.ts +5 -0
  55. package/ui/block/Preformatted.js +5 -0
  56. package/ui/block/Preformatted.module.css +23 -0
  57. package/ui/block/Preformatted.tsx +10 -0
  58. package/ui/block/Prose.d.ts +6 -0
  59. package/ui/block/Prose.js +28 -0
  60. package/ui/block/Prose.module.css +15 -0
  61. package/ui/block/Prose.tsx +56 -0
  62. package/ui/block/Section.d.ts +28 -0
  63. package/ui/block/Section.js +26 -0
  64. package/ui/block/Section.module.css +28 -0
  65. package/ui/block/Section.tsx +53 -0
  66. package/ui/block/Subheading.d.ts +3 -0
  67. package/ui/block/Subheading.js +7 -0
  68. package/ui/block/Subheading.module.css +23 -0
  69. package/ui/block/Subheading.tsx +10 -0
  70. package/ui/block/Table.d.ts +5 -0
  71. package/ui/block/Table.js +5 -0
  72. package/ui/block/Table.module.css +85 -0
  73. package/ui/block/Table.tsx +14 -0
  74. package/ui/block/Video.d.ts +36 -0
  75. package/ui/block/Video.js +43 -0
  76. package/ui/block/Video.module.css +103 -0
  77. package/ui/block/Video.tsx +91 -0
  78. package/ui/block/index.d.ts +17 -0
  79. package/ui/block/index.js +17 -0
  80. package/ui/block/index.ts +17 -0
  81. package/ui/dialog/Dialog.d.ts +13 -0
  82. package/ui/dialog/Dialog.js +28 -0
  83. package/ui/dialog/Dialog.module.css +29 -0
  84. package/ui/dialog/Dialog.tsx +57 -0
  85. package/ui/dialog/Dialogs.d.ts +23 -0
  86. package/ui/dialog/Dialogs.js +43 -0
  87. package/ui/dialog/Dialogs.tsx +64 -0
  88. package/ui/dialog/Modal.d.ts +5 -0
  89. package/ui/dialog/Modal.js +5 -0
  90. package/ui/dialog/Modal.module.css +11 -0
  91. package/ui/dialog/Modal.tsx +10 -0
  92. package/ui/dialog/index.d.ts +3 -0
  93. package/ui/dialog/index.js +3 -0
  94. package/ui/dialog/index.ts +3 -0
  95. package/ui/form/ArrayInput.d.ts +13 -0
  96. package/ui/form/ArrayInput.js +23 -0
  97. package/ui/form/ArrayInput.tsx +90 -0
  98. package/ui/form/ArrayRadioInputs.d.ts +15 -0
  99. package/ui/form/ArrayRadioInputs.js +16 -0
  100. package/ui/form/ArrayRadioInputs.tsx +53 -0
  101. package/ui/form/Button.d.ts +24 -0
  102. package/ui/form/Button.js +21 -0
  103. package/ui/form/Button.module.css +83 -0
  104. package/ui/form/Button.tsx +48 -0
  105. package/ui/form/ButtonInput.d.ts +7 -0
  106. package/ui/form/ButtonInput.js +19 -0
  107. package/ui/form/ButtonInput.tsx +33 -0
  108. package/ui/form/ButtonInputPopover.d.ts +16 -0
  109. package/ui/form/ButtonInputPopover.js +17 -0
  110. package/ui/form/ButtonInputPopover.tsx +32 -0
  111. package/ui/form/ButtonPopover.d.ts +16 -0
  112. package/ui/form/ButtonPopover.js +17 -0
  113. package/ui/form/ButtonPopover.tsx +31 -0
  114. package/ui/form/CheckboxInput.d.ts +7 -0
  115. package/ui/form/CheckboxInput.js +8 -0
  116. package/ui/form/CheckboxInput.tsx +37 -0
  117. package/ui/form/ChoiceRadioInputs.d.ts +17 -0
  118. package/ui/form/ChoiceRadioInputs.js +13 -0
  119. package/ui/form/ChoiceRadioInputs.tsx +60 -0
  120. package/ui/form/Clickable.d.ts +27 -0
  121. package/ui/form/Clickable.js +29 -0
  122. package/ui/form/Clickable.tsx +87 -0
  123. package/ui/form/DataInput.d.ts +9 -0
  124. package/ui/form/DataInput.js +17 -0
  125. package/ui/form/DataInput.tsx +43 -0
  126. package/ui/form/DateInput.d.ts +12 -0
  127. package/ui/form/DateInput.js +17 -0
  128. package/ui/form/DateInput.tsx +58 -0
  129. package/ui/form/DictionaryInput.d.ts +13 -0
  130. package/ui/form/DictionaryInput.js +32 -0
  131. package/ui/form/DictionaryInput.tsx +106 -0
  132. package/ui/form/Field.d.ts +10 -0
  133. package/ui/form/Field.js +7 -0
  134. package/ui/form/Field.module.css +45 -0
  135. package/ui/form/Field.test.tsx +26 -0
  136. package/ui/form/Field.tsx +32 -0
  137. package/ui/form/FileInput.d.ts +7 -0
  138. package/ui/form/FileInput.js +13 -0
  139. package/ui/form/FileInput.tsx +41 -0
  140. package/ui/form/Form.d.ts +38 -0
  141. package/ui/form/Form.js +61 -0
  142. package/ui/form/Form.module.css +9 -0
  143. package/ui/form/Form.tsx +130 -0
  144. package/ui/form/FormContext.d.ts +13 -0
  145. package/ui/form/FormContext.js +22 -0
  146. package/ui/form/FormContext.tsx +33 -0
  147. package/ui/form/FormFields.d.ts +6 -0
  148. package/ui/form/FormFields.js +16 -0
  149. package/ui/form/FormFields.tsx +30 -0
  150. package/ui/form/FormFooter.d.ts +11 -0
  151. package/ui/form/FormFooter.js +13 -0
  152. package/ui/form/FormFooter.tsx +27 -0
  153. package/ui/form/FormInput.d.ts +8 -0
  154. package/ui/form/FormInput.js +12 -0
  155. package/ui/form/FormInput.tsx +23 -0
  156. package/ui/form/FormMessage.d.ts +4 -0
  157. package/ui/form/FormMessage.js +11 -0
  158. package/ui/form/FormMessage.tsx +16 -0
  159. package/ui/form/FormNotice.d.ts +4 -0
  160. package/ui/form/FormNotice.js +11 -0
  161. package/ui/form/FormNotice.tsx +16 -0
  162. package/ui/form/FormNotify.d.ts +2 -0
  163. package/ui/form/FormNotify.js +11 -0
  164. package/ui/form/FormNotify.tsx +13 -0
  165. package/ui/form/FormStore.d.ts +39 -0
  166. package/ui/form/FormStore.js +95 -0
  167. package/ui/form/FormStore.tsx +107 -0
  168. package/ui/form/Input.d.ts +47 -0
  169. package/ui/form/Input.js +43 -0
  170. package/ui/form/Input.module.css +190 -0
  171. package/ui/form/Input.tsx +81 -0
  172. package/ui/form/NumberInput.d.ts +12 -0
  173. package/ui/form/NumberInput.js +18 -0
  174. package/ui/form/NumberInput.tsx +54 -0
  175. package/ui/form/Popover.d.ts +31 -0
  176. package/ui/form/Popover.js +20 -0
  177. package/ui/form/Popover.module.css +25 -0
  178. package/ui/form/Popover.tsx +61 -0
  179. package/ui/form/Progress.d.ts +9 -0
  180. package/ui/form/Progress.js +8 -0
  181. package/ui/form/Progress.module.css +30 -0
  182. package/ui/form/Progress.tsx +21 -0
  183. package/ui/form/QueryInput.d.ts +32 -0
  184. package/ui/form/QueryInput.js +37 -0
  185. package/ui/form/QueryInput.tsx +94 -0
  186. package/ui/form/RadioInput.d.ts +7 -0
  187. package/ui/form/RadioInput.js +8 -0
  188. package/ui/form/RadioInput.tsx +37 -0
  189. package/ui/form/SchemaInput.d.ts +59 -0
  190. package/ui/form/SchemaInput.js +102 -0
  191. package/ui/form/SchemaInput.tsx +154 -0
  192. package/ui/form/SegmentedProgress.d.ts +10 -0
  193. package/ui/form/SegmentedProgress.js +16 -0
  194. package/ui/form/SegmentedProgress.module.css +31 -0
  195. package/ui/form/SegmentedProgress.tsx +34 -0
  196. package/ui/form/SelectInput.d.ts +8 -0
  197. package/ui/form/SelectInput.js +6 -0
  198. package/ui/form/SelectInput.tsx +45 -0
  199. package/ui/form/SubmitButton.d.ts +7 -0
  200. package/ui/form/SubmitButton.js +15 -0
  201. package/ui/form/SubmitButton.tsx +38 -0
  202. package/ui/form/TextInput.d.ts +16 -0
  203. package/ui/form/TextInput.js +31 -0
  204. package/ui/form/TextInput.tsx +97 -0
  205. package/ui/form/index.d.ts +34 -0
  206. package/ui/form/index.js +34 -0
  207. package/ui/form/index.ts +34 -0
  208. package/ui/index.d.ts +12 -0
  209. package/ui/index.js +12 -0
  210. package/ui/index.ts +12 -0
  211. package/ui/inline/Code.d.ts +17 -0
  212. package/ui/inline/Code.js +14 -0
  213. package/ui/inline/Code.module.css +14 -0
  214. package/ui/inline/Code.tsx +34 -0
  215. package/ui/inline/Deleted.d.ts +5 -0
  216. package/ui/inline/Deleted.js +5 -0
  217. package/ui/inline/Deleted.module.css +9 -0
  218. package/ui/inline/Deleted.tsx +10 -0
  219. package/ui/inline/Emphasis.d.ts +5 -0
  220. package/ui/inline/Emphasis.js +5 -0
  221. package/ui/inline/Emphasis.module.css +5 -0
  222. package/ui/inline/Emphasis.tsx +10 -0
  223. package/ui/inline/Inserted.d.ts +5 -0
  224. package/ui/inline/Inserted.js +5 -0
  225. package/ui/inline/Inserted.module.css +9 -0
  226. package/ui/inline/Inserted.tsx +10 -0
  227. package/ui/inline/Link.d.ts +5 -0
  228. package/ui/inline/Link.js +5 -0
  229. package/ui/inline/Link.module.css +19 -0
  230. package/ui/inline/Link.tsx +9 -0
  231. package/ui/inline/Mark.d.ts +5 -0
  232. package/ui/inline/Mark.js +5 -0
  233. package/ui/inline/Mark.module.css +15 -0
  234. package/ui/inline/Mark.tsx +10 -0
  235. package/ui/inline/Small.d.ts +5 -0
  236. package/ui/inline/Small.js +5 -0
  237. package/ui/inline/Small.module.css +9 -0
  238. package/ui/inline/Small.tsx +10 -0
  239. package/ui/inline/Strong.d.ts +5 -0
  240. package/ui/inline/Strong.js +5 -0
  241. package/ui/inline/Strong.module.css +5 -0
  242. package/ui/inline/Strong.tsx +10 -0
  243. package/ui/inline/Subscript.d.ts +5 -0
  244. package/ui/inline/Subscript.js +5 -0
  245. package/ui/inline/Subscript.module.css +9 -0
  246. package/ui/inline/Subscript.tsx +10 -0
  247. package/ui/inline/Superscript.d.ts +5 -0
  248. package/ui/inline/Superscript.js +5 -0
  249. package/ui/inline/Superscript.module.css +9 -0
  250. package/ui/inline/Superscript.tsx +10 -0
  251. package/ui/inline/When.d.ts +18 -0
  252. package/ui/inline/When.js +24 -0
  253. package/ui/inline/When.tsx +49 -0
  254. package/ui/inline/index.d.ts +11 -0
  255. package/ui/inline/index.js +11 -0
  256. package/ui/inline/index.ts +11 -0
  257. package/ui/layout/CenteredLayout.d.ts +10 -0
  258. package/ui/layout/CenteredLayout.js +11 -0
  259. package/ui/layout/CenteredLayout.module.css +13 -0
  260. package/ui/layout/CenteredLayout.tsx +23 -0
  261. package/ui/layout/Layout.d.ts +9 -0
  262. package/ui/layout/Layout.js +25 -0
  263. package/ui/layout/Layout.module.css +64 -0
  264. package/ui/layout/Layout.ts +26 -0
  265. package/ui/layout/index.d.ts +2 -0
  266. package/ui/layout/index.js +2 -0
  267. package/ui/layout/index.tsx +2 -0
  268. package/ui/misc/Catcher.d.ts +45 -0
  269. package/ui/misc/Catcher.js +57 -0
  270. package/ui/misc/Catcher.tsx +114 -0
  271. package/ui/misc/Loading.d.ts +8 -0
  272. package/ui/misc/Loading.js +6 -0
  273. package/ui/misc/Loading.module.css +19 -0
  274. package/ui/misc/Loading.tsx +31 -0
  275. package/ui/misc/Meta.d.ts +9 -0
  276. package/ui/misc/Meta.js +14 -0
  277. package/ui/misc/Meta.tsx +20 -0
  278. package/ui/misc/index.d.ts +3 -0
  279. package/ui/misc/index.js +3 -0
  280. package/ui/misc/index.tsx +3 -0
  281. package/ui/notice/Message.d.ts +11 -0
  282. package/ui/notice/Message.js +12 -0
  283. package/ui/notice/Message.module.css +8 -0
  284. package/ui/notice/Message.tsx +30 -0
  285. package/ui/notice/Notice.d.ts +15 -0
  286. package/ui/notice/Notice.js +13 -0
  287. package/ui/notice/Notice.module.css +15 -0
  288. package/ui/notice/Notice.tsx +42 -0
  289. package/ui/notice/NoticeStore.d.ts +21 -0
  290. package/ui/notice/NoticeStore.js +44 -0
  291. package/ui/notice/NoticeStore.ts +60 -0
  292. package/ui/notice/Notices.d.ts +7 -0
  293. package/ui/notice/Notices.js +22 -0
  294. package/ui/notice/Notices.module.css +10 -0
  295. package/ui/notice/Notices.tsx +28 -0
  296. package/ui/notice/NoticesStore.d.ts +11 -0
  297. package/ui/notice/NoticesStore.js +16 -0
  298. package/ui/notice/NoticesStore.ts +23 -0
  299. package/ui/notice/README.md +40 -0
  300. package/ui/notice/Status.d.ts +29 -0
  301. package/ui/notice/Status.js +6 -0
  302. package/ui/notice/Status.module.css +79 -0
  303. package/ui/notice/Status.tsx +36 -0
  304. package/ui/notice/StatusIcon.d.ts +12 -0
  305. package/ui/notice/StatusIcon.js +19 -0
  306. package/ui/notice/StatusIcon.module.css +28 -0
  307. package/ui/notice/StatusIcon.tsx +33 -0
  308. package/ui/notice/index.d.ts +7 -0
  309. package/ui/notice/index.js +7 -0
  310. package/ui/notice/index.ts +7 -0
  311. package/ui/page/Head.d.ts +8 -0
  312. package/ui/page/Head.js +32 -0
  313. package/ui/page/Head.tsx +49 -0
  314. package/ui/page/Page.d.ts +10 -0
  315. package/ui/page/Page.js +10 -0
  316. package/ui/page/Page.tsx +21 -0
  317. package/ui/page/index.d.ts +2 -0
  318. package/ui/page/index.js +2 -0
  319. package/ui/page/index.ts +2 -0
  320. package/ui/router/Router.d.ts +31 -0
  321. package/ui/router/Router.js +59 -0
  322. package/ui/router/Router.tsx +88 -0
  323. package/ui/router/RouterContext.d.ts +5 -0
  324. package/ui/router/RouterContext.js +9 -0
  325. package/ui/router/RouterContext.tsx +12 -0
  326. package/ui/router/RouterStore.d.ts +13 -0
  327. package/ui/router/RouterStore.js +23 -0
  328. package/ui/router/RouterStore.test.tsx +43 -0
  329. package/ui/router/RouterStore.tsx +29 -0
  330. package/ui/router/Routes.d.ts +39 -0
  331. package/ui/router/Routes.js +35 -0
  332. package/ui/router/Routes.tsx +62 -0
  333. package/ui/router/index.d.ts +4 -0
  334. package/ui/router/index.js +4 -0
  335. package/ui/router/index.ts +4 -0
  336. package/ui/transition/CollapseTransition.css +3 -0
  337. package/ui/transition/CollapseTransition.d.ts +6 -0
  338. package/ui/transition/CollapseTransition.js +6 -0
  339. package/ui/transition/CollapseTransition.tsx +9 -0
  340. package/ui/transition/FadeTransition.css +25 -0
  341. package/ui/transition/FadeTransition.d.ts +5 -0
  342. package/ui/transition/FadeTransition.js +5 -0
  343. package/ui/transition/FadeTransition.tsx +8 -0
  344. package/ui/transition/HorizontalTransition.css +66 -0
  345. package/ui/transition/HorizontalTransition.d.ts +6 -0
  346. package/ui/transition/HorizontalTransition.js +6 -0
  347. package/ui/transition/HorizontalTransition.tsx +9 -0
  348. package/ui/transition/Transition.css +3 -0
  349. package/ui/transition/Transition.d.ts +18 -0
  350. package/ui/transition/Transition.js +21 -0
  351. package/ui/transition/Transition.tsx +35 -0
  352. package/ui/transition/VerticalTransition.css +66 -0
  353. package/ui/transition/VerticalTransition.d.ts +6 -0
  354. package/ui/transition/VerticalTransition.js +6 -0
  355. package/ui/transition/VerticalTransition.tsx +9 -0
  356. package/ui/transition/index.d.ts +6 -0
  357. package/ui/transition/index.js +6 -0
  358. package/ui/transition/index.tsx +6 -0
  359. package/ui/transition/util.d.ts +17 -0
  360. package/ui/transition/util.js +6 -0
  361. package/ui/transition/util.tsx +24 -0
  362. package/ui/types.d.ts +9 -0
  363. package/ui/util/context.d.ts +6 -0
  364. package/ui/util/context.js +10 -0
  365. package/ui/util/context.ts +15 -0
  366. package/ui/util/css.d.ts +37 -0
  367. package/ui/util/css.js +63 -0
  368. package/ui/util/css.ts +80 -0
  369. package/ui/util/event.d.ts +2 -0
  370. package/ui/util/event.js +4 -0
  371. package/ui/util/event.ts +4 -0
  372. package/ui/util/focus.d.ts +16 -0
  373. package/ui/util/focus.js +21 -0
  374. package/ui/util/focus.ts +23 -0
  375. package/ui/util/index.d.ts +8 -0
  376. package/ui/util/index.js +8 -0
  377. package/ui/util/index.ts +8 -0
  378. package/ui/util/meta.d.ts +67 -0
  379. package/ui/util/meta.js +33 -0
  380. package/ui/util/meta.ts +97 -0
  381. package/ui/util/notice.d.ts +26 -0
  382. package/ui/util/notice.js +82 -0
  383. package/ui/util/notice.ts +103 -0
  384. package/ui/util/refresh.d.ts +2 -0
  385. package/ui/util/refresh.js +9 -0
  386. package/ui/util/refresh.ts +11 -0
  387. package/ui/util/scroll.d.ts +11 -0
  388. package/ui/util/scroll.js +32 -0
  389. package/ui/util/scroll.ts +40 -0
  390. package/ui/util/state.d.ts +11 -0
  391. package/ui/util/state.js +42 -0
  392. package/ui/util/state.ts +44 -0
  393. package/util/index.d.ts +1 -0
  394. package/util/index.js +1 -0
@@ -0,0 +1,57 @@
1
+ import { XMarkIcon } from "@heroicons/react/24/solid";
2
+ import { type MouseEvent, memo, type ReactElement, type ReactNode, Suspense, useEffect, useRef } from "react";
3
+ import type { Callback } from "../../util/function.js";
4
+ import type { ButtonVariants } from "../form/Button.js";
5
+ import { getModuleClass } from "../util/css.js";
6
+ import styles from "./Dialog.module.css";
7
+
8
+ export interface DialogProps {
9
+ children?: ReactNode;
10
+ onClose?: Callback;
11
+ }
12
+
13
+ export const Dialog = memo(({ children, onClose, ...props }: DialogProps) => {
14
+ const ref = useRef<HTMLDialogElement>(null);
15
+
16
+ useEffect(() => {
17
+ ref.current?.showModal();
18
+ }, []);
19
+
20
+ return (
21
+ <Suspense fallback={null}>
22
+ {/** biome-ignore lint/a11y/useKeyWithClickEvents: Dialogs also show a close button. */}
23
+ <dialog ref={ref} className={styles.dialog} onClick={_closeOnBackdropClick} onClose={onClose} {...props}>
24
+ {children}
25
+ <div className={styles.close}>
26
+ <DialogCloseButton plain />
27
+ </div>
28
+ </dialog>
29
+ </Suspense>
30
+ );
31
+ });
32
+
33
+ /** When the user clicks anywhere on a `<dialog>` element (and the click isn't on a link etc), then close the dialog. */
34
+ function _closeOnBackdropClick({ currentTarget, target }: MouseEvent<HTMLDialogElement>): void {
35
+ // Close the dialog when clicking on the dialog itself (but not its children).
36
+ if (currentTarget === target) currentTarget.close();
37
+
38
+ // Close the dialog when clicking on links or buttons in a `<nav>` element.
39
+ if (target instanceof Element && target.closest("a:any-link, nav button:enabled")) currentTarget.close();
40
+ }
41
+
42
+ export interface DialogCloseButtonProps extends ButtonVariants {
43
+ children?: ReactNode | undefined;
44
+ }
45
+
46
+ /** Button that closes its wrapping dialog with an X icon. */
47
+ export function DialogCloseButton({ children = <XMarkIcon />, ...variants }: DialogCloseButtonProps): ReactElement {
48
+ return (
49
+ <button type="button" title="Close" className={getModuleClass(styles, "button", variants)} onClick={_closeOnButtonClick}>
50
+ {children}
51
+ </button>
52
+ );
53
+ }
54
+
55
+ function _closeOnButtonClick({ currentTarget }: MouseEvent<HTMLButtonElement>): void {
56
+ currentTarget.closest("dialog")?.close();
57
+ }
@@ -0,0 +1,23 @@
1
+ import { type ReactElement, type ReactNode } from "react";
2
+ import { ArrayStore } from "../../store/ArrayStore.js";
3
+ /** Store a list of dialogs. */
4
+ export declare class DialogsStore extends ArrayStore<ReactElement> {
5
+ /** Show a new dialog. */
6
+ show(children: ReactNode): void;
7
+ /** Hide all currently visible dialogs. */
8
+ hideAll(): void;
9
+ }
10
+ /** Return the current dialogs context. */
11
+ export declare function requireDialogs(): DialogsStore;
12
+ declare const _componentProps: unique symbol;
13
+ export interface DialogsContextProps {
14
+ children: ReactNode;
15
+ }
16
+ export interface DialogsProps {
17
+ readonly [_componentProps]?: never;
18
+ }
19
+ /** Create a new `<DialogsStore>` for a set of elements. */
20
+ export declare function DialogsContext({ children }: DialogsContextProps): ReactElement;
21
+ /** Output the list of dialogs from a `DialogsStore` in the current `DialogsContext`. */
22
+ export declare function Dialogs(): ReactNode | null;
23
+ export {};
@@ -0,0 +1,43 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, use } from "react";
3
+ import { useInstance } from "../../react/useInstance.js";
4
+ import { useStore } from "../../react/useStore.js";
5
+ import { ArrayStore } from "../../store/ArrayStore.js";
6
+ import { getRandomKey } from "../../util/random.js";
7
+ import { Dialog } from "./Dialog.js";
8
+ /** How long before a hidden dialogs are removed from the DOM (allow time for animates to complete). */
9
+ const REMOVE_DELAY = 500;
10
+ /** Store a list of dialogs. */
11
+ export class DialogsStore extends ArrayStore {
12
+ /** Show a new dialog. */
13
+ show(children) {
14
+ const dialog = (_jsx(Dialog
15
+ // Add a `key=""` so dialogs can be rendered directly and added/removed in any order.
16
+ , {
17
+ // When the `<dialog>` is closed, wait for the animation to finish then remove the dialog from the list.
18
+ onClose: () => {
19
+ setTimeout(() => this.delete(dialog), REMOVE_DELAY);
20
+ }, children: children }, getRandomKey()));
21
+ this.add(dialog);
22
+ }
23
+ /** Hide all currently visible dialogs. */
24
+ hideAll() {
25
+ this.delete(...this.value);
26
+ }
27
+ }
28
+ /** Context to get the current `DialogsStore` created by a `<DialogsWrapper>`. */
29
+ const _DialogsContext = createContext(new DialogsStore());
30
+ _DialogsContext.displayName = "DialogsContext";
31
+ /** Return the current dialogs context. */
32
+ export function requireDialogs() {
33
+ return use(_DialogsContext);
34
+ }
35
+ /** Create a new `<DialogsStore>` for a set of elements. */
36
+ export function DialogsContext({ children }) {
37
+ return _jsx(_DialogsContext, { value: useInstance(DialogsStore), children: children });
38
+ }
39
+ /** Output the list of dialogs from a `DialogsStore` in the current `DialogsContext`. */
40
+ export function Dialogs() {
41
+ const dialogs = useStore(requireDialogs());
42
+ return dialogs ? dialogs.value : null;
43
+ }
@@ -0,0 +1,64 @@
1
+ import { createContext, type ReactElement, type ReactNode, use } from "react";
2
+ import { useInstance } from "../../react/useInstance.js";
3
+ import { useStore } from "../../react/useStore.js";
4
+ import { ArrayStore } from "../../store/ArrayStore.js";
5
+ import { getRandomKey } from "../../util/random.js";
6
+ import { Dialog } from "./Dialog.js";
7
+
8
+ /** How long before a hidden dialogs are removed from the DOM (allow time for animates to complete). */
9
+ const REMOVE_DELAY = 500;
10
+
11
+ /** Store a list of dialogs. */
12
+ export class DialogsStore extends ArrayStore<ReactElement> {
13
+ /** Show a new dialog. */
14
+ show(children: ReactNode) {
15
+ const dialog = (
16
+ <Dialog
17
+ // Add a `key=""` so dialogs can be rendered directly and added/removed in any order.
18
+ key={getRandomKey()}
19
+ // When the `<dialog>` is closed, wait for the animation to finish then remove the dialog from the list.
20
+ onClose={() => {
21
+ setTimeout(() => this.delete(dialog), REMOVE_DELAY);
22
+ }}
23
+ >
24
+ {children}
25
+ </Dialog>
26
+ );
27
+ this.add(dialog);
28
+ }
29
+
30
+ /** Hide all currently visible dialogs. */
31
+ hideAll() {
32
+ this.delete(...this.value);
33
+ }
34
+ }
35
+
36
+ /** Context to get the current `DialogsStore` created by a `<DialogsWrapper>`. */
37
+ const _DialogsContext = createContext<DialogsStore>(new DialogsStore());
38
+ _DialogsContext.displayName = "DialogsContext";
39
+
40
+ /** Return the current dialogs context. */
41
+ export function requireDialogs(): DialogsStore {
42
+ return use(_DialogsContext);
43
+ }
44
+
45
+ declare const _componentProps: unique symbol;
46
+
47
+ export interface DialogsContextProps {
48
+ children: ReactNode;
49
+ }
50
+
51
+ export interface DialogsProps {
52
+ readonly [_componentProps]?: never;
53
+ }
54
+
55
+ /** Create a new `<DialogsStore>` for a set of elements. */
56
+ export function DialogsContext({ children }: DialogsContextProps): ReactElement {
57
+ return <_DialogsContext value={useInstance(DialogsStore)}>{children}</_DialogsContext>;
58
+ }
59
+
60
+ /** Output the list of dialogs from a `DialogsStore` in the current `DialogsContext`. */
61
+ export function Dialogs(): ReactNode | null {
62
+ const dialogs = useStore(requireDialogs());
63
+ return dialogs ? dialogs.value : null;
64
+ }
@@ -0,0 +1,5 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ export type ModalProps = {
3
+ children?: ReactNode | undefined;
4
+ };
5
+ export declare function Modal({ children }: ModalProps): ReactElement;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import styles from "./Modal.module.css";
3
+ export function Modal({ children }) {
4
+ return _jsx("aside", { className: styles.modal, children: children });
5
+ }
@@ -0,0 +1,11 @@
1
+ .modal {
2
+ margin: auto;
3
+ max-width: 100%;
4
+ border-radius: var(--modal-radius, var(--radius-block));
5
+ border: var(--modal-border, var(--border-block)) solid var(--modal-color-border, var(--color-border));
6
+ background: var(--modal-color-bg, var(--color-bg));
7
+ padding: var(--modal-padding, var(--spacing-block));
8
+ color: var(--modal-color-text, var(--color-text));
9
+ box-shadow: var(--modal-shadow, var(--shadow-block));
10
+ width: var(--modal-width, var(--width-narrow));
11
+ }
@@ -0,0 +1,10 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import styles from "./Modal.module.css";
3
+
4
+ export type ModalProps = {
5
+ children?: ReactNode | undefined;
6
+ };
7
+
8
+ export function Modal({ children }: ModalProps): ReactElement {
9
+ return <aside className={styles.modal}>{children}</aside>;
10
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./Dialog.js";
2
+ export * from "./Dialogs.js";
3
+ export * from "./Modal.js";
@@ -0,0 +1,3 @@
1
+ export * from "./Dialog.js";
2
+ export * from "./Dialogs.js";
3
+ export * from "./Modal.js";
@@ -0,0 +1,3 @@
1
+ export * from "./Dialog.js";
2
+ export * from "./Dialogs.js";
3
+ export * from "./Modal.js";
@@ -0,0 +1,13 @@
1
+ import type { ReactElement } from "react";
2
+ import type { Schema } from "../../schema/Schema.js";
3
+ import { type ImmutableArray } from "../../util/array.js";
4
+ import { type ValueInputProps } from "./Input.js";
5
+ export interface ArrayInputProps<T> extends ValueInputProps<ImmutableArray<T>> {
6
+ one?: string;
7
+ many?: string;
8
+ min?: number | undefined;
9
+ max?: number | undefined;
10
+ /** Schema for the items in the repeater. */
11
+ items: Schema<T>;
12
+ }
13
+ export declare function ArrayInput<T>(props: ArrayInputProps<T>): ReactElement;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PlusIcon, XMarkIcon } from "@heroicons/react/24/solid";
3
+ import { omitArrayIndex, withArrayIndex } from "../../util/array.js";
4
+ import { splitMessage } from "../../util/error.js";
5
+ import { formatUnit } from "../../util/format.js";
6
+ import { Elements } from "../block/Elements.js";
7
+ import { Button } from "./Button.js";
8
+ import { Input } from "./Input.js";
9
+ import { SchemaInput } from "./SchemaInput.js";
10
+ export function ArrayInput({ name,
11
+ // title,
12
+ placeholder, required = false, disabled = false, message = "", value = [], onValue, one = "item", many = `${one}s`, min = 0, max = Number.POSITIVE_INFINITY, items, }) {
13
+ const messages = splitMessage(message);
14
+ const length = value.length;
15
+ const disableRemove = disabled || length <= min;
16
+ const addNewItem = () => onValue([...value, items.value]);
17
+ return (_jsxs(Elements, { column: true, children: [length ? (value.map((v, i) => {
18
+ const k = i.toString();
19
+ return (_jsxs(Elements, { children: [_jsx(SchemaInput, { name: k, schema: items, value: v, onValue: x => onValue(withArrayIndex(value, i, x)), message: messages[k], disabled: disabled }), _jsx(Button, { onClick: () => onValue(omitArrayIndex(value, i)), disabled: disableRemove, title: disableRemove ? `Minimum ${formatUnit(min, one, { unitDisplay: "long", one, many })}` : `Remove ${one}`, children: _jsx(XMarkIcon, {}) })] }, k));
20
+ })) : (_jsx(Input, { onClick: addNewItem, name: name, required: required && min > 1, disabled: disabled, children: placeholder })), _jsxs(Elements, { children: [_jsxs(Button //
21
+ , { onClick: addNewItem, disabled: disabled || (typeof max === "number" && length >= max), small: true, children: [_jsx(PlusIcon, {}), " Add ", one] }), length && min < 1 ? (_jsxs(Button //
22
+ , { onClick: () => onValue([]), small: true, children: [_jsx(XMarkIcon, {}), " Clear ", many] })) : null] })] }));
23
+ }
@@ -0,0 +1,90 @@
1
+ import { PlusIcon, XMarkIcon } from "@heroicons/react/24/solid";
2
+ import type { ReactElement } from "react";
3
+ import type { Schema } from "../../schema/Schema.js";
4
+ import { type ImmutableArray, omitArrayIndex, withArrayIndex } from "../../util/array.js";
5
+ import { splitMessage } from "../../util/error.js";
6
+ import { formatUnit } from "../../util/format.js";
7
+ import { Elements } from "../block/Elements.js";
8
+ import { Button } from "./Button.js";
9
+ import { Input, type ValueInputProps } from "./Input.js";
10
+ import { SchemaInput } from "./SchemaInput.js";
11
+
12
+ export interface ArrayInputProps<T> extends ValueInputProps<ImmutableArray<T>> {
13
+ one?: string;
14
+ many?: string;
15
+ min?: number | undefined;
16
+ max?: number | undefined;
17
+ /** Schema for the items in the repeater. */
18
+ items: Schema<T>;
19
+ }
20
+
21
+ export function ArrayInput<T>(props: ArrayInputProps<T>): ReactElement;
22
+ export function ArrayInput({
23
+ name,
24
+ // title,
25
+ placeholder,
26
+ required = false,
27
+ disabled = false,
28
+ message = "",
29
+ value = [],
30
+ onValue,
31
+ one = "item",
32
+ many = `${one}s`,
33
+ min = 0,
34
+ max = Number.POSITIVE_INFINITY,
35
+ items,
36
+ }: ArrayInputProps<unknown>): ReactElement {
37
+ const messages = splitMessage(message);
38
+ const length = value.length;
39
+ const disableRemove = disabled || length <= min;
40
+ const addNewItem = () => onValue([...value, items.value]);
41
+ return (
42
+ <Elements column>
43
+ {length ? (
44
+ value.map((v, i) => {
45
+ const k = i.toString();
46
+ return (
47
+ <Elements key={k}>
48
+ <SchemaInput
49
+ name={k}
50
+ schema={items}
51
+ value={v}
52
+ onValue={x => onValue(withArrayIndex(value, i, x))}
53
+ message={messages[k]}
54
+ disabled={disabled}
55
+ />
56
+ <Button
57
+ onClick={() => onValue(omitArrayIndex(value, i))}
58
+ disabled={disableRemove}
59
+ title={disableRemove ? `Minimum ${formatUnit(min, one, { unitDisplay: "long", one, many })}` : `Remove ${one}`}
60
+ >
61
+ <XMarkIcon />
62
+ </Button>
63
+ </Elements>
64
+ );
65
+ })
66
+ ) : (
67
+ <Input onClick={addNewItem} name={name} required={required && min > 1} disabled={disabled}>
68
+ {placeholder}
69
+ </Input>
70
+ )}
71
+ <Elements>
72
+ <Button //
73
+ onClick={addNewItem}
74
+ disabled={disabled || (typeof max === "number" && length >= max)}
75
+ small
76
+ >
77
+ <PlusIcon /> Add {one}
78
+ </Button>
79
+ {length && min < 1 ? (
80
+ <Button //
81
+ onClick={() => onValue([])}
82
+ small
83
+ >
84
+ <XMarkIcon /> Clear {many}
85
+ </Button>
86
+ ) : null}
87
+ </Elements>
88
+ </Elements>
89
+ );
90
+ }
@@ -0,0 +1,15 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import type { ImmutableArray } from "../../util/array.js";
3
+ import type { ValueInputProps } from "./Input.js";
4
+ export interface ArrayRadioInputsProps<T> extends ValueInputProps<T> {
5
+ /** Array of values to show in the list of radios. */
6
+ items: ImmutableArray<T>;
7
+ /** Function that formats an obscure item into a `ReactNode` for display. */
8
+ formatter?: ((value: T) => ReactNode) | undefined;
9
+ }
10
+ /**
11
+ * Output a list of `<RadioInput>` elements for each item in an array.
12
+ * - The items can be any type, and can be formatted for output through an optional `formatter()` function.
13
+ * - A `placeholder` option is shown at the bottom if `required=false`.
14
+ */
15
+ export declare function ArrayRadioInputs<T>({ value, onValue, required, items, formatter, ...props }: ArrayRadioInputsProps<T>): ReactElement;
@@ -0,0 +1,16 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { formatValue } from "../../util/format.js";
3
+ import { Elements } from "../block/Elements.js";
4
+ import { RadioInput } from "./RadioInput.js";
5
+ /**
6
+ * Output a list of `<RadioInput>` elements for each item in an array.
7
+ * - The items can be any type, and can be formatted for output through an optional `formatter()` function.
8
+ * - A `placeholder` option is shown at the bottom if `required=false`.
9
+ */
10
+ export function ArrayRadioInputs({ value, onValue, required = false, items, formatter = formatValue, ...props }) {
11
+ return (_jsxs(Elements, { column: true, children: [items.map((v, i) => {
12
+ return (_jsx(RadioInput //
13
+ , { value: value === v, onValue: () => onValue(v), required: required, ...props, children: formatter(v) }, i.toString()));
14
+ }), !required ? (_jsx(RadioInput //
15
+ , { value: !value, onValue: () => onValue(undefined), required: required, ...props })) : null] }));
16
+ }
@@ -0,0 +1,53 @@
1
+ import type { ReactElement, ReactNode } from "react";
2
+ import type { ImmutableArray } from "../../util/array.js";
3
+ import { formatValue } from "../../util/format.js";
4
+ import { Elements } from "../block/Elements.js";
5
+ import type { ValueInputProps } from "./Input.js";
6
+ import { RadioInput } from "./RadioInput.js";
7
+
8
+ export interface ArrayRadioInputsProps<T> extends ValueInputProps<T> {
9
+ /** Array of values to show in the list of radios. */
10
+ items: ImmutableArray<T>;
11
+ /** Function that formats an obscure item into a `ReactNode` for display. */
12
+ formatter?: ((value: T) => ReactNode) | undefined;
13
+ }
14
+
15
+ /**
16
+ * Output a list of `<RadioInput>` elements for each item in an array.
17
+ * - The items can be any type, and can be formatted for output through an optional `formatter()` function.
18
+ * - A `placeholder` option is shown at the bottom if `required=false`.
19
+ */
20
+ export function ArrayRadioInputs<T>({
21
+ value,
22
+ onValue,
23
+ required = false,
24
+ items,
25
+ formatter = formatValue,
26
+ ...props
27
+ }: ArrayRadioInputsProps<T>): ReactElement {
28
+ return (
29
+ <Elements column>
30
+ {items.map((v, i) => {
31
+ return (
32
+ <RadioInput //
33
+ key={i.toString()}
34
+ value={value === v}
35
+ onValue={() => onValue(v)}
36
+ required={required}
37
+ {...props}
38
+ >
39
+ {formatter(v)}
40
+ </RadioInput>
41
+ );
42
+ })}
43
+ {!required ? (
44
+ <RadioInput //
45
+ value={!value}
46
+ onValue={() => onValue(undefined)}
47
+ required={required}
48
+ {...props}
49
+ />
50
+ ) : null}
51
+ </Elements>
52
+ );
53
+ }
@@ -0,0 +1,24 @@
1
+ import type { ReactElement } from "react";
2
+ import { type ElementsVariants } from "../block/Elements.js";
3
+ import { type StatusVariants } from "../notice/Status.js";
4
+ import BUTTON_CSS from "./Button.module.css";
5
+ import { type ClickableProps } from "./Clickable.js";
6
+ /** Variants for buttons. */
7
+ export interface ButtonVariants extends ElementsVariants, StatusVariants {
8
+ /** This is the default button in a form and should be displayed stronger. */
9
+ strong?: boolean | undefined;
10
+ /** Add plain styling (background only appears on hover or focus). */
11
+ plain?: boolean | undefined;
12
+ /** Add outline styling (has no background until hover or focus). */
13
+ outline?: boolean | undefined;
14
+ /** Make the button appear smaller. */
15
+ small?: boolean | undefined;
16
+ /** Make the button content-width. */
17
+ fit?: boolean | undefined;
18
+ }
19
+ export declare const ELEMENTS_BUTTON_CLASS: string;
20
+ interface ButtonProps extends ButtonVariants, ClickableProps {
21
+ }
22
+ /** Return either a `<button>` or an `<a href="">` styled as an button, based on whether an `onClick` or `href` prop is provided. */
23
+ export declare function Button({ disabled, href, onClick, title, target, download, children, ...variants }: ButtonProps): ReactElement;
24
+ export { BUTTON_CSS };
@@ -0,0 +1,21 @@
1
+ import { ELEMENTS_CSS } from "../block/Elements.js";
2
+ import { getStatusClass } from "../notice/Status.js";
3
+ import { getClass, getModuleClass } from "../util/css.js";
4
+ import BUTTON_CSS from "./Button.module.css";
5
+ import { getClickable } from "./Clickable.js";
6
+ // Precomposed styles.
7
+ export const ELEMENTS_BUTTON_CLASS = getClass(BUTTON_CSS.button, ELEMENTS_CSS.elements, ELEMENTS_CSS.center);
8
+ /** Return either a `<button>` or an `<a href="">` styled as an button, based on whether an `onClick` or `href` prop is provided. */
9
+ export function Button({ disabled, href, onClick, title, target, download, children, ...variants }) {
10
+ return getClickable({
11
+ disabled,
12
+ href,
13
+ onClick,
14
+ title,
15
+ target,
16
+ download,
17
+ children,
18
+ }, getClass(ELEMENTS_BUTTON_CLASS, //
19
+ getModuleClass(BUTTON_CSS, variants), getModuleClass(ELEMENTS_CSS, variants), getStatusClass(variants)));
20
+ }
21
+ export { BUTTON_CSS };
@@ -0,0 +1,83 @@
1
+ .button {
2
+ /* Box */
3
+ display: flex;
4
+ box-sizing: border-box;
5
+ inline-size: 100%;
6
+ min-inline-size: fit-content; /* Buttons never go smaller than their contents. */
7
+ border-radius: var(--button-radius, var(--radius-element));
8
+ border: var(--button-border, var(--border-element)) solid var(--button-color-border, var(--color-border));
9
+ padding-block: var(--button-padding, var(--spacing-element));
10
+ padding-inline: var(--button-padding, var(--spacing-element));
11
+ margin-inline: 0;
12
+ margin-block: var(--button-spacing, var(--spacing-element));
13
+ flex-grow: var(--grow-timid); /* When displayed in flex rows inputs expand timidly compared to other elements inputs. */
14
+
15
+ /* Content */
16
+ white-space: nowrap;
17
+ overflow-wrap: normal;
18
+ text-wrap: nowrap;
19
+ word-break: normal;
20
+
21
+ /* Style */
22
+ color: var(--button-color-text, var(--color-quiet));
23
+ background: var(--button-color-bg, var(--color-surface));
24
+ text-decoration: none;
25
+ transition: all 120ms ease-in-out;
26
+ cursor: pointer;
27
+ outline: var(--button-focus-border, var(--border-focus)) solid transparent;
28
+ outline-offset: calc(0px - var(--button-border, var(--border-element)));
29
+
30
+ /* Typography */
31
+ font-family: var(--button-font, var(--font-body));
32
+ font-weight: var(--button-weight, var(--weight-strong));
33
+ font-size: var(--button-size, var(--size-normal));
34
+ line-height: var(--button-leading, var(--leading-normal));
35
+
36
+ /* Pseudo-classes */
37
+ &:disabled,
38
+ &:where(a:not(:any-link)) {
39
+ opacity: var(--button-disabled-opacity, 0.5);
40
+ cursor: default;
41
+ }
42
+ &:where(:enabled:hover, :focus:not(:focus-visible)) {
43
+ background: color-mix(in srgb, var(--button-color-bg, var(--color-surface)) 85%, white);
44
+ border-color: color-mix(in srgb, var(--button-color-border, var(--color-border)) 85%, var(--button-color-text, var(--color-text)));
45
+ }
46
+ &:first-child {
47
+ margin-block-start: 0;
48
+ }
49
+ &:last-child {
50
+ margin-block-end: 0;
51
+ }
52
+
53
+ /* Variants */
54
+ &.small {
55
+ padding-block: var(--button-small-padding, var(--spacing-small));
56
+ padding-inline: var(--button-small-padding, var(--spacing-small));
57
+ }
58
+ &.fit {
59
+ inline-size: fit-content;
60
+ }
61
+ &.strong {
62
+ color: var(--button-strong-contrast, var(--color-contrast));
63
+ border-color: var(--button-strong-contrast, var(--color-text));
64
+ background: var(--button-strong-contrast, var(--color-text));
65
+
66
+ &:where(:enabled:hover, :focus:not(:focus-visible)) {
67
+ background: color-mix(in srgb, var(--button-strong-contrast, var(--color-text)) 80%, white);
68
+ }
69
+ }
70
+ &.plain:not(:hover, :focus) {
71
+ border-color: transparent;
72
+ background: transparent;
73
+ }
74
+ &.outline:not(:hover, :focus) {
75
+ background: transparent;
76
+ }
77
+
78
+ /* Visible focus ring overrides all */
79
+ &:focus-visible {
80
+ outline-color: var(--button-color-focus, var(--focus-text));
81
+ border-color: var(--button-color-focus, var(--focus-text));
82
+ }
83
+ }
@@ -0,0 +1,48 @@
1
+ import type { ReactElement } from "react";
2
+ import { ELEMENTS_CSS, type ElementsVariants } from "../block/Elements.js";
3
+ import { getStatusClass, type StatusVariants } from "../notice/Status.js";
4
+ import { getClass, getModuleClass } from "../util/css.js";
5
+ import BUTTON_CSS from "./Button.module.css";
6
+ import { type ClickableProps, getClickable } from "./Clickable.js";
7
+
8
+ /** Variants for buttons. */
9
+ export interface ButtonVariants extends ElementsVariants, StatusVariants {
10
+ /** This is the default button in a form and should be displayed stronger. */
11
+ strong?: boolean | undefined;
12
+ /** Add plain styling (background only appears on hover or focus). */
13
+ plain?: boolean | undefined;
14
+ /** Add outline styling (has no background until hover or focus). */
15
+ outline?: boolean | undefined;
16
+ /** Make the button appear smaller. */
17
+ small?: boolean | undefined;
18
+ /** Make the button content-width. */
19
+ fit?: boolean | undefined;
20
+ }
21
+
22
+ // Precomposed styles.
23
+ export const ELEMENTS_BUTTON_CLASS = getClass(BUTTON_CSS.button, ELEMENTS_CSS.elements, ELEMENTS_CSS.center);
24
+
25
+ interface ButtonProps extends ButtonVariants, ClickableProps {}
26
+
27
+ /** Return either a `<button>` or an `<a href="">` styled as an button, based on whether an `onClick` or `href` prop is provided. */
28
+ export function Button({ disabled, href, onClick, title, target, download, children, ...variants }: ButtonProps): ReactElement {
29
+ return getClickable(
30
+ {
31
+ disabled,
32
+ href,
33
+ onClick,
34
+ title,
35
+ target,
36
+ download,
37
+ children,
38
+ },
39
+ getClass(
40
+ ELEMENTS_BUTTON_CLASS, //
41
+ getModuleClass(BUTTON_CSS, variants),
42
+ getModuleClass(ELEMENTS_CSS, variants),
43
+ getStatusClass(variants), // Buttons have status colours.
44
+ ),
45
+ );
46
+ }
47
+
48
+ export { BUTTON_CSS };
@@ -0,0 +1,7 @@
1
+ import type { ReactElement } from "react";
2
+ import { type ClickableProps } from "./Clickable.js";
3
+ import { type InputProps } from "./Input.js";
4
+ export interface ButtonInputProps extends InputProps, ClickableProps {
5
+ }
6
+ /** Return either a `<button>` or an `<a href="">` styled as an input, based on whether an `onClick` or `href` prop is provided. */
7
+ export declare function ButtonInput({ title, placeholder, disabled, href, onClick, target, download, children }: ButtonInputProps): ReactElement;