shelving 1.282.2 → 1.284.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 (240) hide show
  1. package/package.json +2 -2
  2. package/ui/README.md +2 -1
  3. package/ui/block/Address.d.ts +7 -7
  4. package/ui/block/Address.js +6 -6
  5. package/ui/block/Address.tsx +10 -9
  6. package/ui/block/Block.d.ts +3 -3
  7. package/ui/block/Block.js +3 -2
  8. package/ui/block/Block.tsx +5 -4
  9. package/ui/block/Blockquote.d.ts +3 -3
  10. package/ui/block/Blockquote.js +2 -2
  11. package/ui/block/Blockquote.tsx +4 -3
  12. package/ui/block/Caption.d.ts +3 -3
  13. package/ui/block/Caption.js +3 -3
  14. package/ui/block/Caption.tsx +5 -4
  15. package/ui/block/Card.d.ts +3 -2
  16. package/ui/block/Card.js +2 -2
  17. package/ui/block/Card.tsx +4 -2
  18. package/ui/block/Column.d.ts +3 -3
  19. package/ui/block/Column.js +2 -2
  20. package/ui/block/Column.tsx +4 -3
  21. package/ui/block/Definitions.d.ts +3 -3
  22. package/ui/block/Definitions.js +2 -2
  23. package/ui/block/Definitions.tsx +4 -3
  24. package/ui/block/Details.d.ts +3 -2
  25. package/ui/block/Details.js +2 -2
  26. package/ui/block/Details.tsx +4 -3
  27. package/ui/block/Divider.d.ts +3 -2
  28. package/ui/block/Divider.js +2 -2
  29. package/ui/block/Divider.tsx +4 -2
  30. package/ui/block/Heading.d.ts +3 -3
  31. package/ui/block/Heading.js +2 -2
  32. package/ui/block/Heading.tsx +4 -3
  33. package/ui/block/Image.d.ts +3 -2
  34. package/ui/block/Image.js +2 -2
  35. package/ui/block/Image.tsx +4 -2
  36. package/ui/block/Label.d.ts +1 -1
  37. package/ui/block/Label.js +2 -2
  38. package/ui/block/Label.tsx +2 -1
  39. package/ui/block/List.d.ts +3 -2
  40. package/ui/block/List.js +4 -4
  41. package/ui/block/List.tsx +6 -4
  42. package/ui/block/Panel.d.ts +3 -3
  43. package/ui/block/Panel.js +2 -2
  44. package/ui/block/Panel.tsx +4 -3
  45. package/ui/block/Paragraph.d.ts +3 -3
  46. package/ui/block/Paragraph.js +2 -2
  47. package/ui/block/Paragraph.tsx +4 -3
  48. package/ui/block/Preformatted.d.ts +3 -3
  49. package/ui/block/Preformatted.js +2 -2
  50. package/ui/block/Preformatted.tsx +4 -3
  51. package/ui/block/Row.d.ts +3 -3
  52. package/ui/block/Row.js +2 -2
  53. package/ui/block/Row.tsx +4 -3
  54. package/ui/block/Section.js +1 -1
  55. package/ui/block/Section.tsx +1 -0
  56. package/ui/block/Subheading.d.ts +1 -1
  57. package/ui/block/Subheading.js +2 -2
  58. package/ui/block/Subheading.tsx +2 -1
  59. package/ui/block/Title.d.ts +1 -1
  60. package/ui/block/Title.js +2 -2
  61. package/ui/block/Title.tsx +2 -1
  62. package/ui/block/Video.d.ts +3 -3
  63. package/ui/block/Video.js +2 -2
  64. package/ui/block/Video.tsx +4 -3
  65. package/ui/button/Button.d.ts +3 -2
  66. package/ui/button/Button.js +2 -2
  67. package/ui/button/Button.md +28 -0
  68. package/ui/button/Button.module.css +23 -5
  69. package/ui/button/Button.tsx +4 -3
  70. package/ui/button/Clickable.d.ts +3 -3
  71. package/ui/button/Clickable.js +6 -4
  72. package/ui/button/Clickable.tsx +9 -9
  73. package/ui/button/FullscreenButton.d.ts +3 -5
  74. package/ui/button/FullscreenButton.tsx +3 -2
  75. package/ui/button/RetryButton.d.ts +2 -2
  76. package/ui/button/RetryButton.tsx +2 -2
  77. package/ui/button/SubmitButton.d.ts +3 -3
  78. package/ui/button/SubmitButton.js +3 -2
  79. package/ui/button/SubmitButton.tsx +5 -3
  80. package/ui/dialog/Dialog.d.ts +6 -4
  81. package/ui/dialog/Dialog.js +7 -4
  82. package/ui/dialog/Dialog.tsx +19 -7
  83. package/ui/dialog/Modal.d.ts +3 -3
  84. package/ui/dialog/Modal.js +3 -3
  85. package/ui/dialog/Modal.tsx +5 -5
  86. package/ui/docs/DocumentationButtons.d.ts +3 -2
  87. package/ui/docs/DocumentationButtons.js +2 -2
  88. package/ui/docs/DocumentationButtons.tsx +4 -1
  89. package/ui/form/Field.d.ts +3 -3
  90. package/ui/form/Field.js +2 -2
  91. package/ui/form/Field.tsx +4 -3
  92. package/ui/form/Form.d.ts +2 -2
  93. package/ui/form/Form.js +3 -2
  94. package/ui/form/Form.tsx +5 -3
  95. package/ui/form/FormFields.d.ts +1 -1
  96. package/ui/form/FormFields.js +2 -2
  97. package/ui/form/FormFields.tsx +2 -2
  98. package/ui/form/FormFooter.d.ts +3 -3
  99. package/ui/form/FormFooter.js +2 -2
  100. package/ui/form/FormFooter.tsx +4 -4
  101. package/ui/form/FormMessage.d.ts +2 -2
  102. package/ui/form/FormMessage.tsx +2 -3
  103. package/ui/form/Progress.d.ts +3 -2
  104. package/ui/form/Progress.js +2 -2
  105. package/ui/form/Progress.tsx +4 -2
  106. package/ui/inline/Code.d.ts +3 -3
  107. package/ui/inline/Code.js +2 -2
  108. package/ui/inline/Code.tsx +4 -3
  109. package/ui/inline/Deleted.d.ts +3 -3
  110. package/ui/inline/Deleted.js +2 -2
  111. package/ui/inline/Deleted.tsx +4 -3
  112. package/ui/inline/Emphasis.d.ts +3 -3
  113. package/ui/inline/Emphasis.js +2 -2
  114. package/ui/inline/Emphasis.tsx +4 -3
  115. package/ui/inline/Inserted.d.ts +3 -3
  116. package/ui/inline/Inserted.js +2 -2
  117. package/ui/inline/Inserted.tsx +4 -3
  118. package/ui/inline/Link.d.ts +3 -2
  119. package/ui/inline/Link.js +2 -2
  120. package/ui/inline/Link.tsx +4 -2
  121. package/ui/inline/Mark.d.ts +3 -3
  122. package/ui/inline/Mark.js +2 -2
  123. package/ui/inline/Mark.tsx +4 -3
  124. package/ui/inline/Small.d.ts +3 -3
  125. package/ui/inline/Small.js +2 -2
  126. package/ui/inline/Small.tsx +4 -3
  127. package/ui/inline/Span.d.ts +3 -3
  128. package/ui/inline/Span.js +3 -2
  129. package/ui/inline/Span.tsx +5 -4
  130. package/ui/inline/Strong.d.ts +3 -3
  131. package/ui/inline/Strong.js +2 -2
  132. package/ui/inline/Strong.tsx +4 -3
  133. package/ui/inline/Subscript.d.ts +3 -3
  134. package/ui/inline/Subscript.js +3 -3
  135. package/ui/inline/Subscript.tsx +5 -5
  136. package/ui/inline/Superscript.d.ts +3 -3
  137. package/ui/inline/Superscript.js +3 -3
  138. package/ui/inline/Superscript.tsx +5 -5
  139. package/ui/input/ArrayInput.js +2 -2
  140. package/ui/input/ArrayInput.tsx +2 -1
  141. package/ui/input/ArrayRadioInputs.d.ts +1 -1
  142. package/ui/input/ArrayRadioInputs.js +2 -2
  143. package/ui/input/ArrayRadioInputs.tsx +2 -1
  144. package/ui/input/ButtonInput.d.ts +1 -1
  145. package/ui/input/ButtonInput.js +2 -2
  146. package/ui/input/ButtonInput.tsx +2 -1
  147. package/ui/input/CheckboxInput.d.ts +1 -1
  148. package/ui/input/CheckboxInput.js +2 -2
  149. package/ui/input/CheckboxInput.tsx +2 -0
  150. package/ui/input/ChoiceRadioInputs.js +2 -2
  151. package/ui/input/ChoiceRadioInputs.tsx +2 -1
  152. package/ui/input/DataInput.js +2 -2
  153. package/ui/input/DataInput.tsx +2 -1
  154. package/ui/input/DateInput.d.ts +1 -1
  155. package/ui/input/DateInput.js +2 -2
  156. package/ui/input/DateInput.tsx +2 -1
  157. package/ui/input/DictionaryInput.js +2 -2
  158. package/ui/input/DictionaryInput.tsx +2 -1
  159. package/ui/input/FileInput.d.ts +1 -1
  160. package/ui/input/FileInput.js +3 -2
  161. package/ui/input/FileInput.tsx +3 -1
  162. package/ui/input/Input.d.ts +10 -3
  163. package/ui/input/Input.js +2 -2
  164. package/ui/input/Input.tsx +11 -4
  165. package/ui/input/NumberInput.d.ts +1 -1
  166. package/ui/input/NumberInput.js +2 -2
  167. package/ui/input/NumberInput.tsx +2 -1
  168. package/ui/input/OutputInput.d.ts +1 -1
  169. package/ui/input/OutputInput.js +2 -2
  170. package/ui/input/OutputInput.tsx +2 -2
  171. package/ui/input/Popover.d.ts +4 -2
  172. package/ui/input/Popover.js +4 -3
  173. package/ui/input/Popover.tsx +6 -3
  174. package/ui/input/PopoverButton.d.ts +28 -0
  175. package/ui/input/{ButtonPopover.js → PopoverButton.js} +10 -8
  176. package/ui/input/PopoverButton.tsx +44 -0
  177. package/ui/input/PopoverButtonInput.d.ts +27 -0
  178. package/ui/input/{ButtonInputPopover.js → PopoverButtonInput.js} +10 -8
  179. package/ui/input/PopoverButtonInput.tsx +44 -0
  180. package/ui/input/QueryInput.d.ts +1 -1
  181. package/ui/input/QueryInput.js +2 -2
  182. package/ui/input/QueryInput.tsx +2 -0
  183. package/ui/input/RadioInput.d.ts +1 -1
  184. package/ui/input/RadioInput.js +2 -2
  185. package/ui/input/RadioInput.tsx +2 -0
  186. package/ui/input/SchemaInput.d.ts +1 -1
  187. package/ui/input/SchemaInput.js +2 -2
  188. package/ui/input/SchemaInput.tsx +2 -2
  189. package/ui/input/SelectInput.js +2 -2
  190. package/ui/input/SelectInput.tsx +2 -1
  191. package/ui/input/TextInput.d.ts +1 -1
  192. package/ui/input/TextInput.js +3 -3
  193. package/ui/input/TextInput.tsx +3 -2
  194. package/ui/input/index.d.ts +2 -2
  195. package/ui/input/index.js +2 -2
  196. package/ui/input/index.ts +2 -2
  197. package/ui/menu/Menu.d.ts +5 -5
  198. package/ui/menu/Menu.js +4 -4
  199. package/ui/menu/Menu.tsx +7 -6
  200. package/ui/misc/Icon.d.ts +2 -1
  201. package/ui/misc/Icon.js +2 -1
  202. package/ui/misc/Icon.tsx +3 -1
  203. package/ui/misc/Loading.d.ts +2 -3
  204. package/ui/misc/Loading.js +2 -2
  205. package/ui/misc/Loading.tsx +10 -3
  206. package/ui/misc/Tag.d.ts +3 -2
  207. package/ui/misc/Tag.js +2 -2
  208. package/ui/misc/Tag.tsx +4 -3
  209. package/ui/notice/Message.d.ts +3 -3
  210. package/ui/notice/Message.js +2 -2
  211. package/ui/notice/Message.tsx +4 -3
  212. package/ui/notice/Notice.d.ts +3 -3
  213. package/ui/notice/Notice.js +2 -2
  214. package/ui/notice/Notice.tsx +4 -2
  215. package/ui/notice/Notices.d.ts +3 -2
  216. package/ui/notice/Notices.js +2 -2
  217. package/ui/notice/Notices.tsx +4 -3
  218. package/ui/table/Cell.d.ts +3 -3
  219. package/ui/table/Cell.js +2 -2
  220. package/ui/table/Cell.tsx +4 -3
  221. package/ui/table/Table.d.ts +3 -3
  222. package/ui/table/Table.js +2 -2
  223. package/ui/table/Table.tsx +4 -3
  224. package/ui/tree/TreeBreadcrumbs.d.ts +3 -2
  225. package/ui/tree/TreeBreadcrumbs.js +2 -2
  226. package/ui/tree/TreeBreadcrumbs.tsx +4 -2
  227. package/ui/tree/TreeButton.d.ts +2 -1
  228. package/ui/tree/TreeButton.tsx +2 -1
  229. package/ui/util/ClassProps.md +56 -0
  230. package/ui/util/css.d.ts +1 -1
  231. package/ui/util/css.js +2 -2
  232. package/ui/util/css.test.ts +29 -0
  233. package/ui/util/css.ts +2 -2
  234. package/ui/util/props.d.ts +12 -0
  235. package/ui/util/props.test.tsx +100 -0
  236. package/ui/util/props.ts +13 -0
  237. package/ui/input/ButtonInputPopover.d.ts +0 -25
  238. package/ui/input/ButtonInputPopover.tsx +0 -41
  239. package/ui/input/ButtonPopover.d.ts +0 -25
  240. package/ui/input/ButtonPopover.tsx +0 -40
