shelving 1.264.0 → 1.264.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/package.json +1 -1
  2. package/ui/block/Card.d.ts +1 -1
  3. package/ui/block/Card.js +1 -1
  4. package/ui/block/Card.tsx +1 -1
  5. package/ui/block/Image.d.ts +3 -3
  6. package/ui/block/Image.js +4 -4
  7. package/ui/block/Image.module.css +4 -1
  8. package/ui/block/Image.tsx +14 -4
  9. package/ui/block/Video.d.ts +3 -58
  10. package/ui/block/Video.js +2 -52
  11. package/ui/block/Video.module.css +1 -51
  12. package/ui/block/Video.tsx +3 -99
  13. package/ui/{form → button}/Button.d.ts +6 -2
  14. package/ui/{form → button}/Button.tsx +6 -1
  15. package/ui/button/FullscreenButton.d.ts +31 -0
  16. package/ui/button/FullscreenButton.js +37 -0
  17. package/ui/button/FullscreenButton.tsx +58 -0
  18. package/ui/button/RetryButton.d.ts +29 -0
  19. package/ui/button/RetryButton.js +27 -0
  20. package/ui/button/RetryButton.tsx +48 -0
  21. package/ui/{form → button}/SubmitButton.d.ts +12 -8
  22. package/ui/{form → button}/SubmitButton.js +4 -4
  23. package/ui/{form → button}/SubmitButton.tsx +22 -18
  24. package/ui/button/index.d.ts +5 -0
  25. package/ui/button/index.js +5 -0
  26. package/ui/button/index.ts +5 -0
  27. package/ui/dialog/Dialog.d.ts +1 -1
  28. package/ui/dialog/Dialog.tsx +1 -1
  29. package/ui/docs/DocumentationSearchPage.js +2 -2
  30. package/ui/docs/DocumentationSearchPage.tsx +2 -2
  31. package/ui/form/FormContext.d.ts +1 -1
  32. package/ui/form/FormContext.js +1 -1
  33. package/ui/form/FormContext.tsx +1 -1
  34. package/ui/form/FormFields.d.ts +1 -1
  35. package/ui/form/FormFields.js +1 -1
  36. package/ui/form/FormFields.tsx +2 -2
  37. package/ui/form/FormFooter.js +1 -1
  38. package/ui/form/FormFooter.tsx +1 -1
  39. package/ui/form/FormInput.d.ts +1 -1
  40. package/ui/form/FormInput.js +1 -1
  41. package/ui/form/FormInput.tsx +2 -2
  42. package/ui/form/Progress.d.ts +6 -24
  43. package/ui/form/Progress.js +9 -20
  44. package/ui/form/Progress.module.css +13 -32
  45. package/ui/form/Progress.tsx +18 -51
  46. package/ui/form/index.d.ts +0 -23
  47. package/ui/form/index.js +0 -23
  48. package/ui/form/index.ts +0 -23
  49. package/ui/index.d.ts +2 -0
  50. package/ui/index.js +2 -0
  51. package/ui/index.ts +2 -0
  52. package/ui/inline/Link.d.ts +1 -1
  53. package/ui/inline/Link.js +1 -1
  54. package/ui/inline/Link.tsx +1 -1
  55. package/ui/{form → input}/ArrayInput.js +1 -1
  56. package/ui/{form → input}/ArrayInput.tsx +1 -1
  57. package/ui/{form → input}/ButtonInput.d.ts +1 -1
  58. package/ui/{form → input}/ButtonInput.js +1 -1
  59. package/ui/{form → input}/ButtonInput.tsx +1 -1
  60. package/ui/{form → input}/ButtonPopover.d.ts +1 -1
  61. package/ui/{form → input}/ButtonPopover.js +1 -1
  62. package/ui/{form → input}/ButtonPopover.tsx +1 -1
  63. package/ui/{form → input}/DictionaryInput.js +1 -1
  64. package/ui/{form → input}/DictionaryInput.tsx +1 -1
  65. package/ui/{form → input}/SchemaInput.js +1 -1
  66. package/ui/{form → input}/SchemaInput.test.tsx +2 -3
  67. package/ui/{form → input}/SchemaInput.tsx +1 -1
  68. package/ui/{form → input}/TextInput.d.ts +1 -1
  69. package/ui/{form → input}/TextInput.js +1 -1
  70. package/ui/{form → input}/TextInput.tsx +1 -1
  71. package/ui/input/index.d.ts +20 -0
  72. package/ui/input/index.js +20 -0
  73. package/ui/input/index.ts +20 -0
  74. package/ui/layout/Layout.d.ts +1 -1
  75. package/ui/layout/Layout.js +4 -0
  76. package/ui/layout/Layout.ts +6 -0
  77. package/ui/layout/SidebarLayout.js +1 -1
  78. package/ui/layout/SidebarLayout.tsx +1 -1
  79. package/ui/menu/Menu.d.ts +1 -1
  80. package/ui/menu/Menu.js +1 -1
  81. package/ui/menu/Menu.tsx +1 -1
  82. package/ui/misc/Catcher.d.ts +2 -19
  83. package/ui/misc/Catcher.js +3 -22
  84. package/ui/misc/Catcher.tsx +4 -40
  85. package/ui/misc/Tag.d.ts +1 -1
  86. package/ui/misc/Tag.js +1 -1
  87. package/ui/misc/Tag.tsx +1 -1
  88. package/ui/tree/TreeButton.d.ts +1 -1
  89. package/ui/tree/TreeButton.js +1 -1
  90. package/ui/tree/TreeButton.tsx +1 -1
  91. package/ui/tree/TreeSidebar.js +1 -1
  92. package/ui/tree/TreeSidebar.tsx +1 -1
  93. /package/ui/{form → button}/Button.js +0 -0
  94. /package/ui/{form → button}/Button.md +0 -0
  95. /package/ui/{form → button}/Button.module.css +0 -0
  96. /package/ui/{form → button}/Clickable.d.ts +0 -0
  97. /package/ui/{form → button}/Clickable.js +0 -0
  98. /package/ui/{form → button}/Clickable.tsx +0 -0
  99. /package/ui/{form → input}/ArrayInput.d.ts +0 -0
  100. /package/ui/{form → input}/ArrayRadioInputs.d.ts +0 -0
  101. /package/ui/{form → input}/ArrayRadioInputs.js +0 -0
  102. /package/ui/{form → input}/ArrayRadioInputs.tsx +0 -0
  103. /package/ui/{form → input}/ButtonInputPopover.d.ts +0 -0
  104. /package/ui/{form → input}/ButtonInputPopover.js +0 -0
  105. /package/ui/{form → input}/ButtonInputPopover.tsx +0 -0
  106. /package/ui/{form → input}/CheckboxInput.d.ts +0 -0
  107. /package/ui/{form → input}/CheckboxInput.js +0 -0
  108. /package/ui/{form → input}/CheckboxInput.tsx +0 -0
  109. /package/ui/{form → input}/ChoiceRadioInputs.d.ts +0 -0
  110. /package/ui/{form → input}/ChoiceRadioInputs.js +0 -0
  111. /package/ui/{form → input}/ChoiceRadioInputs.tsx +0 -0
  112. /package/ui/{form → input}/DataInput.d.ts +0 -0
  113. /package/ui/{form → input}/DataInput.js +0 -0
  114. /package/ui/{form → input}/DataInput.tsx +0 -0
  115. /package/ui/{form → input}/DateInput.d.ts +0 -0
  116. /package/ui/{form → input}/DateInput.js +0 -0
  117. /package/ui/{form → input}/DateInput.tsx +0 -0
  118. /package/ui/{form → input}/DictionaryInput.d.ts +0 -0
  119. /package/ui/{form → input}/FileInput.d.ts +0 -0
  120. /package/ui/{form → input}/FileInput.js +0 -0
  121. /package/ui/{form → input}/FileInput.tsx +0 -0
  122. /package/ui/{form → input}/Input.d.ts +0 -0
  123. /package/ui/{form → input}/Input.js +0 -0
  124. /package/ui/{form → input}/Input.module.css +0 -0
  125. /package/ui/{form → input}/Input.tsx +0 -0
  126. /package/ui/{form → input}/NumberInput.d.ts +0 -0
  127. /package/ui/{form → input}/NumberInput.js +0 -0
  128. /package/ui/{form → input}/NumberInput.tsx +0 -0
  129. /package/ui/{form → input}/OutputInput.d.ts +0 -0
  130. /package/ui/{form → input}/OutputInput.js +0 -0
  131. /package/ui/{form → input}/OutputInput.tsx +0 -0
  132. /package/ui/{form → input}/Popover.d.ts +0 -0
  133. /package/ui/{form → input}/Popover.js +0 -0
  134. /package/ui/{form → input}/Popover.module.css +0 -0
  135. /package/ui/{form → input}/Popover.tsx +0 -0
  136. /package/ui/{form → input}/QueryInput.d.ts +0 -0
  137. /package/ui/{form → input}/QueryInput.js +0 -0
  138. /package/ui/{form → input}/QueryInput.tsx +0 -0
  139. /package/ui/{form → input}/RadioInput.d.ts +0 -0
  140. /package/ui/{form → input}/RadioInput.js +0 -0
  141. /package/ui/{form → input}/RadioInput.tsx +0 -0
  142. /package/ui/{form → input}/SchemaInput.d.ts +0 -0
  143. /package/ui/{form → input}/SchemaInput.md +0 -0
  144. /package/ui/{form → input}/SelectInput.d.ts +0 -0
  145. /package/ui/{form → input}/SelectInput.js +0 -0
  146. /package/ui/{form → input}/SelectInput.tsx +0 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.264.0",
