@rackbops/ui-react 0.1.0 → 0.1.2

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/dist/Button.d.ts CHANGED
@@ -1,6 +1,13 @@
1
- import type { ButtonHTMLAttributes } from "react";
2
- export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
1
+ import { type ButtonHTMLAttributes, type RefAttributes } from "react";
2
+ export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement>, RefAttributes<HTMLButtonElement> {
3
3
  /** Visual emphasis. Maps to .rb-btn--{variant}. */
4
4
  variant?: "default" | "primary" | "accent" | "danger" | "ghost";
5
+ /** Size. "sm" maps to .rb-btn--sm for inline/table-row actions; "md" is the default. */
6
+ size?: "sm" | "md";
7
+ /**
8
+ * Icon-only mode: square hit target, no text gap. Maps to .rb-icon-btn.
9
+ * There's no visible label, so pass an accessible name via `aria-label`.
10
+ */
11
+ iconOnly?: boolean;
5
12
  }
6
- export declare function Button({ variant, type, className, ...rest }: ButtonProps): import("react").JSX.Element;
13
+ export declare const Button: import("react").ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & RefAttributes<HTMLButtonElement>>;
package/dist/Button.js CHANGED
@@ -1,7 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
2
3
  import { cx } from "./cx.js";
3
- export function Button({ variant = "default", type = "button", className, ...rest }) {
4
+ export const Button = forwardRef(function Button({ variant = "default", size = "md", iconOnly = false, type = "button", className, ...rest }, ref) {
4
5
  // Default type="button" so a Button inside a <form> doesn't submit it on
5
6
  // click; pass type="submit" explicitly when that's what you want.
6
- return (_jsx("button", { type: type, className: cx("rb-btn", variant !== "default" && `rb-btn--${variant}`, className), ...rest }));
7
- }
7
+ return (_jsx("button", { ref: ref, type: type, className: cx("rb-btn", variant !== "default" && `rb-btn--${variant}`, size === "sm" && "rb-btn--sm", iconOnly && "rb-icon-btn", className), ...rest }));
8
+ });
9
+ Button.displayName = "Button";
package/dist/Card.d.ts CHANGED
@@ -1,6 +1,12 @@
1
- import type { HTMLAttributes } from "react";
2
- export interface CardProps extends HTMLAttributes<HTMLDivElement> {
3
- /** Raised elevation (.rb-card--raised); themes that don't define it fall back. */
1
+ import { type HTMLAttributes, type RefAttributes } from "react";
2
+ export interface CardProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<HTMLDivElement> {
3
+ /**
4
+ * Raised elevation (.rb-card--raised). Falls back to the base card in the
5
+ * three nazuraki ports: luminous-precision and neon-butterfly have no
6
+ * second elevation tier upstream at all; summer-cloud's upstream second
7
+ * tier is `--floating`, already carried over, so it doesn't also add a
8
+ * near-duplicate `--raised`.
9
+ */
4
10
  raised?: boolean;
5
11
  }
6
- export declare function Card({ raised, className, ...rest }: CardProps): import("react").JSX.Element;
12
+ export declare const Card: import("react").ForwardRefExoticComponent<Omit<CardProps, "ref"> & RefAttributes<HTMLDivElement>>;
package/dist/Card.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
2
3
  import { cx } from "./cx.js";
3
- export function Card({ raised, className, ...rest }) {
4
- return _jsx("div", { className: cx("rb-card", raised && "rb-card--raised", className), ...rest });
5
- }
4
+ export const Card = forwardRef(function Card({ raised, className, ...rest }, ref) {
5
+ return (_jsx("div", { ref: ref, className: cx("rb-card", raised && "rb-card--raised", className), ...rest }));
6
+ });
7
+ Card.displayName = "Card";
package/dist/Dialog.d.ts CHANGED
@@ -1,11 +1,9 @@
1
- import { type ReactNode } from "react";
2
- export interface DialogProps {
1
+ import { type DialogHTMLAttributes, type ReactNode, type RefAttributes } from "react";
2
+ export interface DialogProps extends Omit<DialogHTMLAttributes<HTMLDialogElement>, "open" | "title" | "onClose">, RefAttributes<HTMLDialogElement> {
3
3
  open: boolean;
4
4
  onClose?: () => void;
5
5
  title?: ReactNode;
6
6
  actions?: ReactNode;
7
- children?: ReactNode;
8
- className?: string;
9
7
  }
10
8
  /** A native <dialog> driven by the `open` prop (showModal/close). */
11
- export declare function Dialog({ open, onClose, title, actions, children, className }: DialogProps): import("react").JSX.Element;
9
+ export declare const Dialog: import("react").ForwardRefExoticComponent<Omit<DialogProps, "ref"> & RefAttributes<HTMLDialogElement>>;
package/dist/Dialog.js CHANGED
@@ -1,18 +1,35 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect, useId, useRef } from "react";
2
+ import { forwardRef, useEffect, useId, useRef, } from "react";
3
3
  import { cx } from "./cx.js";
4
+ /** Combines an internal ref this component needs with a consumer-supplied one,
5
+ * so both end up pointing at the same DOM node. */
6
+ function mergeRefs(...refs) {
7
+ return (node) => {
8
+ for (const ref of refs) {
9
+ if (typeof ref === "function")
10
+ ref(node);
11
+ else if (ref)
12
+ ref.current = node;
13
+ }
14
+ };
15
+ }
4
16
  /** A native <dialog> driven by the `open` prop (showModal/close). */
5
- export function Dialog({ open, onClose, title, actions, children, className }) {
6
- const ref = useRef(null);
17
+ export const Dialog = forwardRef(function Dialog({ open, onClose, title, actions, children, className, ...rest }, forwardedRef) {
18
+ const internalRef = useRef(null);
7
19
  const titleId = useId();
20
+ // No dependency array: a native close (Escape, or a method="dialog" form)
21
+ // flips el.open out from under the `open` prop with nothing to reconcile
22
+ // them, so a stranded open=true re-render must re-sync too, not just a
23
+ // render where `open` itself changed (issue #31).
8
24
  useEffect(() => {
9
- const el = ref.current;
25
+ const el = internalRef.current;
10
26
  if (!el)
11
27
  return;
12
28
  if (open && !el.open)
13
29
  el.showModal();
14
30
  else if (!open && el.open)
15
31
  el.close();
16
- }, [open]);
17
- return (_jsxs("dialog", { ref: ref, className: cx("rb-dialog", className), onClose: onClose, "aria-labelledby": title !== undefined ? titleId : undefined, children: [_jsxs("div", { className: "rb-dialog__body", children: [title !== undefined && (_jsx("h2", { id: titleId, className: "rb-dialog__title", children: title })), children] }), actions !== undefined && _jsx("div", { className: "rb-dialog__actions", children: actions })] }));
18
- }
32
+ });
33
+ return (_jsxs("dialog", { ref: mergeRefs(internalRef, forwardedRef), className: cx("rb-dialog", className), onClose: onClose, "aria-labelledby": title !== undefined ? titleId : undefined, ...rest, children: [_jsxs("div", { className: "rb-dialog__body", children: [title !== undefined && (_jsx("h2", { id: titleId, className: "rb-dialog__title", children: title })), children] }), actions !== undefined && _jsx("div", { className: "rb-dialog__actions", children: actions })] }));
34
+ });
35
+ Dialog.displayName = "Dialog";
@@ -1,4 +1,4 @@
1
- import type { HTMLAttributes } from "react";
1
+ import { type HTMLAttributes, type RefAttributes } from "react";
2
2
  export interface LinkUrl {
3
3
  label: string;
4
4
  url: string;
@@ -17,7 +17,7 @@ export interface LinkItem {
17
17
  host?: string;
18
18
  monitored?: boolean;
19
19
  }
20
- export interface LinksIndexProps extends HTMLAttributes<HTMLDivElement> {
20
+ export interface LinksIndexProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<HTMLDivElement> {
21
21
  categories: LinkCategory[];
22
22
  links: LinkItem[];
23
23
  }
@@ -26,4 +26,4 @@ export interface LinksIndexProps extends HTMLAttributes<HTMLDivElement> {
26
26
  * of `rb-card`s; links whose `category` is not listed collect into a trailing "Other" group. No
27
27
  * router assumed -- external URLs open in a new tab. Themed by the consumer's `data-rb-style`.
28
28
  */
29
- export declare function LinksIndex({ categories, links, className, ...rest }: LinksIndexProps): import("react").JSX.Element;
29
+ export declare const LinksIndex: import("react").ForwardRefExoticComponent<Omit<LinksIndexProps, "ref"> & RefAttributes<HTMLDivElement>>;
@@ -1,4 +1,5 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
2
3
  import { Card } from "./Card.js";
3
4
  import { Badge } from "./feedback.js";
4
5
  // Structural inline layout only -- the card/badge surfaces + colour come from @rackbops/styles
@@ -9,8 +10,9 @@ const gridStyle = {
9
10
  gridTemplateColumns: "repeat(auto-fill, minmax(16rem, 1fr))",
10
11
  gap: "var(--rb-space-4)",
11
12
  };
12
- // Reset the url list structurally (no bullets/indent) so it renders the same under every theme --
13
- // the themes don't all reset a bare `ul`.
13
+ // Reset the url list structurally (no bullets/indent) -- this is a link-nav list, not prose, so it
14
+ // deliberately opts out of the themes' bare `ul` treatment (disc markers + indent) rather than
15
+ // working around an inconsistency between them.
14
16
  const listStyle = { listStyle: "none", margin: 0, padding: 0 };
15
17
  // External = an http(s) or protocol-relative (`//host`) url -> opens in a new tab; anything else
16
18
  // (relative, mailto:, tel:, ...) stays a plain in-page link.
@@ -26,11 +28,12 @@ function Group({ label, items }) {
26
28
  * of `rb-card`s; links whose `category` is not listed collect into a trailing "Other" group. No
27
29
  * router assumed -- external URLs open in a new tab. Themed by the consumer's `data-rb-style`.
28
30
  */
29
- export function LinksIndex({ categories, links, className, ...rest }) {
31
+ export const LinksIndex = forwardRef(function LinksIndex({ categories, links, className, ...rest }, ref) {
30
32
  const known = new Set(categories.map((c) => c.id));
31
33
  const other = links.filter((l) => !known.has(l.category));
32
- return (_jsxs("div", { className: className, ...rest, children: [categories.map((cat) => {
34
+ return (_jsxs("div", { ref: ref, className: className, ...rest, children: [categories.map((cat) => {
33
35
  const items = links.filter((l) => l.category === cat.id);
34
36
  return items.length > 0 ? _jsx(Group, { label: cat.label, items: items }, cat.id) : null;
35
37
  }), other.length > 0 ? _jsx(Group, { label: "Other", items: other }) : null] }));
36
- }
38
+ });
39
+ LinksIndex.displayName = "LinksIndex";
package/dist/NavLink.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { AnchorHTMLAttributes } from "react";
2
- export interface NavLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
1
+ import { type AnchorHTMLAttributes, type RefAttributes } from "react";
2
+ export interface NavLinkProps extends AnchorHTMLAttributes<HTMLAnchorElement>, RefAttributes<HTMLAnchorElement> {
3
3
  /** Marks the active route (.rb-link--active). */
4
4
  active?: boolean;
5
5
  }
6
- export declare function NavLink({ active, className, ...rest }: NavLinkProps): import("react").JSX.Element;
6
+ export declare const NavLink: import("react").ForwardRefExoticComponent<Omit<NavLinkProps, "ref"> & RefAttributes<HTMLAnchorElement>>;
package/dist/NavLink.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
2
3
  import { cx } from "./cx.js";
3
- export function NavLink({ active, className, ...rest }) {
4
- return (_jsx("a", { "aria-current": active ? "page" : undefined, className: cx("rb-link", active && "rb-link--active", className), ...rest }));
5
- }
4
+ export const NavLink = forwardRef(function NavLink({ active, className, ...rest }, ref) {
5
+ return (_jsx("a", { ref: ref, "aria-current": active ? "page" : undefined, className: cx("rb-link", active && "rb-link--active", className), ...rest }));
6
+ });
7
+ NavLink.displayName = "NavLink";
@@ -0,0 +1,19 @@
1
+ import { type HTMLAttributes, type ReactNode, type RefAttributes } from "react";
2
+ export interface NavRailItem {
3
+ /** Matched against `activeId`; also used as the React list key. */
4
+ id: string;
5
+ label: ReactNode;
6
+ href?: string;
7
+ }
8
+ export interface NavRailProps extends HTMLAttributes<HTMLElement>, RefAttributes<HTMLElement> {
9
+ items: NavRailItem[];
10
+ /** Id of the currently active item (mirrors NavLink's own `active` contract --
11
+ * no second active-state convention). No item is marked active if it matches none. */
12
+ activeId?: string;
13
+ }
14
+ /**
15
+ * A vertical nav container (.rb-nav-rail) rendering one NavLink per item.
16
+ * Controlled by the caller via `activeId`, same as NavLink's own `active` prop --
17
+ * this component owns no state of its own.
18
+ */
19
+ export declare const NavRail: import("react").ForwardRefExoticComponent<Omit<NavRailProps, "ref"> & RefAttributes<HTMLElement>>;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { cx } from "./cx.js";
4
+ import { NavLink } from "./NavLink.js";
5
+ /**
6
+ * A vertical nav container (.rb-nav-rail) rendering one NavLink per item.
7
+ * Controlled by the caller via `activeId`, same as NavLink's own `active` prop --
8
+ * this component owns no state of its own.
9
+ */
10
+ export const NavRail = forwardRef(function NavRail({ items, activeId, className, ...rest }, ref) {
11
+ return (_jsx("nav", { ref: ref, className: cx("rb-nav-rail", className), ...rest, children: items.map((item) => (_jsx(NavLink, { href: item.href, active: item.id === activeId, children: item.label }, item.id))) }));
12
+ });
13
+ NavRail.displayName = "NavRail";
@@ -0,0 +1,26 @@
1
+ import { type OlHTMLAttributes, type ReactNode, type RefAttributes } from "react";
2
+ export interface StepperStep {
3
+ /** Also used as the React list key. */
4
+ id: string;
5
+ label: ReactNode;
6
+ /** Shown for the current/upcoming states; a complete step always shows the
7
+ * built-in checkmark instead, regardless of this. */
8
+ icon?: ReactNode;
9
+ }
10
+ export interface StepperProps extends OlHTMLAttributes<HTMLOListElement>, RefAttributes<HTMLOListElement> {
11
+ steps: StepperStep[];
12
+ /** 0-based index of the current step; steps before it read complete, after
13
+ * it read upcoming. Drives each step's state -- and, through it, the
14
+ * connector segment leading into that step -- there is no separate
15
+ * progress-percentage prop to keep in sync with `current`. */
16
+ current: number;
17
+ }
18
+ /**
19
+ * A delivery/milestone stepper (.rb-stepper): renders one <li> per step, each
20
+ * classed .rb-stepper--complete/--current/--upcoming derived from `current` --
21
+ * callers never compute step state themselves. Each step's own class also
22
+ * drives the connector segment leading into it (CSS: `.rb-stepper__step:not(
23
+ * :first-child).rb-stepper--complete/--current::before`), so the rail fill
24
+ * and the step states can never drift out of sync with each other.
25
+ */
26
+ export declare const Stepper: import("react").ForwardRefExoticComponent<Omit<StepperProps, "ref"> & RefAttributes<HTMLOListElement>>;
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef } from "react";
3
+ import { cx } from "./cx.js";
4
+ function CheckIcon() {
5
+ return (_jsx("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: _jsx("path", { d: "M4 12.5 9.5 18 20 6", stroke: "currentColor", strokeWidth: "3", strokeLinecap: "round", strokeLinejoin: "round" }) }));
6
+ }
7
+ /**
8
+ * A delivery/milestone stepper (.rb-stepper): renders one <li> per step, each
9
+ * classed .rb-stepper--complete/--current/--upcoming derived from `current` --
10
+ * callers never compute step state themselves. Each step's own class also
11
+ * drives the connector segment leading into it (CSS: `.rb-stepper__step:not(
12
+ * :first-child).rb-stepper--complete/--current::before`), so the rail fill
13
+ * and the step states can never drift out of sync with each other.
14
+ */
15
+ export const Stepper = forwardRef(function Stepper({ steps, current, className, ...rest }, ref) {
16
+ return (_jsx("ol", { ref: ref, className: cx("rb-stepper", className), ...rest, children: steps.map((step, i) => {
17
+ const state = i < current ? "complete" : i === current ? "current" : "upcoming";
18
+ return (_jsxs("li", { className: cx("rb-stepper__step", `rb-stepper--${state}`), "aria-current": state === "current" ? "step" : undefined, children: [_jsx("span", { className: "rb-stepper__node", children: state === "complete" ? _jsx(CheckIcon, {}) : (step.icon ?? i + 1) }), _jsx("span", { className: "rb-stepper__label", children: step.label })] }, step.id));
19
+ }) }));
20
+ });
21
+ Stepper.displayName = "Stepper";
package/dist/Tabs.d.ts CHANGED
@@ -1,13 +1,13 @@
1
- import { type ReactNode } from "react";
1
+ import { type ReactNode, type RefAttributes } from "react";
2
2
  export interface TabItem {
3
3
  id: string;
4
4
  label: ReactNode;
5
5
  content: ReactNode;
6
6
  }
7
- export interface TabsProps {
7
+ export interface TabsProps extends RefAttributes<HTMLDivElement> {
8
8
  items: TabItem[];
9
9
  /** Initially active tab id; defaults to the first item. */
10
10
  defaultId?: string;
11
11
  className?: string;
12
12
  }
13
- export declare function Tabs({ items, defaultId, className }: TabsProps): import("react").JSX.Element;
13
+ export declare const Tabs: import("react").ForwardRefExoticComponent<Omit<TabsProps, "ref"> & RefAttributes<HTMLDivElement>>;
package/dist/Tabs.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useId, useRef, useState } from "react";
2
+ import { forwardRef, useId, useRef, useState, } from "react";
3
3
  import { cx } from "./cx.js";
4
- export function Tabs({ items, defaultId, className }) {
4
+ export const Tabs = forwardRef(function Tabs({ items, defaultId, className }, ref) {
5
5
  const base = useId();
6
6
  const [active, setActive] = useState(defaultId ?? items[0]?.id);
7
7
  // Fall back to the first tab if `active` names no item, so exactly one tab is
@@ -26,7 +26,7 @@ export function Tabs({ items, defaultId, className }) {
26
26
  // Move focus with the selection — the whole point of the roving tabindex.
27
27
  tabRefs.current[next]?.focus();
28
28
  };
29
- return (_jsxs("div", { className: className, children: [_jsx("div", { className: "rb-tabs", role: "tablist", children: items.map((t, idx) => {
29
+ return (_jsxs("div", { ref: ref, className: className, children: [_jsx("div", { className: "rb-tabs", role: "tablist", children: items.map((t, idx) => {
30
30
  const selected = t.id === activeId;
31
31
  return (_jsx("button", { ref: (el) => {
32
32
  tabRefs.current[idx] = el;
@@ -35,4 +35,5 @@ export function Tabs({ items, defaultId, className }) {
35
35
  const selected = t.id === activeId;
36
36
  return (_jsx("div", { className: "rb-tabpanel", role: "tabpanel", id: `${base}-panel-${t.id}`, "aria-labelledby": `${base}-tab-${t.id}`, hidden: !selected, tabIndex: 0, children: t.content }, t.id));
37
37
  })] }));
38
- }
38
+ });
39
+ Tabs.displayName = "Tabs";
@@ -1,14 +1,17 @@
1
- import type { HTMLAttributes, ProgressHTMLAttributes, ReactNode } from "react";
1
+ import { type HTMLAttributes, type ProgressHTMLAttributes, type ReactNode, type RefAttributes } from "react";
2
2
  export type SemanticVariant = "info" | "success" | "warning" | "danger";
3
- export interface BadgeProps extends HTMLAttributes<HTMLSpanElement> {
3
+ export interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, RefAttributes<HTMLSpanElement> {
4
4
  variant?: SemanticVariant;
5
5
  }
6
- export declare function Badge({ variant, className, ...rest }: BadgeProps): import("react").JSX.Element;
7
- export interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, "title"> {
6
+ export declare const Badge: import("react").ForwardRefExoticComponent<Omit<BadgeProps, "ref"> & RefAttributes<HTMLSpanElement>>;
7
+ export interface AlertProps extends Omit<HTMLAttributes<HTMLDivElement>, "title">, RefAttributes<HTMLDivElement> {
8
8
  variant?: SemanticVariant;
9
9
  title?: ReactNode;
10
10
  }
11
- export declare function Alert({ variant, title, className, children, ...rest }: AlertProps): import("react").JSX.Element;
12
- export type ProgressProps = ProgressHTMLAttributes<HTMLProgressElement>;
13
- export declare function Progress({ className, ...rest }: ProgressProps): import("react").JSX.Element;
14
- export declare function Spinner({ className, ...rest }: HTMLAttributes<HTMLSpanElement>): import("react").JSX.Element;
11
+ export declare const Alert: import("react").ForwardRefExoticComponent<Omit<AlertProps, "ref"> & RefAttributes<HTMLDivElement>>;
12
+ export interface ProgressProps extends ProgressHTMLAttributes<HTMLProgressElement>, RefAttributes<HTMLProgressElement> {
13
+ }
14
+ export declare const Progress: import("react").ForwardRefExoticComponent<Omit<ProgressProps, "ref"> & RefAttributes<HTMLProgressElement>>;
15
+ export interface SpinnerProps extends HTMLAttributes<HTMLSpanElement>, RefAttributes<HTMLSpanElement> {
16
+ }
17
+ export declare const Spinner: import("react").ForwardRefExoticComponent<Omit<SpinnerProps, "ref"> & RefAttributes<HTMLSpanElement>>;
package/dist/feedback.js CHANGED
@@ -1,14 +1,19 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, } from "react";
2
3
  import { cx } from "./cx.js";
3
- export function Badge({ variant, className, ...rest }) {
4
- return (_jsx("span", { className: cx("rb-badge", variant && `rb-badge--${variant}`, className), ...rest }));
5
- }
6
- export function Alert({ variant, title, className, children, ...rest }) {
7
- return (_jsxs("div", { role: "alert", className: cx("rb-alert", variant && `rb-alert--${variant}`, className), ...rest, children: [title !== undefined && _jsx("div", { className: "rb-alert__title", children: title }), children] }));
8
- }
9
- export function Progress({ className, ...rest }) {
10
- return _jsx("progress", { className: cx("rb-progress", className), ...rest });
11
- }
12
- export function Spinner({ className, ...rest }) {
13
- return (_jsx("span", { role: "status", "aria-label": "Loading", className: cx("rb-spinner", className), ...rest }));
14
- }
4
+ export const Badge = forwardRef(function Badge({ variant, className, ...rest }, ref) {
5
+ return (_jsx("span", { ref: ref, className: cx("rb-badge", variant && `rb-badge--${variant}`, className), ...rest }));
6
+ });
7
+ Badge.displayName = "Badge";
8
+ export const Alert = forwardRef(function Alert({ variant, title, className, children, ...rest }, ref) {
9
+ return (_jsxs("div", { ref: ref, role: "alert", className: cx("rb-alert", variant && `rb-alert--${variant}`, className), ...rest, children: [title !== undefined && _jsx("div", { className: "rb-alert__title", children: title }), children] }));
10
+ });
11
+ Alert.displayName = "Alert";
12
+ export const Progress = forwardRef(function Progress({ className, ...rest }, ref) {
13
+ return _jsx("progress", { ref: ref, className: cx("rb-progress", className), ...rest });
14
+ });
15
+ Progress.displayName = "Progress";
16
+ export const Spinner = forwardRef(function Spinner({ className, ...rest }, ref) {
17
+ return (_jsx("span", { ref: ref, role: "status", "aria-label": "Loading", className: cx("rb-spinner", className), ...rest }));
18
+ });
19
+ Spinner.displayName = "Spinner";
package/dist/form.d.ts CHANGED
@@ -1,17 +1,23 @@
1
- import type { HTMLAttributes, InputHTMLAttributes, LabelHTMLAttributes, ReactNode, SelectHTMLAttributes, TextareaHTMLAttributes } from "react";
2
- export type InputProps = InputHTMLAttributes<HTMLInputElement>;
3
- export declare function Input({ className, ...rest }: InputProps): import("react").JSX.Element;
4
- export type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement>;
5
- export declare function Textarea({ className, ...rest }: TextareaProps): import("react").JSX.Element;
6
- export type SelectProps = SelectHTMLAttributes<HTMLSelectElement>;
7
- export declare function Select({ className, ...rest }: SelectProps): import("react").JSX.Element;
8
- export type LabelProps = LabelHTMLAttributes<HTMLLabelElement>;
9
- export declare function Label({ className, ...rest }: LabelProps): import("react").JSX.Element;
10
- export declare function Field({ className, ...rest }: HTMLAttributes<HTMLDivElement>): import("react").JSX.Element;
11
- export interface ChoiceProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
1
+ import { type HTMLAttributes, type InputHTMLAttributes, type LabelHTMLAttributes, type ReactNode, type RefAttributes, type SelectHTMLAttributes, type TextareaHTMLAttributes } from "react";
2
+ export interface InputProps extends InputHTMLAttributes<HTMLInputElement>, RefAttributes<HTMLInputElement> {
3
+ }
4
+ export declare const Input: import("react").ForwardRefExoticComponent<Omit<InputProps, "ref"> & RefAttributes<HTMLInputElement>>;
5
+ export interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement>, RefAttributes<HTMLTextAreaElement> {
6
+ }
7
+ export declare const Textarea: import("react").ForwardRefExoticComponent<Omit<TextareaProps, "ref"> & RefAttributes<HTMLTextAreaElement>>;
8
+ export interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement>, RefAttributes<HTMLSelectElement> {
9
+ }
10
+ export declare const Select: import("react").ForwardRefExoticComponent<Omit<SelectProps, "ref"> & RefAttributes<HTMLSelectElement>>;
11
+ export interface LabelProps extends LabelHTMLAttributes<HTMLLabelElement>, RefAttributes<HTMLLabelElement> {
12
+ }
13
+ export declare const Label: import("react").ForwardRefExoticComponent<Omit<LabelProps, "ref"> & RefAttributes<HTMLLabelElement>>;
14
+ export interface FieldProps extends HTMLAttributes<HTMLDivElement>, RefAttributes<HTMLDivElement> {
15
+ }
16
+ export declare const Field: import("react").ForwardRefExoticComponent<Omit<FieldProps, "ref"> & RefAttributes<HTMLDivElement>>;
17
+ export interface ChoiceProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type">, RefAttributes<HTMLInputElement> {
12
18
  /** Optional label text; when set the control is wrapped in a .rb-choice row. */
13
19
  label?: ReactNode;
14
20
  }
15
- export declare function Checkbox({ label, className, ...rest }: ChoiceProps): import("react").JSX.Element;
16
- export declare function Radio({ label, className, ...rest }: ChoiceProps): import("react").JSX.Element;
17
- export declare function Switch({ label, className, ...rest }: ChoiceProps): import("react").JSX.Element;
21
+ export declare const Checkbox: import("react").ForwardRefExoticComponent<Omit<ChoiceProps, "ref"> & RefAttributes<HTMLInputElement>>;
22
+ export declare const Radio: import("react").ForwardRefExoticComponent<Omit<ChoiceProps, "ref"> & RefAttributes<HTMLInputElement>>;
23
+ export declare const Switch: import("react").ForwardRefExoticComponent<Omit<ChoiceProps, "ref"> & RefAttributes<HTMLInputElement>>;
package/dist/form.js CHANGED
@@ -1,32 +1,41 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { forwardRef, } from "react";
2
3
  import { cx } from "./cx.js";
3
- export function Input({ className, ...rest }) {
4
- return _jsx("input", { className: cx("rb-input", className), ...rest });
5
- }
6
- export function Textarea({ className, ...rest }) {
7
- return _jsx("textarea", { className: cx("rb-textarea", className), ...rest });
8
- }
9
- export function Select({ className, ...rest }) {
10
- return _jsx("select", { className: cx("rb-select", className), ...rest });
11
- }
12
- export function Label({ className, ...rest }) {
13
- return _jsx("label", { className: cx("rb-label", className), ...rest });
14
- }
15
- export function Field({ className, ...rest }) {
16
- return _jsx("div", { className: cx("rb-field", className), ...rest });
17
- }
4
+ export const Input = forwardRef(function Input({ className, ...rest }, ref) {
5
+ return _jsx("input", { ref: ref, className: cx("rb-input", className), ...rest });
6
+ });
7
+ Input.displayName = "Input";
8
+ export const Textarea = forwardRef(function Textarea({ className, ...rest }, ref) {
9
+ return _jsx("textarea", { ref: ref, className: cx("rb-textarea", className), ...rest });
10
+ });
11
+ Textarea.displayName = "Textarea";
12
+ export const Select = forwardRef(function Select({ className, ...rest }, ref) {
13
+ return _jsx("select", { ref: ref, className: cx("rb-select", className), ...rest });
14
+ });
15
+ Select.displayName = "Select";
16
+ export const Label = forwardRef(function Label({ className, ...rest }, ref) {
17
+ return _jsx("label", { ref: ref, className: cx("rb-label", className), ...rest });
18
+ });
19
+ Label.displayName = "Label";
20
+ export const Field = forwardRef(function Field({ className, ...rest }, ref) {
21
+ return _jsx("div", { ref: ref, className: cx("rb-field", className), ...rest });
22
+ });
23
+ Field.displayName = "Field";
18
24
  /** A checkbox/radio/switch control, optionally wrapped with its label. */
19
25
  function ChoiceControl({ label, control }) {
20
26
  if (label === undefined)
21
27
  return _jsx(_Fragment, { children: control });
22
28
  return (_jsxs("label", { className: "rb-choice", children: [control, label] }));
23
29
  }
24
- export function Checkbox({ label, className, ...rest }) {
25
- return (_jsx(ChoiceControl, { label: label, control: _jsx("input", { type: "checkbox", className: cx("rb-checkbox", className), ...rest }) }));
26
- }
27
- export function Radio({ label, className, ...rest }) {
28
- return (_jsx(ChoiceControl, { label: label, control: _jsx("input", { type: "radio", className: cx("rb-radio", className), ...rest }) }));
29
- }
30
- export function Switch({ label, className, ...rest }) {
31
- return (_jsx(ChoiceControl, { label: label, control: _jsx("input", { type: "checkbox", role: "switch", className: cx("rb-switch", className), ...rest }) }));
32
- }
30
+ export const Checkbox = forwardRef(function Checkbox({ label, className, ...rest }, ref) {
31
+ return (_jsx(ChoiceControl, { label: label, control: _jsx("input", { ref: ref, type: "checkbox", className: cx("rb-checkbox", className), ...rest }) }));
32
+ });
33
+ Checkbox.displayName = "Checkbox";
34
+ export const Radio = forwardRef(function Radio({ label, className, ...rest }, ref) {
35
+ return (_jsx(ChoiceControl, { label: label, control: _jsx("input", { ref: ref, type: "radio", className: cx("rb-radio", className), ...rest }) }));
36
+ });
37
+ Radio.displayName = "Radio";
38
+ export const Switch = forwardRef(function Switch({ label, className, ...rest }, ref) {
39
+ return (_jsx(ChoiceControl, { label: label, control: _jsx("input", { ref: ref, type: "checkbox", role: "switch", className: cx("rb-switch", className), ...rest }) }));
40
+ });
41
+ Switch.displayName = "Switch";
package/dist/index.d.ts CHANGED
@@ -1,9 +1,11 @@
1
1
  export { Button, type ButtonProps } from "./Button.js";
2
2
  export { Card, type CardProps } from "./Card.js";
3
3
  export { NavLink, type NavLinkProps } from "./NavLink.js";
4
- export { Input, Textarea, Select, Label, Field, Checkbox, Radio, Switch, type InputProps, type TextareaProps, type SelectProps, type LabelProps, type ChoiceProps, } from "./form.js";
5
- export { Badge, Alert, Progress, Spinner, type BadgeProps, type AlertProps, type ProgressProps, type SemanticVariant, } from "./feedback.js";
4
+ export { NavRail, type NavRailProps, type NavRailItem } from "./NavRail.js";
5
+ export { Input, Textarea, Select, Label, Field, Checkbox, Radio, Switch, type InputProps, type TextareaProps, type SelectProps, type LabelProps, type FieldProps, type ChoiceProps, } from "./form.js";
6
+ export { Badge, Alert, Progress, Spinner, type BadgeProps, type AlertProps, type ProgressProps, type SpinnerProps, type SemanticVariant, } from "./feedback.js";
6
7
  export { Dialog, type DialogProps } from "./Dialog.js";
7
8
  export { Tabs, type TabsProps, type TabItem } from "./Tabs.js";
9
+ export { Stepper, type StepperProps, type StepperStep } from "./Stepper.js";
8
10
  export { LinksIndex, type LinksIndexProps, type LinkItem, type LinkCategory, type LinkUrl, } from "./LinksIndex.js";
9
11
  export { cx } from "./cx.js";
package/dist/index.js CHANGED
@@ -1,9 +1,11 @@
1
1
  export { Button } from "./Button.js";
2
2
  export { Card } from "./Card.js";
3
3
  export { NavLink } from "./NavLink.js";
4
+ export { NavRail } from "./NavRail.js";
4
5
  export { Input, Textarea, Select, Label, Field, Checkbox, Radio, Switch, } from "./form.js";
5
6
  export { Badge, Alert, Progress, Spinner, } from "./feedback.js";
6
7
  export { Dialog } from "./Dialog.js";
7
8
  export { Tabs } from "./Tabs.js";
9
+ export { Stepper } from "./Stepper.js";
8
10
  export { LinksIndex, } from "./LinksIndex.js";
9
11
  export { cx } from "./cx.js";
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@rackbops/ui-react",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "React components styled by @rackbops/styles rackbops themes.",
5
- "license": "UNLICENSED",
5
+ "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/roshne/rackbops-ui-ux-std-lib.git",
@@ -29,9 +29,11 @@
29
29
  "react": ">=18"
30
30
  },
31
31
  "devDependencies": {
32
+ "@types/jsdom": "^30.0.0",
32
33
  "@types/node": "^22.0.0",
33
34
  "@types/react": "^19.0.0",
34
35
  "@types/react-dom": "^19.0.0",
36
+ "jsdom": "^30.0.1",
35
37
  "react": "^19.0.0",
36
38
  "react-dom": "^19.0.0",
37
39
  "tsx": "^4.19.0",