@@ -1,11 +1,11 @@
1
1
  import type { ReactElement } from "react";
2
- import type { OptionalChildProps } from "../util/props.js";
2
+ import type { ClassProps, OptionalChildProps } from "../util/props.js";
3
3
  /**
4
4
  * Props for `Superscript` — optional `children`.
5
5
  *
6
6
  * @see https://shelving.cc/ui/SuperscriptProps
7
7
  */
8
- export interface SuperscriptProps extends OptionalChildProps {
8
+ export interface SuperscriptProps extends OptionalChildProps, ClassProps {
9
9
  }
10
10
  /**
11
11
  * Superscript text — renders a `<sup>` element for typographically raised text (e.g. exponents, footnote markers).
@@ -14,4 +14,4 @@ export interface SuperscriptProps extends OptionalChildProps {
14
14
  * @example <>E = mc<Superscript>2</Superscript></>
15
15
  * @see https://shelving.cc/ui/Superscript
16
16
  */
17
- export declare function Superscript({ children }: SuperscriptProps): ReactElement;
17
+ export declare function Superscript({ children, className }: SuperscriptProps): ReactElement;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getModuleClass } from "../util/css.js";
2
+ import { getClass, getModuleClass } from "../util/css.js";
3
3
  import SUPERSCRIPT_CSS from "./Superscript.module.css";