3
+ "version": "1.264.1",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,5 +1,5 @@
1
1
  import type { ReactElement } from "react";
2
- import { type ClickableProps } from "../form/Clickable.js";
2
+ import { type ClickableProps } from "../button/Clickable.js";
3
3
  import { type BlockVariants } from "../style/Block.js";
4
4
  import { type StatusVariants } from "../style/Status.js";
5
5
  import type { BlockElement } from "./Block.js";
package/ui/block/Card.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Clickable } from "../form/Clickable.js";
2
+ import { Clickable } from "../button/Clickable.js";
3
3
  import { getBlockClass } from "../style/Block.js";
4
4
  import { getStatusClass } from "../style/Status.js";
5
5
  import { getClass, getModuleClass } from "../util/css.js";
package/ui/block/Card.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ReactElement } from "react";
2
- import { Clickable, type ClickableProps } from "../form/Clickable.js";
2
+ import { Clickable, type ClickableProps } from "../button/Clickable.js";
3
3
  import { type BlockVariants, getBlockClass } from "../style/Block.js";
4
4
  import { getStatusClass, type StatusVariants } from "../style/Status.js";
5
5
  import { getClass, getModuleClass } from "../util/css.js";
@@ -1,6 +1,6 @@
1
1
  import type { ReactElement } from "react";
