shelving 1.253.6 → 1.254.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shelving",
3
- "version": "1.253.6",
3
+ "version": "1.254.0",
4
4
  "author": "Dave Houlbrooke <dave@shax.com>",
5
5
  "repository": {
6
6
  "type": "git",
@@ -9,7 +9,7 @@ import { CenteredLayout } from "../layout/CenteredLayout.js";
9
9
  import { Notice } from "../notice/Notice.js";
10
10
  import { Page } from "../page/Page.js";
11
11
  import { Row } from "../style/Flex.js";
12
- import { StatusIcon } from "./StatusIcon.js";
12
+ import { Icon } from "./Icon.js";
13
13
  const RetryContext = createContext(undefined);
14
14
  RetryContext.displayName = "RetryContext";
15
15
  const RETRY_CHILDREN = (_jsxs(_Fragment, { children: [_jsx(ArrowPathIcon, {}), "Retry"] }));
@@ -103,5 +103,5 @@ export function ErrorNotice({ reason }) {
103
103
  */
104
104
  export function ErrorPage({ reason }) {
105
105
  const message = getMessage(reason) ?? "Unknown error";
106
- return (_jsx(Page, { title: "Error", children: _jsx(CenteredLayout, { children: _jsxs(Card, { status: "error", children: [_jsx(Subheading, { children: _jsxs(Row, { left: true, children: [_jsx(StatusIcon, { status: "error", size: "xlarge" }), " ", message] }) }), _jsx(RetryButton, {})] }) }) }));
106
+ return (_jsx(Page, { title: "Error", children: _jsx(CenteredLayout, { children: _jsxs(Card, { status: "error", children: [_jsx(Subheading, { children: _jsxs(Row, { left: true, children: [_jsx(Icon, { status: "error" }), " ", message] }) }), _jsx(RetryButton, {})] }) }) }));
107
107
  }
@@ -10,7 +10,7 @@ import { Notice } from "../notice/Notice.js";
10
10
  import { Page } from "../page/Page.js";
11
11
  import { Row } from "../style/Flex.js";
12
12
  import type { ChildProps, OptionalChildProps } from "../util/props.js";
13
- import { StatusIcon } from "./StatusIcon.js";
13
+ import { Icon } from "./Icon.js";
14
14
 
15
15
  const RetryContext = createContext<Callback | undefined>(undefined);
16
16
  RetryContext.displayName = "RetryContext";
@@ -185,7 +185,7 @@ export function ErrorPage({ reason }: ErrorPageProps): ReactElement {
185
185
  <Card status="error">
186
186
  <Subheading>
187
187
  <Row left>
188
- <StatusIcon status="error" size="xlarge" /> {message}
188
+ <Icon status="error" /> {message}
189
189
  </Row>
190
190
  </Subheading>
191
191
  <RetryButton />
@@ -0,0 +1,32 @@
1
+ import type { ComponentType, ReactElement } from "react";
2
+ import { type ColorVariants } from "../style/Color.js";
3
+ import { type StatusVariants } from "../style/Status.js";
4
+ import { type SizeVariant } from "../style/Typography.js";
5
+ /**
6
+ * Props for `<StatusIcon>` — the `status` to represent and optional icon `size`.
7
+ *
8
+ * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIconProps
9
+ */
10
+ export interface IconProps extends ColorVariants, StatusVariants {
11
+ /**
12
+ * Set the icon to use. Defaults to appropriate icon matching for `status`
13
+ */
14
+ icon?: ComponentType<{
15
+ className?: string | undefined;
16
+ }>;
17
+ /**
18
+ * Size of the icon.
19
+ * @default 1lh
20
+ */
21
+ size?: SizeVariant;
22
+ }
23
+ /**
24
+ * Render the icon for a given status, coloured to match.
25
+ *
26
+ * - Picks a heroicon per status (`success`, `error`, `warning`, etc.), falling back to an info icon, and uses the animated `<Loading>` spinner for `"loading"`.
27
+ *
28
+ * @kind component
29
+ * @example <StatusIcon status="error" size="large" />
30
+ * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIcon
31
+ */
32
+ export declare function Icon(props: IconProps): ReactElement;
@@ -1,9 +1,11 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { CheckCircleIcon, ExclamationTriangleIcon, InformationCircleIcon, XCircleIcon } from "@heroicons/react/24/solid";
3
- import statusStyles from "../style/Status.module.css";
4
- import { getModuleClass } from "../util/css.js";
3
+ import { getColorClass } from "../style/Color.js";
4
+ import { getStatusClass } from "../style/Status.js";
5
+ import { getTypographyClass } from "../style/Typography.js";
6
+ import { getClass, getModuleClass } from "../util/css.js";
7
+ import ICON_CSS from "./Icon.module.css";
5
8
  import { Loading } from "./Loading.js";
6
- import styles from "./StatusIcon.module.css";
7
9
  const STATUS_ICONS = {
8
10
  loading: Loading,
9
11
  success: CheckCircleIcon,
@@ -16,14 +18,12 @@ const STATUS_ICONS = {
16
18
  *
17
19
  * - Picks a heroicon per status (`success`, `error`, `warning`, etc.), falling back to an info icon, and uses the animated `<Loading>` spinner for `"loading"`.
18
20
  *
19
- * @param status The status to represent (defaults to `"info"`).
20
- * @param size Optional icon size (defaults to the current line height).
21
- * @returns The status icon element.
22
21
  * @kind component
23
22
  * @example <StatusIcon status="error" size="large" />
24
23
  * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIcon
25
24
  */
26
- export function StatusIcon({ status = "info", size }) {
27
- const Icon = STATUS_ICONS[status] ?? InformationCircleIcon;
28
- return _jsx(Icon, { className: `${getModuleClass(styles, "icon", size)} ${getModuleClass(statusStyles, status)}` });
25
+ export function Icon(props) {
26
+ const { status = "info", icon: Element = STATUS_ICONS[status] ?? InformationCircleIcon } = props;
27
+ return (_jsx(Element, { className: getClass(getModuleClass(ICON_CSS, "icon"), //
28
+ getColorClass(props), getStatusClass(props), getTypographyClass(props)) }));
29
29
  }
@@ -0,0 +1,28 @@
1
+ # Icon
2
+
3
+ Renders an icon for a given status, coloured to match. Picks a heroicon per status (`success`, `error`, `warning`, etc.) and uses the animated `<Loading>` spinner for `"loading"`.
4
+
5
+ **Things to know:**
6
+
7
+ - `status` defaults to `"info"` (an info icon) when unset.
8
+ - Size it via the `size` prop (`"small"`, `"normal"`, `"large"`, `"xlarge"`, or `"xxlarge"`); defaults to the current line height.
9
+ - Paints from its status tint by default, so the icon colour matches the `status` — override `--icon-color` to force a specific colour.
10
+
11
+ ## Usage
12
+
13
+ ```tsx
14
+ import { Icon } from "shelving/ui";
15
+
16
+ <Icon status="success" size="large" />
17
+ <Icon status="error" />
18
+ <Icon status="loading" size="small" />
19
+ ```
20
+
21
+ ## Styling
22
+
23
+ | Variable | Styles | Default |
24
+ |---|---|---|
25
+ | `--icon-color` | Icon colour | `var(--tint-50)` (the status tint, e.g. `--color-failure` for `status="error"`) |
26
+ | `--icon-size` | Icon width / height | `1lh` (current line height) |
27
+
28
+ **Global tokens it reads** — the status tint anchor `--tint-50`, plus the size tokens `--size-small` / `--size-normal` / `--size-large` / `--size-xlarge` / `--size-xxlarge` used by the `size` prop.
@@ -0,0 +1,18 @@
1
+ @import "../style/layers.css";
2
+ @import "../style/Typography.module.css";
3
+ @import "../style/Color.module.css";
4
+ @import "../style/Status.module.css";
5
+
6
+ @layer defaults {
7
+ .icon {
8
+ width: var(--icon-size, 1lh);
9
+ height: var(--icon-size, 1lh);
10
+ color: var(--icon-color, var(--tint-50));
11
+ }
12
+ }
13
+
14
+ @layer overrides {
15
+ .icon {
16
+ flex: none;
17
+ }
18
+ }
@@ -0,0 +1,58 @@
1
+ import { CheckCircleIcon, ExclamationTriangleIcon, InformationCircleIcon, XCircleIcon } from "@heroicons/react/24/solid";
2
+ import type { ComponentType, ReactElement } from "react";
3
+ import { type ColorVariants, getColorClass } from "../style/Color.js";
4
+ import { getStatusClass, type Status, type StatusVariants } from "../style/Status.js";
5
+ import { getTypographyClass, type SizeVariant } from "../style/Typography.js";
6
+ import { getClass, getModuleClass } from "../util/css.js";
7
+ import ICON_CSS from "./Icon.module.css";
8
+ import { Loading } from "./Loading.js";
9
+
10
+ const STATUS_ICONS: {
11
+ [K in Status]?: ComponentType;
12
+ } = {
13
+ loading: Loading,
14
+ success: CheckCircleIcon,
15
+ error: XCircleIcon,
16
+ warning: ExclamationTriangleIcon,
17
+ danger: ExclamationTriangleIcon,
18
+ };
19
+
20
+ /**
21
+ * Props for `<StatusIcon>` — the `status` to represent and optional icon `size`.
22
+ *
23
+ * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIconProps
24
+ */
25
+ export interface IconProps extends ColorVariants, StatusVariants {
26
+ /**
27
+ * Set the icon to use. Defaults to appropriate icon matching for `status`
28
+ */
29
+ icon?: ComponentType<{ className?: string | undefined }>;
30
+ /**
31
+ * Size of the icon.
32
+ * @default 1lh
33
+ */
34
+ size?: SizeVariant;
35
+ }
36
+
37
+ /**
38
+ * Render the icon for a given status, coloured to match.
39
+ *
40
+ * - Picks a heroicon per status (`success`, `error`, `warning`, etc.), falling back to an info icon, and uses the animated `<Loading>` spinner for `"loading"`.
41
+ *
42
+ * @kind component
43
+ * @example <StatusIcon status="error" size="large" />
44
+ * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIcon
45
+ */
46
+ export function Icon(props: IconProps): ReactElement {
47
+ const { status = "info", icon: Element = STATUS_ICONS[status] ?? InformationCircleIcon } = props;
48
+ return (
49
+ <Element
50
+ className={getClass(
51
+ getModuleClass(ICON_CSS, "icon"), //
52
+ getColorClass(props),
53
+ getStatusClass(props),
54
+ getTypographyClass(props),
55
+ )}
56
+ />
57
+ );
58
+ }
@@ -1,7 +1,7 @@
1
1
  export * from "./Catcher.js";
2
+ export * from "./Icon.js";
2
3
  export * from "./Loading.js";
3
4
  export * from "./Mapper.js";
4
5
  export * from "./Markup.js";
5
6
  export * from "./MetaContext.js";
6
- export * from "./StatusIcon.js";
7
7
  export * from "./Tag.js";
package/ui/misc/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./Catcher.js";
2
+ export * from "./Icon.js";
2
3
  export * from "./Loading.js";
3
4
  export * from "./Mapper.js";
4
5
  export * from "./Markup.js";
5
6
  export * from "./MetaContext.js";
6
- export * from "./StatusIcon.js";
7
7
  export * from "./Tag.js";
package/ui/misc/index.tsx CHANGED
@@ -1,7 +1,7 @@
1
1
  export * from "./Catcher.js";
2
+ export * from "./Icon.js";
2
3
  export * from "./Loading.js";
3
4
  export * from "./Mapper.js";
4
5
  export * from "./Markup.js";
5
6
  export * from "./MetaContext.js";
6
- export * from "./StatusIcon.js";
7
7
  export * from "./Tag.js";
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { getBlockClass } from "../block/Block.js";
3
- import { StatusIcon } from "../misc/StatusIcon.js";
3
+ import { Icon } from "../misc/Icon.js";
4
4
  import { getFlexClass } from "../style/Flex.js";
5
5
  import { getStatusClass } from "../style/Status.js";
6
6
  import { getClass, getModuleClass } from "../util/css.js";
@@ -21,7 +21,7 @@ import NOTICE_CSS from "./Notice.module.css";
21
21
  export function Notice({ children, //
22
22
  icon, ...props }) {
23
23
  const { status } = props;
24
- return (_jsxs("aside", { role: status === "danger" || status === "error" ? "alert" : "status", className: getClass(getBlockClass(props), getModuleClass(NOTICE_CSS, "notice", props), getFlexClass(props), getStatusClass(props)), children: [icon !== undefined ? icon : status && _jsx(StatusIcon, { status: status }), children] }));
24
+ return (_jsxs("aside", { role: status === "danger" || status === "error" ? "alert" : "status", className: getClass(getBlockClass(props), getModuleClass(NOTICE_CSS, "notice", props), getFlexClass(props), getStatusClass(props)), children: [icon !== undefined ? icon : status && _jsx(Icon, { status: status }), children] }));
25
25
  }
26
26
  /**
27
27
  * Shared loading `<Notice>` element showing the loading spinner.
@@ -1,6 +1,6 @@
1
1
  import type { ReactElement } from "react";
2
2
  import { getBlockClass } from "../block/Block.js";
3
- import { StatusIcon } from "../misc/StatusIcon.js";
3
+ import { Icon } from "../misc/Icon.js";
4
4
  import type { ColorVariants } from "../style/Color.js";
5
5
  import { type FlexVariants, getFlexClass } from "../style/Flex.js";
6
6
  import { getStatusClass, type StatusVariants } from "../style/Status.js";
@@ -42,7 +42,7 @@ export function Notice({
42
42
  role={status === "danger" || status === "error" ? "alert" : "status"}
43
43
  className={getClass(getBlockClass(props), getModuleClass(NOTICE_CSS, "notice", props), getFlexClass(props), getStatusClass(props))}
44
44
  >
45
- {icon !== undefined ? icon : status && <StatusIcon status={status} />}
45
+ {icon !== undefined ? icon : status && <Icon status={status} />}
46
46
  {children}
47
47
  </aside>
48
48
  );
@@ -1,25 +0,0 @@
1
- import type { ReactElement } from "react";
2
- import type { Status } from "../style/Status.js";
3
- /**
4
- * Props for `<StatusIcon>` — the `status` to represent and optional icon `size`.
5
- *
6
- * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIconProps
7
- */
8
- export interface StatusIconProps {
9
- status?: Status;
10
- /** Size of the icon (defaults to the current line height). */
11
- size?: "small" | "normal" | "large" | "xlarge" | "xxlarge" | undefined;
12
- }
13
- /**
14
- * Render the icon for a given status, coloured to match.
15
- *
16
- * - Picks a heroicon per status (`success`, `error`, `warning`, etc.), falling back to an info icon, and uses the animated `<Loading>` spinner for `"loading"`.
17
- *
18
- * @param status The status to represent (defaults to `"info"`).
19
- * @param size Optional icon size (defaults to the current line height).
20
- * @returns The status icon element.
21
- * @kind component
22
- * @example <StatusIcon status="error" size="large" />
23
- * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIcon
24
- */
25
- export declare function StatusIcon({ status, size }: StatusIconProps): ReactElement;
@@ -1,28 +0,0 @@
1
- # StatusIcon
2
-
3
- Renders the icon for a given status, coloured to match. Picks a heroicon per status (`success`, `error`, `warning`, etc.) and uses the animated `<Loading>` spinner for `"loading"`.
4
-
5
- **Things to know:**
6
-
7
- - `status` defaults to `"info"` (an info icon) when unset.
8
- - Size it via the `size` prop (`"small"`, `"normal"`, `"large"`, `"xlarge"`, or `"xxlarge"`); defaults to the current line height.
9
- - Paints from its status tint by default, so the icon colour matches the `status` — override `--status-icon-color` to force a specific colour.
10
-
11
- ## Usage
12
-
13
- ```tsx
14
- import { StatusIcon } from "shelving/ui";
15
-
16
- <StatusIcon status="success" size="large" />
17
- <StatusIcon status="error" />
18
- <StatusIcon status="loading" size="small" />
19
- ```
20
-
21
- ## Styling
22
-
23
- | Variable | Styles | Default |
24
- |---|---|---|
25
- | `--status-icon-color` | Icon colour | `var(--tint-50)` (the status tint, e.g. `--color-failure` for `status="error"`) |
26
- | `--status-icon-size` | Icon width / height | `1lh` (current line height) |
27
-
28
- **Global tokens it reads** — the status tint anchor `--tint-50`, plus the size tokens `--size-small` / `--size-normal` / `--size-large` / `--size-xlarge` / `--size-xxlarge` used by the `size` prop.
@@ -1,37 +0,0 @@
1
- @import "../style/layers.css";
2
- @import "../style/Typography.module.css";
3
- @import "../style/Tint.module.css";
4
-
5
- @layer components {
6
- .icon {
7
- flex: none;
8
- border-radius: 999px;
9
- width: var(--status-icon-size, 1lh);
10
- height: var(--status-icon-size, 1lh);
11
-
12
- /* Paint from the status tint anchor so e.g. `status="error"` renders red, `success` green, etc. */
13
- color: var(--status-icon-color, var(--tint-50));
14
-
15
- /* Variants */
16
- &.small {
17
- width: var(--status-icon-small-size, var(--size-small));
18
- height: var(--status-icon-small-size, var(--size-small));
19
- }
20
- &.normal {
21
- width: var(--status-icon-normal-size, var(--size-normal));
22
- height: var(--status-icon-normal-size, var(--size-normal));
23
- }
24
- &.large {
25
- width: var(--status-icon-large-size, var(--size-large));
26
- height: var(--status-icon-large-size, var(--size-large));
27
- }
28
- &.xlarge {
29
- width: var(--status-icon-xlarge-size, var(--size-xlarge));
30
- height: var(--status-icon-xlarge-size, var(--size-xlarge));
31
- }
32
- &.xxlarge {
33
- width: var(--status-icon-xxlarge-size, var(--size-xxlarge));
34
- height: var(--status-icon-xxlarge-size, var(--size-xxlarge));
35
- }
36
- }
37
- }
@@ -1,45 +0,0 @@
1
- import { CheckCircleIcon, ExclamationTriangleIcon, InformationCircleIcon, XCircleIcon } from "@heroicons/react/24/solid";
2
- import type { ComponentType, ReactElement } from "react";
3
- import type { Status } from "../style/Status.js";
4
- import statusStyles from "../style/Status.module.css";
5
- import { getModuleClass } from "../util/css.js";
6
- import { Loading } from "./Loading.js";
7
- import styles from "./StatusIcon.module.css";
8
-
9
- const STATUS_ICONS: {
10
- [K in Status]?: ComponentType<Record<string, unknown>>;
11
- } = {
12
- loading: Loading,
13
- success: CheckCircleIcon,
14
- error: XCircleIcon,
15
- warning: ExclamationTriangleIcon,
16
- danger: ExclamationTriangleIcon,
17
- };
18
-
19
- /**
20
- * Props for `<StatusIcon>` — the `status` to represent and optional icon `size`.
21
- *
22
- * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIconProps
23
- */
24
- export interface StatusIconProps {
25
- status?: Status;
26
- /** Size of the icon (defaults to the current line height). */
27
- size?: "small" | "normal" | "large" | "xlarge" | "xxlarge" | undefined;
28
- }
29
-
30
- /**
31
- * Render the icon for a given status, coloured to match.
32
- *
33
- * - Picks a heroicon per status (`success`, `error`, `warning`, etc.), falling back to an info icon, and uses the animated `<Loading>` spinner for `"loading"`.
34
- *
35
- * @param status The status to represent (defaults to `"info"`).
36
- * @param size Optional icon size (defaults to the current line height).
37
- * @returns The status icon element.
38
- * @kind component
39
- * @example <StatusIcon status="error" size="large" />
40
- * @see https://dhoulb.github.io/shelving/ui/misc/StatusIcon/StatusIcon
41
- */
42
- export function StatusIcon({ status = "info", size }: StatusIconProps): ReactElement {
43
- const Icon = STATUS_ICONS[status] ?? InformationCircleIcon;
44
- return <Icon className={`${getModuleClass(styles, "icon", size)} ${getModuleClass(statusStyles, status)}`} />;
45
- }