4
4
  const SUPERSCRIPT_CLASS = getModuleClass(SUPERSCRIPT_CSS, "superscript");
5
5
  /**
@@ -9,6 +9,6 @@ const SUPERSCRIPT_CLASS = getModuleClass(SUPERSCRIPT_CSS, "superscript");
9
9
  * @example <>E = mc<Superscript>2</Superscript></>
10
10
  * @see https://shelving.cc/ui/Superscript
11
11
  */
12
- export function Superscript({ children }) {
13
- return _jsx("sup", { className: SUPERSCRIPT_CLASS, children: children });
12
+ export function Superscript({ children, className }) {
13
+ return _jsx("sup", { className: getClass(SUPERSCRIPT_CLASS, className), children: children });
14
14
  }
@@ -1,6 +1,6 @@
1
1
  import type { ReactElement } from "react";
2
- import { getModuleClass } from "../util/css.js";
3
- import type { OptionalChildProps } from "../util/props.js";
2
+ import { getClass, getModuleClass } from "../util/css.js";
3
+ import type { ClassProps, OptionalChildProps } from "../util/props.js";
4
4
  import SUPERSCRIPT_CSS from "./Superscript.module.css";
5
5
 
6
6
  const SUPERSCRIPT_CLASS = getModuleClass(SUPERSCRIPT_CSS, "superscript");
@@ -10,7 +10,7 @@ const SUPERSCRIPT_CLASS = getModuleClass(SUPERSCRIPT_CSS, "superscript");
10
10
  *
11
11
  * @see https://shelving.cc/ui/SuperscriptProps
12
12
  */
13
- export interface SuperscriptProps extends OptionalChildProps {}
13
+ export interface SuperscriptProps extends OptionalChildProps, ClassProps {}
14
14
 
15
15
  /**
16
16
  * Superscript text — renders a `<sup>` element for typographically raised text (e.g. exponents, footnote markers).
@@ -19,6 +19,6 @@ export interface SuperscriptProps extends OptionalChildProps {}
19
19
  * @example <>E = mc<Superscript>2</Superscript></>
20
20
  * @see https://shelving.cc/ui/Superscript
21
21
  */
22
- export function Superscript({ children }: SuperscriptProps): ReactElement {
23
- return <sup className={SUPERSCRIPT_CLASS}>{children}</sup>;
22
+ export function Superscript({ children, className }: SuperscriptProps): ReactElement {
23
+ return <sup className={getClass(SUPERSCRIPT_CLASS, className)}>{children}</sup>;
24
24
  }
@@ -10,12 +10,12 @@ import { ButtonInput } from "./ButtonInput.js";
10
10
  import { SchemaInput } from "./SchemaInput.js";
11
11
  export function ArrayInput({ name,
12
12
  // title,
13
- placeholder, required = false, disabled = false, message = "", value = [], onValue, one = "item", many = `${one}s`, min = 0, max = Number.POSITIVE_INFINITY, items, }) {
13
+ placeholder, required = false, disabled = false, message = "", value = [], onValue, one = "item", many = `${one}s`, min = 0, max = Number.POSITIVE_INFINITY, items, className, }) {
14
14
  const messages = splitMessage(message);
15
15
  const length = value.length;
16
16
  const disableRemove = disabled || length <= min;
17
17
  const addNewItem = () => onValue([...value, items.value]);
18
- return (_jsxs(Column, { children: [length ? (value.map((v, i) => {
18
+ return (_jsxs(Column, { className: className, children: [length ? (value.map((v, i) => {
19
19
  const k = i.toString();
20
20
  return (_jsxs(Row, { 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));
21
21
  })) : (_jsx(ButtonInput, { onClick: addNewItem, name: name, required: required && min > 1, disabled: disabled, children: placeholder })), _jsxs(Row, { children: [_jsxs(Button //
@@ -50,13 +50,14 @@ export function ArrayInput({
50
50
  min = 0,
51
51
  max = Number.POSITIVE_INFINITY,
52
52
  items,
53
+ className,
53
54
  }: ArrayInputProps<unknown>): ReactElement {
54
55
  const messages = splitMessage(message);
55
56
  const length = value.length;
56
57
  const disableRemove = disabled || length <= min;
57
58
  const addNewItem = () => onValue([...value, items.value]);
58
59
  return (
59
- <Column>
60
+ <Column className={className}>
60
61
  {length ? (
61
62
  value.map((v, i) => {
62
63
  const k = i.toString();
@@ -21,4 +21,4 @@ export interface ArrayRadioInputsProps<T> extends ValueInputProps<T> {
21
21
  * @example <ArrayRadioInputs name="size" items={["s", "m", "l"]} value={size} onValue={setSize} />
22
22
  * @see https://shelving.cc/ui/ArrayRadioInputs
23
23
  */
24
- export declare function ArrayRadioInputs<T>({ value, onValue, required, items, formatter, ...props }: ArrayRadioInputsProps<T>): ReactElement;
24
+ export declare function ArrayRadioInputs<T>({ value, onValue, required, items, formatter, className, ...props }: ArrayRadioInputsProps<T>): ReactElement;
@@ -11,8 +11,8 @@ import { RadioInput } from "./RadioInput.js";
11
11
  * @example <ArrayRadioInputs name="size" items={["s", "m", "l"]} value={size} onValue={setSize} />
12
12
  * @see https://shelving.cc/ui/ArrayRadioInputs
13
13
  */
14
- export function ArrayRadioInputs({ value, onValue, required = false, items, formatter = formatValue, ...props }) {
15
- return (_jsxs(Column, { children: [items.map((v, i) => {
14
+ export function ArrayRadioInputs({ value, onValue, required = false, items, formatter = formatValue, className, ...props }) {
15
+ return (_jsxs(Column, { className: className, children: [items.map((v, i) => {
16
16
  return (_jsx(RadioInput //
17
17
  , { value: value === v, onValue: () => onValue(v), required: required, ...props, children: formatter(v) }, i.toString()));
18
18
  }), !required ? (_jsx(RadioInput //
@@ -31,10 +31,11 @@ export function ArrayRadioInputs<T>({
31
31
  required = false,
32
32
  items,
33
33
  formatter = formatValue,
34
+ className,
34
35
  ...props
35
36
  }: ArrayRadioInputsProps<T>): ReactElement {
36
37
  return (
37
- <Column>
38
+ <Column className={className}>
38
39
  {items.map((v, i) => {
39
40
  return (
40
41
  <RadioInput //
@@ -18,4 +18,4 @@ export interface ButtonInputProps extends InputProps, ClickableProps, FlexVarian
18
18
  * @example <ButtonInput name="choose" onClick={open}>Choose…</ButtonInput>
19
19
  * @see https://shelving.cc/ui/ButtonInput
20
20
  */
21
- export declare function ButtonInput({ title, placeholder, children, ...props }: ButtonInputProps): ReactElement;
21
+ export declare function ButtonInput({ title, placeholder, children, className, ...props }: ButtonInputProps): ReactElement;
@@ -14,7 +14,7 @@ import INPUT_CSS from "./Input.module.css";
14
14
  * @example <ButtonInput name="choose" onClick={open}>Choose…</ButtonInput>
15
15
  * @see https://shelving.cc/ui/ButtonInput
16
16
  */
17
- export function ButtonInput({ title, placeholder, children = title, ...props }) {
17
+ export function ButtonInput({ title, placeholder, children = title, className, ...props }) {
18
18
  const hasChildren = notNullish(children);
19
- return (_jsx(Clickable, { ...props, className: getClass(getInputClass(props), getModuleClass(INPUT_CSS, "button"), getFlexClass(props), hasChildren && getModuleClass(INPUT_CSS, "placeholder")), children: hasChildren ? children : placeholder }));
19
+ return (_jsx(Clickable, { ...props, className: getClass(getInputClass(props), getModuleClass(INPUT_CSS, "button"), getFlexClass(props), hasChildren && getModuleClass(INPUT_CSS, "placeholder"), className), children: hasChildren ? children : placeholder }));
20
20
  }
@@ -22,7 +22,7 @@ export interface ButtonInputProps extends InputProps, ClickableProps, FlexVarian
22
22
  * @example <ButtonInput name="choose" onClick={open}>Choose…</ButtonInput>
23
23
  * @see https://shelving.cc/ui/ButtonInput
24
24
  */
25
- export function ButtonInput({ title, placeholder, children = title, ...props }: ButtonInputProps): ReactElement {
25
+ export function ButtonInput({ title, placeholder, children = title, className, ...props }: ButtonInputProps): ReactElement {
26
26
  const hasChildren = notNullish(children);
27
27
  return (
28
28
  <Clickable
@@ -32,6 +32,7 @@ export function ButtonInput({ title, placeholder, children = title, ...props }:
32
32
  getModuleClass(INPUT_CSS, "button"),
33
33
  getFlexClass(props),
34
34
  hasChildren && getModuleClass(INPUT_CSS, "placeholder"),
35
+ className,
35
36
  )}
36
37
  >
37
38
  {hasChildren ? children : placeholder}
@@ -17,4 +17,4 @@ export interface CheckboxProps extends ValueInputProps<boolean>, OptionalChildPr
17
17
  * @example <CheckboxInput name="agree" value={agree} onValue={setAgree}>I agree</CheckboxInput>
18
18
  * @see https://shelving.cc/ui/CheckboxInput
19
19
  */
20
- export declare function CheckboxInput({ name, title, placeholder, required, disabled, message, value, onValue, children, ...props }: CheckboxProps): ReactElement;
20
+ export declare function CheckboxInput({ name, title, placeholder, required, disabled, message, value, onValue, children, className, ...props }: CheckboxProps): ReactElement;
@@ -12,7 +12,7 @@ const INPUT_LABEL_CLASS = getModuleClass(INPUT_CSS, "label");
12
12
  * @example <CheckboxInput name="agree" value={agree} onValue={setAgree}>I agree</CheckboxInput>
13
13
  * @see https://shelving.cc/ui/CheckboxInput
14
14
  */
15
- export function CheckboxInput({ name, title, placeholder = title || "Yes", required = false, disabled = false, message = "", value = false, onValue, children = placeholder, ...props }) {
15
+ export function CheckboxInput({ name, title, placeholder = title || "Yes", required = false, disabled = false, message = "", value = false, onValue, children = placeholder, className, ...props }) {
16
16
  return (_jsxs("label", { className: getClass(getInputClass(props), //
17
- getFlexClass(props), INPUT_LABEL_CLASS), children: [_jsx("input", { className: getModuleClass(INPUT_CSS, "radio"), type: "checkbox", name: name, defaultChecked: !!value, onChange: e => onValue?.(!!e.currentTarget.checked), disabled: disabled, required: required, title: message, "aria-invalid": !!message }), _jsx("span", { children: children })] }));
17
+ getFlexClass(props), INPUT_LABEL_CLASS, className), children: [_jsx("input", { className: getModuleClass(INPUT_CSS, "radio"), type: "checkbox", name: name, defaultChecked: !!value, onChange: e => onValue?.(!!e.currentTarget.checked), disabled: disabled, required: required, title: message, "aria-invalid": !!message }), _jsx("span", { children: children })] }));
18
18
  }
@@ -32,6 +32,7 @@ export function CheckboxInput({
32
32
  value = false,
33
33
  onValue,
34
34
  children = placeholder,
35
+ className,
35
36
  ...props
36
37
  }: CheckboxProps): ReactElement {
37
38
  return (
@@ -40,6 +41,7 @@ export function CheckboxInput({
40
41
  getInputClass(props), //
41
42
  getFlexClass(props),
42
43
  INPUT_LABEL_CLASS,
44
+ className,
43
45
  )}
44
46
  >
45
47
  <input
@@ -4,10 +4,10 @@ import { Row } from "../block/Row.js";
4
4
  import { RadioInput } from "./RadioInput.js";
5
5
  /** Maximum number of options to show in a row. */
6
6
  const MAX_ROW_OPTIONS = 2;
7
- export function ChoiceRadioInputs({ required = false, value = "", onValue, wrap = false, column, options, ...props }) {
7
+ export function ChoiceRadioInputs({ required = false, value = "", onValue, wrap = false, column, options, className, ...props }) {
8
8
  const entries = getProps(options);
9
9
  const hasMany = entries.length > MAX_ROW_OPTIONS;
10
- return (_jsxs(Row, { wrap: wrap, column: column ?? hasMany, children: [entries.map(([k, t]) => (_jsx(RadioInput //
10
+ return (_jsxs(Row, { wrap: wrap, column: column ?? hasMany, className: className, children: [entries.map(([k, t]) => (_jsx(RadioInput //
11
11
  , { value: value === k, onValue: () => onValue(k), required: required, ...props, children: t }, k))), !required ? (_jsx(RadioInput //
12
12
  , { value: !value, onValue: () => onValue(undefined), required: required, ...props })) : null] }));
13
13
  }
@@ -40,12 +40,13 @@ export function ChoiceRadioInputs({
40
40
  wrap = false,
41
41
  column,
42
42
  options,
43
+ className,
43
44
  ...props
44
45
  }: ChoiceRadioInputsProps<string>): ReactElement {
45
46
  const entries = getProps(options);
46
47
  const hasMany = entries.length > MAX_ROW_OPTIONS;
47
48
  return (
48
- <Row wrap={wrap} column={column ?? hasMany}>
49
+ <Row wrap={wrap} column={column ?? hasMany} className={className}>
49
50
  {entries.map(([k, t]) => (
50
51
  <RadioInput //
51
52
  key={k}
@@ -9,9 +9,9 @@ export function DataInput({
9
9
  // placeholder,
10
10
  // required = false,
11
11
  // disabled = false,
12
- message = "", value = {}, onValue, props, }) {
12
+ message = "", value = {}, onValue, props, className, }) {
13
13
  const messages = splitMessage(message);
14
14
  const entries = getProps(props);
15
- return (_jsx(Row, { column: entries.length > 2, children: entries.map(([k, s]) => (_jsx(SchemaInput //
15
+ return (_jsx(Row, { column: entries.length > 2, className: className, children: entries.map(([k, s]) => (_jsx(SchemaInput //
16
16
  , { name: k, schema: s, value: value[k], onValue: x => onValue(withProp(value, k, x)), message: messages[k] }, k))) }));
17
17
  }
@@ -37,11 +37,12 @@ export function DataInput({
37
37
  value = {},
38
38
  onValue,
39
39
  props,
40
+ className,
40
41
  }: DataInputProps<Data>): ReactElement {
41
42
  const messages = splitMessage(message);
42
43
  const entries = getProps(props);
43
44
  return (
44
- <Row column={entries.length > 2}>
45
+ <Row column={entries.length > 2} className={className}>
45
46
  {entries.map(([k, s]) => (
46
47
  <SchemaInput //
47
48
  key={k}
@@ -22,4 +22,4 @@ export interface DateInputProps extends ValueInputProps<string, PossibleDate>, I
22
22
  * @see https://shelving.cc/ui/DateInput
23
23
  */
24
24
  export declare function DateInput({ name, title, placeholder, // Placeholder must be defined or `:placeholder-shown` CSS rules won't show.
25
- required, disabled, message, value, onValue, min, max, input, step, ...variants }: DateInputProps): ReactElement;
25
+ required, disabled, message, value, onValue, min, max, input, step, className, ...variants }: DateInputProps): ReactElement;
@@ -18,10 +18,10 @@ const _DATE_TO_STRING = {
18
18
  * @see https://shelving.cc/ui/DateInput
19
19
  */
20
20
  export function DateInput({ name, title = "", placeholder = title, // Placeholder must be defined or `:placeholder-shown` CSS rules won't show.
21
- required = false, disabled = false, message = "", value, onValue, min, max, input = "date", step, ...variants }) {
21
+ required = false, disabled = false, message = "", value, onValue, min, max, input = "date", step, className, ...variants }) {
22
22
  const onChange = (e) => {
23
23
  onValue?.(e.currentTarget.value ?? undefined);
24
24
  };
25
25
  const dateToString = _DATE_TO_STRING[input];
26
- return (_jsx("input", { name: name, type: input, min: dateToString(min), max: dateToString(max), disabled: disabled, required: required, defaultValue: dateToString(value), placeholder: placeholder || " ", className: getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text")), onChange: onChange, onInput: onChange, title: message, "aria-invalid": !!message, step: step }));
26
+ return (_jsx("input", { name: name, type: input, min: dateToString(min), max: dateToString(max), disabled: disabled, required: required, defaultValue: dateToString(value), placeholder: placeholder || " ", className: getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text"), className), onChange: onChange, onInput: onChange, title: message, "aria-invalid": !!message, step: step }));
27
27
  }
@@ -45,6 +45,7 @@ export function DateInput({
45
45
  max,
46
46
  input = "date",
47
47
  step,
48
+ className,
48
49
  ...variants
49
50
  }: DateInputProps): ReactElement {
50
51
  const onChange = (e: SyntheticEvent<HTMLInputElement>) => {
@@ -63,7 +64,7 @@ export function DateInput({
63
64
  required={required}
64
65
  defaultValue={dateToString(value)}
65
66
  placeholder={placeholder || " "}
66
- className={getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text"))}
67
+ className={getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text"), className)}
67
68
  onChange={onChange}
68
69
  onInput={onChange}
69
70
  title={message}
@@ -11,12 +11,12 @@ import { SchemaInput } from "./SchemaInput.js";
11
11
  import { TextInput } from "./TextInput.js";
12
12
  export function DictionaryInput({ name,
13
13
  // title,
14
- placeholder, required = false, disabled = false, message = "", value = {}, onValue, one = "item", many = `${one}s`, min = 0, max = Number.POSITIVE_INFINITY, items, }) {
14
+ placeholder, required = false, disabled = false, message = "", value = {}, onValue, one = "item", many = `${one}s`, min = 0, max = Number.POSITIVE_INFINITY, items, className, }) {
15
15
  const messages = splitMessage(message);
16
16
  const length = Object.keys(value).length;
17
17
  const disableRemove = disabled || length <= min;
18
18
  const addNewItem = () => onValue({ ...value, [one]: items.value });
19
- return (_jsxs(Row, { column: true, children: [length ? (Object.entries(value).map(([k, v], i) => {
19
+ return (_jsxs(Row, { column: true, className: className, children: [length ? (Object.entries(value).map(([k, v], i) => {
20
20
  const r = i.toString();
21
21
  const message = messages[r];
22
22
  return (_jsxs(Row, { children: [_jsx(TextInput, { name: `${r}-key`, value: k, onValue: x => {
@@ -52,13 +52,14 @@ export function DictionaryInput({
52
52
  min = 0,
53
53
  max = Number.POSITIVE_INFINITY,
54
54
  items,
55
+ className,
55
56
  }: DictionaryInputProps<unknown>): ReactElement {
56
57
  const messages = splitMessage(message);
57
58
  const length = Object.keys(value).length;
58
59
  const disableRemove = disabled || length <= min;
59
60
  const addNewItem = () => onValue({ ...value, [one]: items.value });
60
61
  return (
61
- <Row column>
62
+ <Row column className={className}>
62
63
  {length ? (
63
64
  Object.entries(value).map(([k, v], i) => {
64
65
  const r = i.toString();
@@ -17,4 +17,4 @@ export interface FileInputProps extends ValueInputProps<string | File>, InputVar
17
17
  * @example <FileInput name="avatar" types={{ png: "image/png" }} onValue={setFile} />
18
18
  * @see https://shelving.cc/ui/FileInput
19
19
  */
20
- export declare function FileInput({ name, title, placeholder, required, disabled, message, onValue, types, ...variants }: FileInputProps): ReactElement;
20
+ export declare function FileInput({ name, title, placeholder, required, disabled, message, onValue, types, className, ...variants }: FileInputProps): ReactElement;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { getClass } from "../util/css.js";
2
3
  import { getInputClass } from "./Input.js";
3
4
  /**
4
5
  * File picker input that emits the selected `File` through `onValue`.
@@ -10,12 +11,12 @@ import { getInputClass } from "./Input.js";
10
11
  */
11
12
  export function FileInput({ name, title, placeholder = title, required = false, disabled = false, message,
12
13
  // value,
13
- onValue, types = {}, ...variants }) {
14
+ onValue, types = {}, className, ...variants }) {
14
15
  const onChange = (e) => {
15
16
  const files = e.currentTarget.files;
16
17
  if (files)
17
18
  for (const file of files)
18
19
  onValue(file);
19
20
  };
20
- return (_jsx("input", { name: name, type: "file", accept: Object.values(types).join(","), required: required, disabled: disabled, placeholder: placeholder, className: getInputClass(variants), onChange: onChange, onInput: onChange, multiple: false, title: message, "aria-invalid": !!message }));
21
+ return (_jsx("input", { name: name, type: "file", accept: Object.values(types).join(","), required: required, disabled: disabled, placeholder: placeholder, className: getClass(getInputClass(variants), className), onChange: onChange, onInput: onChange, multiple: false, title: message, "aria-invalid": !!message }));
21
22
  }
@@ -1,5 +1,6 @@
1
1
  import type { ReactElement, SyntheticEvent } from "react";
2
2
  import type { FileTypes } from "../../util/file.js";
3
+ import { getClass } from "../util/css.js";
3
4
  import { getInputClass, type InputVariants, type ValueInputProps } from "./Input.js";
4
5
 
5
6
  /**
@@ -29,6 +30,7 @@ export function FileInput({
29
30
  // value,
30
31
  onValue,
31
32
  types = {},
33
+ className,
32
34
  ...variants
33
35
  }: FileInputProps): ReactElement {
34
36
  const onChange = (e: SyntheticEvent<HTMLInputElement>) => {
@@ -44,7 +46,7 @@ export function FileInput({
44
46
  required={required}
45
47
  disabled={disabled}
46
48
  placeholder={placeholder}
47
- className={getInputClass(variants)}
49
+ className={getClass(getInputClass(variants), className)}
48
50
  onChange={onChange}
49
51
  onInput={onChange}
50
52
  multiple={false}
@@ -1,6 +1,6 @@
1
1
  import type { ReactElement } from "react";
2
2
  import { type WidthVariants } from "../style/Width.js";
3
- import type { ChildProps } from "../util/props.js";
3
+ import type { ChildProps, ClassProps } from "../util/props.js";
4
4
  /**
5
5
  * Styling variants shared by every form input — currently the `width` variant (`width="narrow"`, `"normal"`, `"wide"`, `"full"`, `"fit"`).
6
6
  * - Extends `WidthVariants` so any input can be sized (e.g. `<CheckboxInput width="fit">` to shrink to its content).
@@ -23,7 +23,7 @@ export declare function getInputClass(props: InputVariants): string;
23
23
  *
24
24
  * @see https://shelving.cc/ui/InputProps
25
25
  */
26
- export interface InputProps {
26
+ export interface InputProps extends ClassProps {
27
27
  /** The `name=""` prop of the input. */
28
28
  name: string;
29
29
  /** Friendly title for the input. */
@@ -46,9 +46,16 @@ export interface ValueInputProps<O, I = never> extends InputProps {
46
46
  }
47
47
  /** Input that is loading. */
48
48
  export declare const LOADING_INPUT: import("react").JSX.Element;
49
+ /**
50
+ * Props for `InputWrapper` — the wrapped `children` plus an optional `className`.
51
+ *
52
+ * @see https://shelving.cc/ui/InputWrapperProps
53
+ */
54
+ export interface InputWrapperProps extends ChildProps, ClassProps {
55
+ }
49
56
  /**
50
57
  * Wraps an input with support for absolutely-positioned `data-slot` icon elements on either side.
51
58
  * - This is so you can put an icon before or after an input.
52
59
  * @kind component
53
60
  */
54
- export declare function InputWrapper({ children }: ChildProps): ReactElement;
61
+ export declare function InputWrapper({ children, className }: InputWrapperProps): ReactElement;
package/ui/input/Input.js CHANGED
@@ -21,6 +21,6 @@ export const LOADING_INPUT = _jsx("div", { className: getClass(getInputClass({})
21
21
  * - This is so you can put an icon before or after an input.
22
22
  * @kind component
23
23
  */
24
- export function InputWrapper({ children }) {
25
- return _jsx("div", { className: getClass(getInputClass({}), getModuleClass(INPUT_CSS, "wrapper")), children: children });
24
+ export function InputWrapper({ children, className }) {
25
+ return _jsx("div", { className: getClass(getInputClass({}), getModuleClass(INPUT_CSS, "wrapper"), className), children: children });
26
26
  }
@@ -3,7 +3,7 @@ import { LOADING } from "../misc/Loading.js";
3
3
  import { getFlexClass } from "../style/Flex.js";
4
4
  import { getWidthClass, type WidthVariants } from "../style/Width.js";
5
5
  import { getClass, getModuleClass } from "../util/css.js";
6
- import type { ChildProps } from "../util/props.js";
6
+ import type { ChildProps, ClassProps } from "../util/props.js";
7
7
  import INPUT_CSS from "./Input.module.css";
8
8
 
9
9
  /**
@@ -31,7 +31,7 @@ export function getInputClass(props: InputVariants): string {
31
31
  *
32
32
  * @see https://shelving.cc/ui/InputProps
33
33
  */
34
- export interface InputProps {
34
+ export interface InputProps extends ClassProps {
35
35
  /** The `name=""` prop of the input. */
36
36
  name: string;
37
37
  /** Friendly title for the input. */
@@ -57,11 +57,18 @@ export interface ValueInputProps<O, I = never> extends InputProps {
57
57
  /** Input that is loading. */
58
58
  export const LOADING_INPUT = <div className={getClass(getInputClass({}), getFlexClass({}))}>{LOADING}</div>;
59
59
 
60
+ /**
61
+ * Props for `InputWrapper` — the wrapped `children` plus an optional `className`.
62
+ *
63
+ * @see https://shelving.cc/ui/InputWrapperProps
64
+ */
65
+ export interface InputWrapperProps extends ChildProps, ClassProps {}
66
+
60
67
  /**
61
68
  * Wraps an input with support for absolutely-positioned `data-slot` icon elements on either side.
62
69
  * - This is so you can put an icon before or after an input.
63
70
  * @kind component
64
71
  */
65
- export function InputWrapper({ children }: ChildProps): ReactElement {
66
- return <div className={getClass(getInputClass({}), getModuleClass(INPUT_CSS, "wrapper"))}>{children}</div>;
72
+ export function InputWrapper({ children, className }: InputWrapperProps): ReactElement {
73
+ return <div className={getClass(getInputClass({}), getModuleClass(INPUT_CSS, "wrapper"), className)}>{children}</div>;
67
74
  }
@@ -21,5 +21,5 @@ export interface NumberInputProps extends ValueInputProps<number>, InputVariants
21
21
  * @see https://shelving.cc/ui/NumberInput
22
22
  */
23
23
  export declare function NumberInput({ name, title, placeholder, // Placeholder must be defined or `:placeholder-shown` CSS rules won't show.
24
- required, disabled, message, value, onValue, formatter, ...variants }: NumberInputProps): ReactElement;
24
+ required, disabled, message, value, onValue, formatter, className, ...variants }: NumberInputProps): ReactElement;
25
25
  export {};
@@ -16,7 +16,7 @@ export function NumberInput({ name, title = "", placeholder = title, // Placehol
16
16
  required = false, disabled = false, message = "", value, onValue,
17
17
  // min = Number.NEGATIVE_INFINITY,
18
18
  // max = Number.POSITIVE_INFINITY,
19
- formatter = formatNumber, ...variants }) {
19
+ formatter = formatNumber, className, ...variants }) {
20
20
  const onChange = ({ currentTarget }) => {
21
21
  onValue?.(getNumber(currentTarget.value) ?? undefined);
22
22
  };
@@ -24,5 +24,5 @@ formatter = formatNumber, ...variants }) {
24
24
  const num = getNumber(currentTarget.value);
25
25
  currentTarget.value = num !== undefined ? formatter(num) : "";
26
26
  };
27
- return (_jsx("input", { name: name, type: "text", inputMode: "decimal", defaultValue: value !== undefined ? formatter(value) : "", required: required, disabled: disabled, placeholder: placeholder || " ", className: getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text")), onChange: onChange, onInput: onChange, onBlur: onBlur, title: message, "aria-invalid": !!message }));
27
+ return (_jsx("input", { name: name, type: "text", inputMode: "decimal", defaultValue: value !== undefined ? formatter(value) : "", required: required, disabled: disabled, placeholder: placeholder || " ", className: getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text"), className), onChange: onChange, onInput: onChange, onBlur: onBlur, title: message, "aria-invalid": !!message }));
28
28
  }
@@ -39,6 +39,7 @@ export function NumberInput({
39
39
  // min = Number.NEGATIVE_INFINITY,
40
40
  // max = Number.POSITIVE_INFINITY,
41
41
  formatter = formatNumber,
42
+ className,
42
43
  ...variants
43
44
  }: NumberInputProps): ReactElement {
44
45
  const onChange = ({ currentTarget }: SyntheticEvent<HTMLInputElement>) => {
@@ -59,7 +60,7 @@ export function NumberInput({
59
60
  required={required}
60
61
  disabled={disabled}
61
62
  placeholder={placeholder || " "}
62
- className={getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text"))}
63
+ className={getClass(getInputClass(variants), getModuleClass(INPUT_CSS, "text"), className)}
63
64
  onChange={onChange}
64
65
  onInput={onChange}
65
66
  onBlur={onBlur}
@@ -17,4 +17,4 @@ export interface OutputInputProps extends InputProps, OptionalChildProps, FlexVa
17
17
  * @example <OutputInput title="Status">Active</OutputInput>
18
18
  * @see https://shelving.cc/ui/OutputInput
19
19
  */
20
- export declare function OutputInput({ title, placeholder, children, ...props }: OutputInputProps): ReactElement;
20
+ export declare function OutputInput({ title, placeholder, children, className, ...props }: OutputInputProps): ReactElement;
@@ -12,7 +12,7 @@ import INPUT_CSS from "./Input.module.css";
12
12
  * @example <OutputInput title="Status">Active</OutputInput>
13
13
  * @see https://shelving.cc/ui/OutputInput
14
14
  */
15
- export function OutputInput({ title, placeholder, children = title, ...props }) {
15
+ export function OutputInput({ title, placeholder, children = title, className, ...props }) {
16
16
  const hasChildren = notNullish(children);
17
- return (_jsx("output", { ...props, className: getClass(getInputClass(props), getFlexClass(props), hasChildren && getModuleClass(INPUT_CSS, "placeholder")), children: hasChildren ? children : placeholder }));
17
+ return (_jsx("output", { ...props, className: getClass(getInputClass(props), getFlexClass(props), hasChildren && getModuleClass(INPUT_CSS, "placeholder"), className), children: hasChildren ? children : placeholder }));
18
18
  }
@@ -21,12 +21,12 @@ export interface OutputInputProps extends InputProps, OptionalChildProps, FlexVa
21
21
  * @example <OutputInput title="Status">Active</OutputInput>
22
22
  * @see https://shelving.cc/ui/OutputInput
23
23
  */
24
- export function OutputInput({ title, placeholder, children = title, ...props }: OutputInputProps): ReactElement {
24
+ export function OutputInput({ title, placeholder, children = title, className, ...props }: OutputInputProps): ReactElement {
25
25
  const hasChildren = notNullish(children);
26
26
  return (
27
27
  <output
28
28
  {...props}
29
- className={getClass(getInputClass(props), getFlexClass(props), hasChildren && getModuleClass(INPUT_CSS, "placeholder"))}
29
+ className={getClass(getInputClass(props), getFlexClass(props), hasChildren && getModuleClass(INPUT_CSS, "placeholder"), className)}
30
30
  >
31
31
  {hasChildren ? children : placeholder}
32
32
  </output>
@@ -2,6 +2,7 @@
2
2
  /** biome-ignore-all lint/a11y/useKeyWithClickEvents: This is fine we're only using this to listen for clicks on child buttons. */
3
3
  import type { ReactElement, ReactNode } from "react";
4
4
  import type { Callback } from "../../util/function.js";
5
+ import type { ClassProps } from "../util/props.js";
5
6
  /**
6
7
  * Children tuple for `Popover`: a leading trigger node followed by the popover's contents.
7
8
  *
@@ -23,7 +24,7 @@ export type PopoverChildren = readonly [
23
24
  *
24
25
  * @see https://shelving.cc/ui/PopoverProps
25
26
  */
26
- export interface PopoverProps {
27
+ export interface PopoverProps extends ClassProps {
27
28
  /** Children for the popover. */
28
29
  children: PopoverChildren;
29
30
  /** Callback that gets called when the Popover closes. */
@@ -35,6 +36,7 @@ export interface PopoverProps {
35
36
  * Trigger element that reveals a floating popover panel beside it when active or focused.
36
37
  * - The first `children` node is the trigger; the rest become the popover contents.
37
38
  * - Closes on blur away or `Escape`, calling `onClose`.
39
+ * - `className` lands on the floating panel rather than the wrapper, since the panel is the surface worth styling.
38
40
  *
39
41
  * @returns A wrapper element containing the trigger and (when open) the popover panel.
40
42
  * @example <Popover>{trigger}{panelContent}</Popover>
@@ -43,4 +45,4 @@ export interface PopoverProps {
43
45
  * @todo DH: Would love to use new HTML `popover="auto"` functionality for this but the anchor positioning it needs is not supported everywhere yet.
44
46
  */
45
47
  export declare function Popover({ children: [trigger, ...popover], //
46
- onClose, open, }: PopoverProps): ReactElement;
48
+ onClose, open, className, }: PopoverProps): ReactElement;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { isTruthy } from "../../util/boolean.js";
3
- import { getModuleClass } from "../util/css.js";
3
+ import { getClass, getModuleClass } from "../util/css.js";
4
4
  import { eventPreventDefault } from "../util/event.js";
5
5
  import { eventLoopFocus } from "../util/focus.js";
6
6
  import styles from "./Popover.module.css";
@@ -8,6 +8,7 @@ import styles from "./Popover.module.css";
8
8
  * Trigger element that reveals a floating popover panel beside it when active or focused.
9
9
  * - The first `children` node is the trigger; the rest become the popover contents.
10
10
  * - Closes on blur away or `Escape`, calling `onClose`.
11
+ * - `className` lands on the floating panel rather than the wrapper, since the panel is the surface worth styling.
11
12
  *
12
13
  * @returns A wrapper element containing the trigger and (when open) the popover panel.
13
14
  * @example <Popover>{trigger}{panelContent}</Popover>
@@ -16,11 +17,11 @@ import styles from "./Popover.module.css";
16
17
  * @todo DH: Would love to use new HTML `popover="auto"` functionality for this but the anchor positioning it needs is not supported everywhere yet.
17
18
  */
18
19
  export function Popover({ children: [trigger, ...popover], //
19
- onClose, open = popover.flat().some(isTruthy), }) {
20
+ onClose, open = popover.flat().some(isTruthy), className, }) {
20
21
  return (_jsxs("div", { className: getModuleClass(styles, "wrap"), onBlur: e => {
21
22
  if (e.relatedTarget)
22
23
  eventLoopFocus(e);
23
24
  else
24
25
  onClose?.();
25
- }, onKeyDown: e => e.key === "Escape" && onClose?.(), children: [trigger, open ? (_jsx("section", { className: getModuleClass(styles, "panel"), onMouseDown: eventPreventDefault, children: popover })) : null] }));
26
+ }, onKeyDown: e => e.key === "Escape" && onClose?.(), children: [trigger, open ? (_jsx("section", { className: getClass(getModuleClass(styles, "panel"), className), onMouseDown: eventPreventDefault, children: popover })) : null] }));
26
27
  }