2
- import { type SpaceVariants } from "../style/Space.js";
3
- import { type WidthVariants } from "../style/Width.js";
2
+ import type { SpaceVariants } from "../style/Space.js";
3
+ import type { WidthVariants } from "../style/Width.js";
4
4
  /**
5
5
  * Props for `Image` — an `src`, optional `alt` text, plus space and width variants.
6
6
  *
@@ -17,4 +17,4 @@ export interface ImageProps extends SpaceVariants, WidthVariants {
17
17
  * @example <Image src="/logo.png" alt="Logo" width="narrow" />
18
18
  * @see https://shelving.cc/ui/Image
19
19
  */
20
- export declare function Image({ src, alt, ...variants }: ImageProps): ReactElement;
20
+ export declare function Image({ src, alt, ...props }: ImageProps): ReactElement;
package/ui/block/Image.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { getSpaceClass } from "../style/Space.js";
3
- import { getWidthClass } from "../style/Width.js";
2
+ import { getBlockClass } from "../style/Block.js";
4
3
  import { getClass, getModuleClass } from "../util/css.js";
5
4
  import IMAGE_CSS from "./Image.module.css";
6
5
  const IMAGE_CLASS = getModuleClass(IMAGE_CSS, "image");
@@ -11,6 +10,7 @@ const IMAGE_CLASS = getModuleClass(IMAGE_CSS, "image");
11
10
  * @example <Image src="/logo.png" alt="Logo" width="narrow" />
12
11
  * @see https://shelving.cc/ui/Image
13
12
  */
14
- export function Image({ src, alt, ...variants }) {
15
- return _jsx("img", { src: src, alt: alt, className: getClass(IMAGE_CLASS, getSpaceClass(variants), getWidthClass(variants)) });
13
+ export function Image({ src, alt, ...props }) {
14
+ return (_jsx("img", { src: src, alt: alt, className: getClass(IMAGE_CLASS, //
15
+ getBlockClass(props)) }));
16
16
  }
@@ -4,9 +4,12 @@
4
4
  @layer components {
5
5
  .image,
6
6
  .prose img {
7
- inline-size: var(--image-width, 100%);
7
+ /* Box */
8
+ border: var(--image-border, none);
9
+ border-radius: var(--image-radius, var(--radius-normal));
8
10
  margin-block: var(--image-space, var(--space-paragraph));
9
11
 
12
+ /* Contents */
10
13
  object-position: center center;
11
14
  object-fit: cover; /* Don't distort when resized. */
12
15
  }
@@ -1,6 +1,7 @@
1
1
  import type { ReactElement } from "react";
2
- import { getSpaceClass, type SpaceVariants } from "../style/Space.js";
3
- import { getWidthClass, type WidthVariants } from "../style/Width.js";
2
+ import { getBlockClass } from "../style/Block.js";
3
+ import type { SpaceVariants } from "../style/Space.js";
4
+ import type { WidthVariants } from "../style/Width.js";
4
5
  import { getClass, getModuleClass } from "../util/css.js";
5
6
  import IMAGE_CSS from "./Image.module.css";
6
7
 
@@ -23,6 +24,15 @@ export interface ImageProps extends SpaceVariants, WidthVariants {
23
24
  * @example <Image src="/logo.png" alt="Logo" width="narrow" />
24
25
  * @see https://shelving.cc/ui/Image
25
26
  */
26
- export function Image({ src, alt, ...variants }: ImageProps): ReactElement {
27
- return <img src={src} alt={alt} className={getClass(IMAGE_CLASS, getSpaceClass(variants), getWidthClass(variants))} />;
27
+ export function Image({ src, alt, ...props }: ImageProps): ReactElement {
28
+ return (
29
+ <img
30
+ src={src}
31
+ alt={alt}
32
+ className={getClass(
33
+ IMAGE_CLASS, //
34
+ getBlockClass(props),
35
+ )}
36
+ />
37
+ );
28
38
  }
@@ -1,7 +1,7 @@
1
- import { type MouseEvent, type ReactElement } from "react";
1
+ import { type ReactElement } from "react";
2
2
  import type { SpaceVariants } from "../style/Space.js";
3
3
  import type { WidthVariants } from "../style/Width.js";
4
- import type { ChildProps, OptionalChildProps } from "../util/props.js";
4
+ import type { OptionalChildProps } from "../util/props.js";
5
5
  /**
6
6
  * Props for `Video` — space and width variants plus optional `children`.
7
7
  *
@@ -9,68 +9,13 @@ import type { ChildProps, OptionalChildProps } from "../util/props.js";
9
9
  */
10
10
  export interface VideoProps extends SpaceVariants, WidthVariants, OptionalChildProps {
11
11
  }
12
- /**
13
- * Props for `VideoButtons` — `children` plus an optional `left` alignment flag.
14
- *
15
- * @see https://shelving.cc/ui/VideoButtonsProps
16
- */
17
- export interface VideoButtonsProps extends ChildProps {
18
- left?: boolean;
19
- }
20
- /**
21
- * Props for `VideoButton` — `children` plus optional `title`, `onClick`, `danger`, and `disabled`.
22
- *
23
- * @see https://shelving.cc/ui/VideoButtonProps
24
- */
25
- export interface VideoButtonProps extends ChildProps {
26
- title?: string | undefined;
27
- onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
28
- danger?: boolean;
29
- disabled?: boolean;
30
- }
31
12
  /**
32
13
  * Video container element.
33
14
  * - Has a black background and a 16:9 aspect ratio.
34
- * - Shows its contents (i.e. a `<video>` element or a `<TwilioRoom>`.
15
+ * - Shows its contents (i.e. a `<video>` element or a `<TwilioRoom>`).
35
16
  *
36
17
  * @kind component
37
18
  * @example <Video><video src="/clip.mp4" /></Video>
38
19
  * @see https://shelving.cc/ui/Video
39
20
  */
40
21
  export declare function Video({ children, ...props }: VideoProps): ReactElement;
41
- /**
42
- * Set of video buttons floating over a video.
43
- *
44
- * @example <VideoButtons><FullscreenVideoButton /></VideoButtons>
45
- * @see https://shelving.cc/ui/VideoButtons
46
- */
47
- export declare function VideoButtons({ children, ...variants }: VideoButtonsProps): import("react").JSX.Element;
48
- /**
49
- * Individual video button over a video — renders a `<button>`.
50
- *
51
- * @kind component
52
- * @example <VideoButton title="Play" onClick={play}><PlayIcon /></VideoButton>
53
- * @see https://shelving.cc/ui/VideoButton
54
- */
55
- export declare function VideoButton({ children, title, onClick, disabled, ...variants }: VideoButtonProps): ReactElement;
56
- declare const _fullscreenVideoButtonProps: unique symbol;
57
- /**
58
- * Props for `FullscreenVideoButton` — an empty marker interface (the component takes no props).
59
- *
60
- * @see https://shelving.cc/ui/FullscreenVideoButtonProps
61
- */
62
- export interface FullscreenVideoButtonProps {
63
- readonly [_fullscreenVideoButtonProps]?: never;
64
- }
65
- /**
66
- * Button to toggle the surrounding video element in and out of fullscreen.
67
- * - Renders `null` when the browser does not support the Fullscreen API.
68
- * - Tracks fullscreen state so the icon and title flip between enter/exit.
69
- *
70
- * @returns Rendered fullscreen toggle button, or `null` when fullscreen is unavailable.
71
- * @kind component
72
- * @example <Video><video src="/clip.mp4" /><VideoButtons><FullscreenVideoButton /></VideoButtons></Video>
73
- * @see https://shelving.cc/ui/FullscreenVideoButton
74
- */
75
- export declare function FullscreenVideoButton(): ReactElement | null;
76
- export {};
package/ui/block/Video.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/24/solid";
3
- import { useEffect, useRef, useState } from "react";
2
+ import { useRef } from "react";
4
3
  import { getBlockClass } from "../style/Block.js";
5
4
  import { getClass, getModuleClass } from "../util/css.js";
6
5
  import VIDEO_CSS from "./Video.module.css";
@@ -8,7 +7,7 @@ const VIDEO_CLASS = getModuleClass(VIDEO_CSS, "video");
8
7
  /**
9
8
  * Video container element.
10
9
  * - Has a black background and a 16:9 aspect ratio.
11
- * - Shows its contents (i.e. a `<video>` element or a `<TwilioRoom>`.
10
+ * - Shows its contents (i.e. a `<video>` element or a `<TwilioRoom>`).
12
11
  *
13
12
  * @kind component
14
13
  * @example <Video><video src="/clip.mp4" /></Video>
@@ -19,52 +18,3 @@ export function Video({ children, ...props }) {
19
18
  return (_jsx("figure", { ref: ref, className: getClass(VIDEO_CLASS, //
20
19
  getBlockClass(props)), children: children }));
21
20
  }
22
- /**
23
- * Set of video buttons floating over a video.
24
- *
25
- * @example <VideoButtons><FullscreenVideoButton /></VideoButtons>
26
- * @see https://shelving.cc/ui/VideoButtons
27
- */
28
- export function VideoButtons({ children, ...variants }) {
29
- return _jsx("div", { className: getModuleClass(VIDEO_CSS, "buttons", variants), children: children });
30
- }
31
- /**
32
- * Individual video button over a video — renders a `<button>`.
33
- *
34
- * @kind component
35
- * @example <VideoButton title="Play" onClick={play}><PlayIcon /></VideoButton>
36
- * @see https://shelving.cc/ui/VideoButton
37
- */
38
- export function VideoButton({ children, title, onClick, disabled, ...variants }) {
39
- return (_jsx("button", { type: "button", onClick: onClick, className: getModuleClass(VIDEO_CSS, "button", variants), title: title, disabled: disabled, children: children }));
40
- }
41
- /**
42
- * Button to toggle the surrounding video element in and out of fullscreen.
43
- * - Renders `null` when the browser does not support the Fullscreen API.
44
- * - Tracks fullscreen state so the icon and title flip between enter/exit.
45
- *
46
- * @returns Rendered fullscreen toggle button, or `null` when fullscreen is unavailable.
47
- * @kind component
48
- * @example <Video><video src="/clip.mp4" /><VideoButtons><FullscreenVideoButton /></VideoButtons></Video>
49
- * @see https://shelving.cc/ui/FullscreenVideoButton
50
- */
51
- export function FullscreenVideoButton() {
52
- const [isFull, setFull] = useState(() => typeof document !== "undefined" && !!document.fullscreenElement);
53
- useEffect(() => {
54
- const onChange = () => setFull(!!document.fullscreenElement);
55
- document.addEventListener("fullscreenchange", onChange);
56
- return () => document.removeEventListener("fullscreenchange", onChange);
57
- });
58
- if (!document.fullscreenEnabled)
59
- return null;
60
- return (_jsx(VideoButton, { title: isFull ? "Exit full screen mode" : "Enter full screen mode", onClick: ({ currentTarget }) => {
61
- if (document.fullscreenElement) {
62
- document.exitFullscreen();
63
- }
64
- else {
65
- const parent = currentTarget.closest("figure, video");
66
- if (parent)
67
- parent.requestFullscreen();
68
- }
69
- }, children: isFull ? _jsx(ArrowsPointingInIcon, {}) : _jsx(ArrowsPointingOutIcon, {}) }));
70
- }
@@ -12,7 +12,7 @@
12
12
  /* Box */
13
13
  aspect-ratio: 16 / 9;
14
14
  margin-block: var(--video-space, var(--space-paragraph));
15
- border: var(--video-border, var(--stroke-normal) solid black);
15
+ border: var(--video-border, none);
16
16
  border-radius: var(--video-radius, var(--radius-normal));
17
17
  padding: var(--video-padding, var(--space-normal));
18
18
 
@@ -35,54 +35,4 @@
35
35
  border-radius: 0;
36
36
  }
37
37
  }
38
-
39
- .buttons {
40
- position: absolute;
41
- top: var(--video-buttons-offset-y, var(--space-normal));
42
- right: var(--video-buttons-offset-x, var(--space-normal));
43
- display: flex;
44
- gap: var(--video-buttons-gap, var(--space-small));
45
-
46
- &.left {
47
- right: auto;
48
- left: var(--video-buttons-offset-x, var(--space-normal));
49
- }
50
- }
51
-
52
- .button {
53
- /* Box */
54
- display: block;
55
- border: var(--video-button-border, var(--stroke-normal) solid black);
56
- border-radius: var(--video-button-radius, 100rem);
57
- padding-inline: var(--video-button-padding-x, var(--space-xsmall));
58
-
59
- /* Style */
60
- color: var(--video-button-text, white);
61
- background: var(--video-button-bg, black);
62
- transition: var(--video-button-transition, all var(--duration-fast));
63
- outline: var(--video-button-focus-border, var(--stroke-focus) solid var(--color-focus));
64
- outline-offset: calc(0px - var(--stroke-normal));
65
- box-shadow: var(--video-button-shadow, var(--shadow-normal));
66
- cursor: pointer;
67
-
68
- /* Pseudo-classes */
69
- &:disabled,
70
- &:where(a:not(:any-link)) {
71
- opacity: var(--video-button-disabled-opacity, 0.5);
72
- cursor: default;
73
- }
74
- &:enabled:hover,
75
- &:any-link:hover,
76
- &:focus:not(:focus-visible) {
77
- background: color-mix(in oklch, white 85%, transparent);
78
- }
79
- }
80
- }
81
-
82
- @layer overrides {
83
- .button {
84
- &:not(:focus-visible) {
85
- outline-color: transparent;
86
- }
87
- }
88
38
  }
@@ -1,10 +1,9 @@
1
- import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/24/solid";
2
- import { type MouseEvent, type ReactElement, useEffect, useRef, useState } from "react";
1
+ import { type ReactElement, useRef } from "react";
3
2
  import { getBlockClass } from "../style/Block.js";
4
3
  import type { SpaceVariants } from "../style/Space.js";
5
4
  import type { WidthVariants } from "../style/Width.js";
6
5
  import { getClass, getModuleClass } from "../util/css.js";
7
- import type { ChildProps, OptionalChildProps } from "../util/props.js";
6
+ import type { OptionalChildProps } from "../util/props.js";
8
7
  import VIDEO_CSS from "./Video.module.css";
9
8
 
10
9
  const VIDEO_CLASS = getModuleClass(VIDEO_CSS, "video");
@@ -16,31 +15,10 @@ const VIDEO_CLASS = getModuleClass(VIDEO_CSS, "video");
16
15
  */
17
16
  export interface VideoProps extends SpaceVariants, WidthVariants, OptionalChildProps {}
18
17
 
19
- /**
20
- * Props for `VideoButtons` — `children` plus an optional `left` alignment flag.
21
- *
22
- * @see https://shelving.cc/ui/VideoButtonsProps
23
- */
24
- export interface VideoButtonsProps extends ChildProps {
25
- left?: boolean;
26
- }
27
-
28
- /**
29
- * Props for `VideoButton` — `children` plus optional `title`, `onClick`, `danger`, and `disabled`.
30
- *
31
- * @see https://shelving.cc/ui/VideoButtonProps
32
- */
33
- export interface VideoButtonProps extends ChildProps {
34
- title?: string | undefined;
35
- onClick?: (event: MouseEvent<HTMLButtonElement>) => void;
36
- danger?: boolean;
37
- disabled?: boolean;
38
- }
39
-
40
18
  /**
41
19
  * Video container element.
42
20
  * - Has a black background and a 16:9 aspect ratio.
43
- * - Shows its contents (i.e. a `<video>` element or a `<TwilioRoom>`.
21
+ * - Shows its contents (i.e. a `<video>` element or a `<TwilioRoom>`).
44
22
  *
45
23
  * @kind component
46
24
  * @example <Video><video src="/clip.mp4" /></Video>
@@ -61,77 +39,3 @@ export function Video({ children, ...props }: VideoProps): ReactElement {
61
39
  </figure>
62
40
  );
63
41
  }
64
-
65
- /**
66
- * Set of video buttons floating over a video.
67
- *
68
- * @example <VideoButtons><FullscreenVideoButton /></VideoButtons>
69
- * @see https://shelving.cc/ui/VideoButtons
70
- */
71
- export function VideoButtons({ children, ...variants }: VideoButtonsProps) {
72
- return <div className={getModuleClass(VIDEO_CSS, "buttons", variants)}>{children}</div>;
73
- }
74
-
75
- /**
76
- * Individual video button over a video — renders a `<button>`.
77
- *
78
- * @kind component
79
- * @example <VideoButton title="Play" onClick={play}><PlayIcon /></VideoButton>
80
- * @see https://shelving.cc/ui/VideoButton
81
- */
82
- export function VideoButton({ children, title, onClick, disabled, ...variants }: VideoButtonProps): ReactElement {
83
- return (
84
- <button type="button" onClick={onClick} className={getModuleClass(VIDEO_CSS, "button", variants)} title={title} disabled={disabled}>
85
- {children}
86
- </button>
87
- );
88
- }
89
-
90
- declare const _fullscreenVideoButtonProps: unique symbol;
91
-
92
- /**
93
- * Props for `FullscreenVideoButton` — an empty marker interface (the component takes no props).
94
- *
95
- * @see https://shelving.cc/ui/FullscreenVideoButtonProps
96
- */
97
- export interface FullscreenVideoButtonProps {
98
- readonly [_fullscreenVideoButtonProps]?: never;
99
- }
100
-
101
- /**
102
- * Button to toggle the surrounding video element in and out of fullscreen.
103
- * - Renders `null` when the browser does not support the Fullscreen API.
104
- * - Tracks fullscreen state so the icon and title flip between enter/exit.
105
- *
106
- * @returns Rendered fullscreen toggle button, or `null` when fullscreen is unavailable.
107
- * @kind component
108
- * @example <Video><video src="/clip.mp4" /><VideoButtons><FullscreenVideoButton /></VideoButtons></Video>
109
- * @see https://shelving.cc/ui/FullscreenVideoButton
110
- */
111
- export function FullscreenVideoButton(): ReactElement | null {
112
- const [isFull, setFull] = useState(() => typeof document !== "undefined" && !!document.fullscreenElement);
113
-
114
- useEffect(() => {
115
- const onChange = () => setFull(!!document.fullscreenElement);
116
- document.addEventListener("fullscreenchange", onChange);
117
- return () => document.removeEventListener("fullscreenchange", onChange);
118
- });
119
-
120
- if (!document.fullscreenEnabled) return null;
121
-
122
- return (
123
- <VideoButton
124
- title={isFull ? "Exit full screen mode" : "Enter full screen mode"}
125
- onClick={({ currentTarget }) => {
126
- if (document.fullscreenElement) {
127
- document.exitFullscreen();
128
- } else {
129
- const parent = currentTarget.closest("figure, video");
130
- if (parent) parent.requestFullscreen();
131
- }
132
- }}
133
- >
134
- {isFull ? <ArrowsPointingInIcon /> : <ArrowsPointingOutIcon />}
135
- </VideoButton>
136
- );
137
- }
@@ -28,7 +28,12 @@ export interface ButtonVariants extends FlexVariants, StatusVariants, Typography
28
28
  * @see https://shelving.cc/ui/getButtonClass
29
29
  */
30
30
  export declare function getButtonClass(variants: ButtonVariants): string;
31
- interface ButtonProps extends ButtonVariants, ClickableProps {
31
+ /**
32
+ * Component props for a `<Button>` component.
33
+ *
34
+ * @see https://shelving.cc/ui/ButtonProps
35
+ */
36
+ export interface ButtonProps extends ButtonVariants, ClickableProps {
32
37
  }
33
38
  /**
34
39
  * Render either a `<button>` or an `<a href="">` styled as a button, based on whether an `onClick` or `href` prop is provided.
@@ -39,4 +44,3 @@ interface ButtonProps extends ButtonVariants, ClickableProps {
39
44
  * @see https://shelving.cc/ui/Button
40
45
  */
41
46
  export declare function Button(props: ButtonProps): ReactElement;
42
- export {};
@@ -40,7 +40,12 @@ export function getButtonClass(variants: ButtonVariants): string {
40
40
  );
41
41
  }
42
42
 
43
- interface ButtonProps extends ButtonVariants, ClickableProps {}
43
+ /**
44
+ * Component props for a `<Button>` component.
45
+ *
46
+ * @see https://shelving.cc/ui/ButtonProps
47
+ */
48
+ export interface ButtonProps extends ButtonVariants, ClickableProps {}
44
49
 
45
50
  /**
46
51
  * Render either a `<button>` or an `<a href="">` styled as a button, based on whether an `onClick` or `href` prop is provided.
@@ -0,0 +1,31 @@
1
+ import { type ReactElement } from "react";
2
+ import { type ButtonVariants } from "./Button.js";
3
+ /**
4
+ * Component props for a `<FullscreenButton>`
5
+ *
6
+ * @see https://shelving.cc/ui/FullscreenButtonProps
7
+ */
8
+ export interface FullscreenButtonProps extends ButtonVariants {
9
+ /**
10
+ * CSS selector to identify the parent element to toggle fullscreen status on.
11
+ * @default "body, figure"
12
+ */
13
+ target?: string;
14
+ }
15
+ /**
16
+ * Button to toggle the surrounding `<figure>` element or `<body>` element in/out of fullscreen mode.
17
+ * - Renders `null` when the browser does not support the Fullscreen API.
18
+ * - Tracks fullscreen state so the icon and title toggle between enter/exit.
19
+ * - Parent can be identified by `props.target`, but defaults to `figure, body` does not exist, the button will do nothing when clicked.
20
+ * - The `<Figure>` and `<Video>` components are rendered as `<figure>` so this works out the box with both of these.
21
+ * - If not contained in a `<figure>` by default the
22
+ *
23
+ * @returns Rendered fullscreen toggle button, or `null` when fullscreen is unavailable.
24
+ * @kind component
25
+ * @example <Video><video src="/clip.mp4" /><FullscreenButton /></Video>
26
+ * @see https://shelving.cc/ui/FullscreenButton
27
+ */
28
+ export declare function FullscreenButton({ target, ...props }: {
29
+ [x: string]: any;
30
+ target?: string | undefined;
31
+ }): ReactElement | null;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/16/solid";
3
+ import { useEffect, useState } from "react";
4
+ import { Button } from "./Button.js";
5
+ /**
6
+ * Button to toggle the surrounding `<figure>` element or `<body>` element in/out of fullscreen mode.
7
+ * - Renders `null` when the browser does not support the Fullscreen API.
8
+ * - Tracks fullscreen state so the icon and title toggle between enter/exit.
9
+ * - Parent can be identified by `props.target`, but defaults to `figure, body` does not exist, the button will do nothing when clicked.
10
+ * - The `<Figure>` and `<Video>` components are rendered as `<figure>` so this works out the box with both of these.
11
+ * - If not contained in a `<figure>` by default the
12
+ *
13
+ * @returns Rendered fullscreen toggle button, or `null` when fullscreen is unavailable.
14
+ * @kind component
15
+ * @example <Video><video src="/clip.mp4" /><FullscreenButton /></Video>
16
+ * @see https://shelving.cc/ui/FullscreenButton
17
+ */
18
+ export function FullscreenButton({ target = "body, figure", ...props }) {
19
+ const [isFull, setFull] = useState(() => typeof document !== "undefined" && !!document.fullscreenElement);
20
+ useEffect(() => {
21
+ const onChange = () => setFull(!!document.fullscreenElement);
22
+ document.addEventListener("fullscreenchange", onChange);
23
+ return () => document.removeEventListener("fullscreenchange", onChange);
24
+ });
25
+ if (!document.fullscreenEnabled)
26
+ return null;
27
+ return (_jsx(Button, { title: isFull ? "Exit full screen mode" : "Enter full screen mode", onClick: ({ currentTarget }) => {
28
+ if (document.fullscreenElement) {
29
+ document.exitFullscreen();
30
+ }
31
+ else {
32
+ const parent = currentTarget.closest(target);
33
+ if (parent)
34
+ parent.requestFullscreen();
35
+ }
36
+ }, ...props, children: isFull ? _jsx(ArrowsPointingInIcon, {}) : _jsx(ArrowsPointingOutIcon, {}) }));
37
+ }
@@ -0,0 +1,58 @@
1
+ import { ArrowsPointingInIcon, ArrowsPointingOutIcon } from "@heroicons/react/16/solid";
2
+ import { type ReactElement, useEffect, useState } from "react";
3
+ import { Button, type ButtonVariants } from "./Button.js";
4
+
5
+ /**
6
+ * Component props for a `<FullscreenButton>`
7
+ *
8
+ * @see https://shelving.cc/ui/FullscreenButtonProps
9
+ */
10
+ export interface FullscreenButtonProps extends ButtonVariants {
11
+ /**
12
+ * CSS selector to identify the parent element to toggle fullscreen status on.
13
+ * @default "body, figure"
14
+ */
15
+ target?: string;
16
+ }
17
+
18
+ /**
19
+ * Button to toggle the surrounding `<figure>` element or `<body>` element in/out of fullscreen mode.
20
+ * - Renders `null` when the browser does not support the Fullscreen API.
21
+ * - Tracks fullscreen state so the icon and title toggle between enter/exit.
22
+ * - Parent can be identified by `props.target`, but defaults to `figure, body` does not exist, the button will do nothing when clicked.
23
+ * - The `<Figure>` and `<Video>` components are rendered as `<figure>` so this works out the box with both of these.
24
+ * - If not contained in a `<figure>` by default the
25
+ *
26
+ * @returns Rendered fullscreen toggle button, or `null` when fullscreen is unavailable.
27
+ * @kind component
28
+ * @example <Video><video src="/clip.mp4" /><FullscreenButton /></Video>
29
+ * @see https://shelving.cc/ui/FullscreenButton
30
+ */
31
+ export function FullscreenButton({ target = "body, figure", ...props }): ReactElement | null {
32
+ const [isFull, setFull] = useState(() => typeof document !== "undefined" && !!document.fullscreenElement);
33
+
34
+ useEffect(() => {
35
+ const onChange = () => setFull(!!document.fullscreenElement);
36
+ document.addEventListener("fullscreenchange", onChange);
37
+ return () => document.removeEventListener("fullscreenchange", onChange);
38
+ });
39
+
40
+ if (!document.fullscreenEnabled) return null;
41
+
42
+ return (
43
+ <Button
44
+ title={isFull ? "Exit full screen mode" : "Enter full screen mode"}
45
+ onClick={({ currentTarget }) => {
46
+ if (document.fullscreenElement) {
47
+ document.exitFullscreen();
48
+ } else {
49
+ const parent = currentTarget.closest(target);
50
+ if (parent) parent.requestFullscreen();
51
+ }
52
+ }}
53
+ {...props}
54
+ >
55
+ {isFull ? <ArrowsPointingInIcon /> : <ArrowsPointingOutIcon />}
56
+ </Button>
57
+ );
58
+ }
@@ -0,0 +1,29 @@
1
+ import { type ReactElement } from "react";
2
+ import type { Callback } from "../../util/function.js";
3
+ import type { OptionalChildProps } from "../util/index.js";
4
+ import { type ButtonVariants } from "./Button.js";
5
+ /**
6
+ * Context for providing a "retry" callback to descendant `<RetryButton>` elements.
7
+ * - Used by `<Catcher>` to provide a retry callback to its children.
8
+ * - Default `<ErrorNotice>` and `<ErrorPage>` elements include `<RetryButton>` to trigger a retry on their parent `<Catcher>`
9
+ */
10
+ export declare const RetryContext: import("react").Context<Callback | undefined>;
11
+ /**
12
+ * Component props for `<RetryButton>`
13
+ *
14
+ * @property children - The content of the button. Defaults to a refresh icon and `"Retry"`
15
+ *
16
+ * @see https://shelving.cc/ui/RetryButtonProps
17
+ */
18
+ export interface RetryButtonProps extends ButtonVariants, OptionalChildProps {
19
+ }
20
+ /**
21
+ * Button that retries the nearest `<Catcher>` error boundary when clicked.
22
+ *
23
+ * - Reads the retry callback from `<Catcher>`'s private context, so it renders `null` when there is no boundary above it to retry.
24
+ * - Defaults to an "Retry" label with a refresh icon; pass `children` to override.
25
+ *
26
+ * @kind component
27
+ * @see https://shelving.cc/ui/RetryButton
28
+ */
29
+ export declare function RetryButton({ children, ...props }: RetryButtonProps): ReactElement | null;