@usevyre/react 1.2.1 → 1.4.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.
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @usevyre/react — Carousel + CarouselSlide
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Component: Carousel (+ CarouselSlide) │
7
+ * │ Import: import { Carousel, CarouselSlide } from "@usevyre/react" │
8
+ * │ │
9
+ * │ Accessible content slider (galleries / onboarding / testimonials).│
10
+ * │ CONTROLLED by a 0-based slide index. Slide order = index. │
11
+ * │ │
12
+ * │ <Carousel> │
13
+ * │ value? = number (controlled active slide) │
14
+ * │ defaultValue = number (uncontrolled, default 0) │
15
+ * │ onChange? = (index: number) => void │
16
+ * │ loop? = boolean (wrap past the ends) │
17
+ * │ autoPlay? = boolean interval = ms (default 5000) │
18
+ * │ showArrows? = boolean (default true) │
19
+ * │ showIndicators= boolean (default true) │
20
+ * │ <CarouselSlide> any content </CarouselSlide> │
21
+ * │ │
22
+ * │ Snap scrolling, clickable dot indicators, ←/→ keyboard, │
23
+ * │ autoplay pauses on hover/focus. │
24
+ * └──────────────────────────────────────────────────────────────────┘
25
+ *
26
+ * @example
27
+ * const [i, setI] = useState(0);
28
+ * <Carousel value={i} onChange={setI} loop>
29
+ * <CarouselSlide><img src="/a.jpg" alt="A" /></CarouselSlide>
30
+ * <CarouselSlide><img src="/b.jpg" alt="B" /></CarouselSlide>
31
+ * </Carousel>
32
+ */
33
+ import React from "react";
34
+ import type { BaseProps } from "../../types";
35
+ export interface CarouselSlideProps extends BaseProps {
36
+ children?: React.ReactNode;
37
+ }
38
+ export declare const CarouselSlide: React.ForwardRefExoticComponent<CarouselSlideProps & React.RefAttributes<HTMLDivElement>>;
39
+ export interface CarouselProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange">, BaseProps {
40
+ value?: number;
41
+ defaultValue?: number;
42
+ onChange?: (index: number) => void;
43
+ loop?: boolean;
44
+ autoPlay?: boolean;
45
+ /** Autoplay interval in ms */
46
+ interval?: number;
47
+ showArrows?: boolean;
48
+ showIndicators?: boolean;
49
+ children?: React.ReactNode;
50
+ "aria-label"?: string;
51
+ }
52
+ export declare const Carousel: React.ForwardRefExoticComponent<CarouselProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @usevyre/react — EmptyState
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Component: EmptyState │
7
+ * │ Import: import { EmptyState } from "@usevyre/react" │
8
+ * │ │
9
+ * │ Presentational placeholder for empty lists, tables, and search │
10
+ * │ results. No state. The optional call-to-action goes in children. │
11
+ * │ │
12
+ * │ title = string (required) │
13
+ * │ description? = string │
14
+ * │ variant = "default"(box) | "search"(magnifier) │
15
+ * │ | "error"(warning) — picks a preset icon │
16
+ * │ icon? = ReactNode (overrides the preset) │
17
+ * │ size = "sm" | "md"(default) | "lg" │
18
+ * │ children? = the CTA (Button, or two buttons in a Stack) │
19
+ * └──────────────────────────────────────────────────────────────────┘
20
+ *
21
+ * @example
22
+ * <EmptyState
23
+ * variant="search"
24
+ * title="No results"
25
+ * description="Try a different search term."
26
+ * >
27
+ * <Button variant="secondary" onClick={reset}>Clear filters</Button>
28
+ * </EmptyState>
29
+ */
30
+ import React from "react";
31
+ import type { BaseProps } from "../../types";
32
+ declare const PRESET_ICONS: {
33
+ readonly default: () => import("react/jsx-runtime").JSX.Element;
34
+ readonly search: () => import("react/jsx-runtime").JSX.Element;
35
+ readonly error: () => import("react/jsx-runtime").JSX.Element;
36
+ };
37
+ export type EmptyStateVariant = keyof typeof PRESET_ICONS;
38
+ export interface EmptyStateProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, BaseProps {
39
+ /** Headline (required) */
40
+ title: string;
41
+ /** Supporting text under the title */
42
+ description?: string;
43
+ /** Picks a preset icon */
44
+ variant?: EmptyStateVariant;
45
+ /** Custom icon, overrides the variant preset */
46
+ icon?: React.ReactNode;
47
+ size?: "sm" | "md" | "lg";
48
+ }
49
+ export declare const EmptyState: React.ForwardRefExoticComponent<EmptyStateProps & React.RefAttributes<HTMLDivElement>>;
50
+ export {};
@@ -0,0 +1,96 @@
1
+ /**
2
+ * @usevyre/react — Form + FormField
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Components: Form, FormField │
7
+ * │ Import: import { Form, FormField } from "@usevyre/react" │
8
+ * │ │
9
+ * │ Controlled, data-driven form. Zero dependencies. Validation runs │
10
+ * │ on submit and (after the first submit) on blur. Errors map into │
11
+ * │ the wrapped Field automatically (state="error" + hint=message). │
12
+ * │ │
13
+ * │ <Form> │
14
+ * │ values? = Record<string, any> (controlled) │
15
+ * │ defaultValues?= Record<string, any> (uncontrolled) │
16
+ * │ onChange? = (values) => void │
17
+ * │ onSubmit = (values) => void | Promise<void> (valid only) │
18
+ * │ onInvalid? = (errors: Record<string,string>) => void │
19
+ * │ │
20
+ * │ <FormField name="email" label="Email" rules={{ ... }}> │
21
+ * │ <Input type="email" /> ← single control child │
22
+ * │ </FormField> │
23
+ * │ rules = { required?: boolean | string, │
24
+ * │ minLength?, maxLength?, min?, max?: number, │
25
+ * │ pattern?: RegExp, email?: boolean, │
26
+ * │ validate?: (value, allValues) => string | null } │
27
+ * │ │
28
+ * │ FormField injects name / value / onChange / onBlur into its │
29
+ * │ child and wraps it in <Field label state hint>. │
30
+ * └──────────────────────────────────────────────────────────────────┘
31
+ *
32
+ * @example
33
+ * const [values, setValues] = useState({ email: "", password: "" });
34
+ * <Form
35
+ * values={values}
36
+ * onChange={setValues}
37
+ * onSubmit={(v) => signIn(v)}
38
+ * >
39
+ * <FormField name="email" label="Email" rules={{ required: true, email: true }}>
40
+ * <Input type="email" />
41
+ * </FormField>
42
+ * <FormField name="password" label="Password" rules={{ required: true, minLength: 8 }}>
43
+ * <Input type="password" />
44
+ * </FormField>
45
+ * <Button type="submit" variant="primary">Sign in</Button>
46
+ * </Form>
47
+ */
48
+ import React from "react";
49
+ export interface FormRules {
50
+ /** Non-empty required. Pass a string to use it as the message. */
51
+ required?: boolean | string;
52
+ /** Minimum string length */
53
+ minLength?: number;
54
+ /** Maximum string length */
55
+ maxLength?: number;
56
+ /** Minimum numeric value */
57
+ min?: number;
58
+ /** Maximum numeric value */
59
+ max?: number;
60
+ /** Must match this pattern */
61
+ pattern?: RegExp;
62
+ /** Must be a valid email address */
63
+ email?: boolean;
64
+ /** Custom validator — return an error message string, or null if valid */
65
+ validate?: (value: unknown, allValues: Record<string, unknown>) => string | null | undefined;
66
+ }
67
+ type Values = Record<string, unknown>;
68
+ type Errors = Record<string, string>;
69
+ export interface FormProps extends Omit<React.FormHTMLAttributes<HTMLFormElement>, "onSubmit" | "onChange" | "onInvalid"> {
70
+ /** Controlled values map */
71
+ values?: Values;
72
+ /** Initial values when uncontrolled */
73
+ defaultValues?: Values;
74
+ /** Called whenever any field value changes */
75
+ onChange?: (values: Values) => void;
76
+ /** Called with the values when the form is submitted AND valid */
77
+ onSubmit?: (values: Values) => void | Promise<void>;
78
+ /** Called with the error map when submitted but invalid */
79
+ onInvalid?: (errors: Errors) => void;
80
+ }
81
+ export declare const Form: React.ForwardRefExoticComponent<FormProps & React.RefAttributes<HTMLFormElement>>;
82
+ export interface FormFieldProps {
83
+ /** Key into the form's values map */
84
+ name: string;
85
+ /** Label rendered by the wrapping Field */
86
+ label?: string;
87
+ /** Helper text shown when there is no error */
88
+ hint?: string;
89
+ /** Validation rules */
90
+ rules?: FormRules;
91
+ /** Single form control element (Input, Textarea, Select, …) */
92
+ children: React.ReactElement;
93
+ className?: string;
94
+ }
95
+ export declare const FormField: React.FC<FormFieldProps>;
96
+ export {};
@@ -0,0 +1,184 @@
1
+ /**
2
+ * @usevyre/react — Layout primitives (Stack, Grid, GridItem, Box)
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Components: Stack, Grid, GridItem, Box │
7
+ * │ Import: import { Stack, Grid, GridItem, Box } from "@usevyre/react"│
8
+ * │ │
9
+ * │ USE THESE INSTEAD OF <div style={{ display: "flex" }}>. │
10
+ * │ Every spacing value is a design token — never a raw px/rem number.│
11
+ * │ │
12
+ * │ Stack/Grid/Box share width/height (avoids inline width style): │
13
+ * │ width|height = "auto"|"full"|"fit"|"screen" │
14
+ * │ | xs|sm|md|lg|xl|2xl (fixed rem sizes) │
15
+ * │ │
16
+ * │ <Stack> full one-dimensional flex layout │
17
+ * │ direction = "row"(default)|"column"|"row-reverse" │
18
+ * │ |"column-reverse" │
19
+ * │ inline = boolean (display:inline-flex) │
20
+ * │ gap = token; rowGap / columnGap = token (per-axis) │
21
+ * │ align = items: start|center|end|stretch|baseline │
22
+ * │ justify = content: start|center|end|between|around|evenly │
23
+ * │ alignContent= multi-line: start|center|end|stretch|between │
24
+ * │ |around|evenly │
25
+ * │ alignSelf = auto|start|center|end|stretch|baseline │
26
+ * │ wrap = "nowrap"(default)|"wrap"|"wrap-reverse" │
27
+ * │ grow shrink = number basis = token|"auto"|"content"|"0" │
28
+ * │ as = any HTML tag (default: "div") │
29
+ * │ │
30
+ * │ <Grid> two-dimensional CSS grid │
31
+ * │ columns = number (1-12) | "auto-fit" (default: 1) │
32
+ * │ rows = number | "auto" │
33
+ * │ flow = "row"|"column"|"dense"|"row-dense"|"column-dense" │
34
+ * │ gap / rowGap / columnGap = token │
35
+ * │ align = align-items justify = justify-items │
36
+ * │ as = any HTML tag (default: "div") │
37
+ * │ <GridItem> child placement │
38
+ * │ colSpan rowSpan colStart rowStart = number │
39
+ * │ │
40
+ * │ <Box> spacing-only container + controlled escape hatch │
41
+ * │ padding paddingX paddingY │
42
+ * │ paddingTop paddingRight paddingBottom paddingLeft = token │
43
+ * │ margin marginX marginY │
44
+ * │ marginTop marginRight marginBottom marginLeft = token │
45
+ * │ (per-side overrides the X/Y/shorthand it belongs to) │
46
+ * │ as = any HTML tag (default: "div") │
47
+ * │ style = ANTI-PATTERN escape hatch — prefer tokens. │
48
+ * │ │
49
+ * │ All render a plain <div> (or `as`) in the browser. │
50
+ * └──────────────────────────────────────────────────────────────────┘
51
+ *
52
+ * @example
53
+ * <Stack direction="column" gap="md" align="center">
54
+ * <Avatar src={user.avatar} />
55
+ * <Text>{user.name}</Text>
56
+ * </Stack>
57
+ *
58
+ * @example
59
+ * <Grid columns={3} gap="lg">
60
+ * <GridItem colSpan={2}><Card>Wide</Card></GridItem>
61
+ * <Card>…</Card>
62
+ * </Grid>
63
+ */
64
+ import React from "react";
65
+ /** Semantic spacing scale — maps to --vyre-spacing-* tokens. */
66
+ export type SpaceToken = "none" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
67
+ export type StackDirection = "row" | "column" | "row-reverse" | "column-reverse";
68
+ export type StackWrap = "nowrap" | "wrap" | "wrap-reverse";
69
+ export type StackAlign = "start" | "center" | "end" | "stretch" | "baseline";
70
+ export type StackJustify = "start" | "center" | "end" | "between" | "around" | "evenly";
71
+ export type StackAlignContent = "start" | "center" | "end" | "stretch" | "between" | "around" | "evenly";
72
+ export type StackAlignSelf = "auto" | "start" | "center" | "end" | "stretch" | "baseline";
73
+ export type StackBasis = SpaceToken | "auto" | "content" | "0";
74
+ export type GridAlign = "start" | "center" | "end" | "stretch";
75
+ export type GridFlow = "row" | "column" | "dense" | "row-dense" | "column-dense";
76
+ export type GridColumns = number | "auto-fit";
77
+ /**
78
+ * Sizing scale for width / height.
79
+ * - Keywords: "auto" | "full" (100%) | "fit" (fit-content) | "screen"
80
+ * (100vw for width, 100vh for height)
81
+ * - Token sizes (fixed rem): xs 8 · sm 12 · md 16 · lg 24 · xl 32 · 2xl 42
82
+ */
83
+ export type SizeToken = "auto" | "full" | "fit" | "screen" | "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
84
+ interface SizingProps {
85
+ /** Width — keyword or token size. Avoids an inline width style. */
86
+ width?: SizeToken;
87
+ /** Height — keyword or token size. Avoids an inline height style. */
88
+ height?: SizeToken;
89
+ }
90
+ type PolymorphicProps<P> = P & {
91
+ /** HTML element to render. Always a real DOM element in the browser. */
92
+ as?: keyof JSX.IntrinsicElements;
93
+ className?: string;
94
+ /**
95
+ * Inline styles. Prefer the token props above; use this only for values
96
+ * the design system genuinely cannot express. Flagged as an anti-pattern
97
+ * by @usevyre/eslint-plugin (no-inline-layout-styles).
98
+ */
99
+ style?: React.CSSProperties;
100
+ children?: React.ReactNode;
101
+ };
102
+ export interface StackProps extends PolymorphicProps<React.HTMLAttributes<HTMLElement>>, SizingProps {
103
+ /** Main axis direction (flex-direction) */
104
+ direction?: StackDirection;
105
+ /** Render as inline-flex instead of flex */
106
+ inline?: boolean;
107
+ /** Space between children — design token */
108
+ gap?: SpaceToken;
109
+ /** Row gap override — design token */
110
+ rowGap?: SpaceToken;
111
+ /** Column gap override — design token */
112
+ columnGap?: SpaceToken;
113
+ /** Cross-axis alignment of items (align-items) */
114
+ align?: StackAlign;
115
+ /** Main-axis distribution (justify-content) */
116
+ justify?: StackJustify;
117
+ /** Multi-line cross-axis distribution (align-content) */
118
+ alignContent?: StackAlignContent;
119
+ /** This element's own cross-axis alignment (align-self) */
120
+ alignSelf?: StackAlignSelf;
121
+ /** Wrapping behaviour (flex-wrap). `true` is treated as "wrap". */
122
+ wrap?: StackWrap | boolean;
123
+ /** flex-grow */
124
+ grow?: number;
125
+ /** flex-shrink */
126
+ shrink?: number;
127
+ /** flex-basis — token, "auto", "content", or "0" */
128
+ basis?: StackBasis;
129
+ }
130
+ export declare const Stack: React.ForwardRefExoticComponent<StackProps & React.RefAttributes<HTMLElement>>;
131
+ export interface GridProps extends PolymorphicProps<React.HTMLAttributes<HTMLElement>>, SizingProps {
132
+ /** Number of equal columns (1–12) or responsive "auto-fit" */
133
+ columns?: GridColumns;
134
+ /** Explicit row count, or "auto" */
135
+ rows?: number | "auto";
136
+ /** Auto-placement flow (grid-auto-flow) */
137
+ flow?: GridFlow;
138
+ /** Space between cells — design token */
139
+ gap?: SpaceToken;
140
+ /** Row gap override — design token */
141
+ rowGap?: SpaceToken;
142
+ /** Column gap override — design token */
143
+ columnGap?: SpaceToken;
144
+ /** Cross-axis alignment of cells (align-items) */
145
+ align?: GridAlign;
146
+ /** Inline-axis alignment of cells (justify-items) */
147
+ justify?: GridAlign;
148
+ }
149
+ export declare const Grid: React.ForwardRefExoticComponent<GridProps & React.RefAttributes<HTMLElement>>;
150
+ export interface GridItemProps extends PolymorphicProps<React.HTMLAttributes<HTMLElement>> {
151
+ /** Number of columns this item spans */
152
+ colSpan?: number;
153
+ /** Number of rows this item spans */
154
+ rowSpan?: number;
155
+ /** 1-based column line this item starts at */
156
+ colStart?: number;
157
+ /** 1-based row line this item starts at */
158
+ rowStart?: number;
159
+ }
160
+ export declare const GridItem: React.ForwardRefExoticComponent<GridItemProps & React.RefAttributes<HTMLElement>>;
161
+ export interface BoxProps extends PolymorphicProps<React.HTMLAttributes<HTMLElement>>, SizingProps {
162
+ /** Inner spacing (all sides) — design token */
163
+ padding?: SpaceToken;
164
+ /** Inner spacing left+right — design token */
165
+ paddingX?: SpaceToken;
166
+ /** Inner spacing top+bottom — design token */
167
+ paddingY?: SpaceToken;
168
+ paddingTop?: SpaceToken;
169
+ paddingRight?: SpaceToken;
170
+ paddingBottom?: SpaceToken;
171
+ paddingLeft?: SpaceToken;
172
+ /** Outer spacing (all sides) — design token */
173
+ margin?: SpaceToken;
174
+ /** Outer spacing left+right — design token */
175
+ marginX?: SpaceToken;
176
+ /** Outer spacing top+bottom — design token */
177
+ marginY?: SpaceToken;
178
+ marginTop?: SpaceToken;
179
+ marginRight?: SpaceToken;
180
+ marginBottom?: SpaceToken;
181
+ marginLeft?: SpaceToken;
182
+ }
183
+ export declare const Box: React.ForwardRefExoticComponent<BoxProps & React.RefAttributes<HTMLElement>>;
184
+ export {};
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @usevyre/react — NumberInput
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Component: NumberInput │
7
+ * │ Import: import { NumberInput } from "@usevyre/react" │
8
+ * │ │
9
+ * │ Controlled numeric input with −/+ stepper buttons. onChange emits │
10
+ * │ a NUMBER (or null when empty) — not an event. Drops straight into │
11
+ * │ <FormField> (Form handles the non-event value automatically). │
12
+ * │ │
13
+ * │ value = number | null (controlled) │
14
+ * │ onChange = (value: number | null) => void │
15
+ * │ min max step = number (step default 1) │
16
+ * │ precision = number (decimal places to round to) │
17
+ * │ size = "sm" | "md"(default) | "lg" │
18
+ * │ disabled readOnly = boolean │
19
+ * │ │
20
+ * │ Clamps to min/max on blur. Keyboard: ArrowUp/Down ±step, │
21
+ * │ Shift+Arrow ±step×10. Empty input → null. │
22
+ * └──────────────────────────────────────────────────────────────────┘
23
+ *
24
+ * @example
25
+ * const [qty, setQty] = useState<number | null>(1);
26
+ * <NumberInput value={qty} onChange={setQty} min={1} max={99} />
27
+ *
28
+ * @example
29
+ * <FormField name="age" label="Age" rules={{ required: true, min: 18 }}>
30
+ * <NumberInput min={0} max={120} />
31
+ * </FormField>
32
+ */
33
+ import React from "react";
34
+ import type { Size, BaseProps } from "../../types";
35
+ export interface NumberInputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, "size" | "value" | "onChange" | "defaultValue" | "type">, BaseProps {
36
+ /** Controlled value. null = empty. */
37
+ value?: number | null;
38
+ /** Uncontrolled initial value */
39
+ defaultValue?: number | null;
40
+ /** Called with the parsed number, or null when the field is empty */
41
+ onChange?: (value: number | null) => void;
42
+ min?: number;
43
+ max?: number;
44
+ /** Increment/decrement amount (default 1) */
45
+ step?: number;
46
+ /** Decimal places to round to */
47
+ precision?: number;
48
+ size?: Exclude<Size, "icon">;
49
+ disabled?: boolean;
50
+ readOnly?: boolean;
51
+ }
52
+ export declare const NumberInput: React.ForwardRefExoticComponent<NumberInputProps & React.RefAttributes<HTMLInputElement>>;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @usevyre/react — OTPInput
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Component: OTPInput │
7
+ * │ Import: import { OTPInput } from "@usevyre/react" │
8
+ * │ │
9
+ * │ Segmented one-time-code input (verification / 2FA). CONTROLLED. │
10
+ * │ onChange emits the STRING value (not an event) — drops into │
11
+ * │ <FormField>. Paste-aware, auto-advance/backspace, arrow keys. │
12
+ * │ │
13
+ * │ value = string (controlled, length ≤ `length`) │
14
+ * │ onChange = (value: string) => void │
15
+ * │ onComplete?= (value: string) => void (all slots filled) │
16
+ * │ length = number (default 6) │
17
+ * │ type = "numeric"(default) | "alphanumeric" │
18
+ * │ mask = boolean (dots instead of chars, like a password) │
19
+ * │ size = "sm" | "md"(default) | "lg" │
20
+ * │ disabled = boolean autoFocus = boolean │
21
+ * │ │
22
+ * │ Pasting a full code fills every slot. Backspace on an empty slot │
23
+ * │ moves to the previous one. │
24
+ * └──────────────────────────────────────────────────────────────────┘
25
+ *
26
+ * @example
27
+ * const [code, setCode] = useState("");
28
+ * <OTPInput value={code} onChange={setCode} onComplete={verify} />
29
+ *
30
+ * @example
31
+ * <FormField name="otp" label="Verification code"
32
+ * rules={{ required: true, minLength: 6 }}>
33
+ * <OTPInput length={6} />
34
+ * </FormField>
35
+ */
36
+ import React from "react";
37
+ import type { BaseProps } from "../../types";
38
+ export interface OTPInputProps extends BaseProps {
39
+ value?: string;
40
+ defaultValue?: string;
41
+ onChange?: (value: string) => void;
42
+ /** Fired once when every slot is filled */
43
+ onComplete?: (value: string) => void;
44
+ length?: number;
45
+ type?: "numeric" | "alphanumeric";
46
+ /** Render dots instead of characters */
47
+ mask?: boolean;
48
+ size?: "sm" | "md" | "lg";
49
+ disabled?: boolean;
50
+ autoFocus?: boolean;
51
+ /** Forwarded to FormField wiring (used as the field name) */
52
+ name?: string;
53
+ onBlur?: React.FocusEventHandler<HTMLInputElement>;
54
+ }
55
+ export declare const OTPInput: React.ForwardRefExoticComponent<OTPInputProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * @usevyre/react — Stat + StatGroup
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Component: Stat (+ StatGroup) │
7
+ * │ Import: import { Stat, StatGroup } from "@usevyre/react" │
8
+ * │ │
9
+ * │ Presentational dashboard KPI. No state. │
10
+ * │ │
11
+ * │ label = string (required) │
12
+ * │ value = string | number (required, large) │
13
+ * │ delta? = string | number (the change amount) │
14
+ * │ trend? = "up" | "down" | "neutral" (CONTROLS the color │
15
+ * │ — up=success, down=danger, neutral=muted) │
16
+ * │ deltaLabel? = string (e.g. "vs last month") │
17
+ * │ icon? = ReactNode │
18
+ * │ size = "sm" | "md"(default) | "lg" │
19
+ * │ │
20
+ * │ trend is EXPLICIT so "churn down = good" can stay green. │
21
+ * │ Wrap several in <StatGroup> for an evenly-split row with dividers.│
22
+ * └──────────────────────────────────────────────────────────────────┘
23
+ *
24
+ * @example
25
+ * <StatGroup>
26
+ * <Stat label="Revenue" value="$48.2k" delta="+12%" trend="up"
27
+ * deltaLabel="vs last month" />
28
+ * <Stat label="Churn" value="2.1%" delta="-0.4%" trend="up"
29
+ * deltaLabel="lower is better" />
30
+ * <Stat label="Orders" value="1,204" delta="0%" trend="neutral" />
31
+ * </StatGroup>
32
+ */
33
+ import React from "react";
34
+ import type { BaseProps } from "../../types";
35
+ export type StatTrend = "up" | "down" | "neutral";
36
+ export interface StatProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title">, BaseProps {
37
+ /** Metric name (required) */
38
+ label: string;
39
+ /** The headline figure (required) */
40
+ value: string | number;
41
+ /** The change amount, e.g. "+12%" or 24 */
42
+ delta?: string | number;
43
+ /** Explicitly sets the delta color — up=success, down=danger, neutral=muted */
44
+ trend?: StatTrend;
45
+ /** Context for the delta, e.g. "vs last month" */
46
+ deltaLabel?: string;
47
+ /** Optional leading icon */
48
+ icon?: React.ReactNode;
49
+ size?: "sm" | "md" | "lg";
50
+ }
51
+ export declare const Stat: React.ForwardRefExoticComponent<StatProps & React.RefAttributes<HTMLDivElement>>;
52
+ export interface StatGroupProps extends React.HTMLAttributes<HTMLDivElement>, BaseProps {
53
+ children?: React.ReactNode;
54
+ }
55
+ export declare const StatGroup: React.ForwardRefExoticComponent<StatGroupProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @usevyre/react — Stepper + Step + StepPanel
3
+ *
4
+ * AI CONTEXT:
5
+ * ┌──────────────────────────────────────────────────────────────────┐
6
+ * │ Component: Stepper (+ StepperNav, Step, StepPanel) │
7
+ * │ Import: import { Stepper, StepperNav, Step, StepPanel } │
8
+ * │ from "@usevyre/react" │
9
+ * │ │
10
+ * │ Multi-step flow indicator + controller (onboarding/checkout/ │
11
+ * │ wizard). CONTROLLED by a 0-based index. Indices come from order. │
12
+ * │ │
13
+ * │ <Stepper> │
14
+ * │ value? = number (controlled active index) │
15
+ * │ defaultValue = number (uncontrolled, default 0) │
16
+ * │ onChange? = (index: number) => void │
17
+ * │ orientation = "horizontal"(default) | "vertical" │
18
+ * │ clickable? = boolean (click a completed Step to go back) │
19
+ * │ <StepperNav> <Step label description? icon? /> … </StepperNav> │
20
+ * │ <StepPanel> … </StepPanel> ← rendered when its order == active │
21
+ * │ │
22
+ * │ Each Step auto-gets state completed | current | upcoming. │
23
+ * │ NOT Tabs (peer panels) — Stepper is an ORDERED linear flow. │
24
+ * └──────────────────────────────────────────────────────────────────┘
25
+ *
26
+ * @example
27
+ * const [step, setStep] = useState(0);
28
+ * <Stepper value={step} onChange={setStep}>
29
+ * <StepperNav>
30
+ * <Step label="Account" />
31
+ * <Step label="Profile" />
32
+ * <Step label="Done" />
33
+ * </StepperNav>
34
+ * <StepPanel><AccountForm /></StepPanel>
35
+ * <StepPanel><ProfileForm /></StepPanel>
36
+ * <StepPanel><Summary /></StepPanel>
37
+ * </Stepper>
38
+ */
39
+ import React from "react";
40
+ import type { BaseProps } from "../../types";
41
+ export interface StepperProps extends BaseProps {
42
+ /** Controlled active step (0-based) */
43
+ value?: number;
44
+ /** Initial active step when uncontrolled */
45
+ defaultValue?: number;
46
+ /** Called with the new active index */
47
+ onChange?: (index: number) => void;
48
+ orientation?: "horizontal" | "vertical";
49
+ /** Allow clicking a completed Step to jump back to it */
50
+ clickable?: boolean;
51
+ children?: React.ReactNode;
52
+ }
53
+ export declare const Stepper: React.ForwardRefExoticComponent<StepperProps & React.RefAttributes<HTMLDivElement>>;
54
+ export interface StepperNavProps extends BaseProps {
55
+ children?: React.ReactNode;
56
+ }
57
+ export declare const StepperNav: React.ForwardRefExoticComponent<StepperNavProps & React.RefAttributes<HTMLDivElement>>;
58
+ export interface StepProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "title"> {
59
+ label?: React.ReactNode;
60
+ description?: React.ReactNode;
61
+ /** Custom indicator content (defaults to step number / ✓ when done) */
62
+ icon?: React.ReactNode;
63
+ /** Explicit 0-based index. Optional — inferred from order otherwise. */
64
+ index?: number;
65
+ /** @internal injected by StepperNav */
66
+ __index?: number;
67
+ }
68
+ export declare const Step: React.ForwardRefExoticComponent<StepProps & React.RefAttributes<HTMLDivElement>>;
69
+ export interface StepPanelProps extends BaseProps {
70
+ children?: React.ReactNode;
71
+ /** Explicit 0-based index. Optional — inferred from order otherwise. */
72
+ index?: number;
73
+ /** @internal injected by Stepper */
74
+ __index?: number;
75
+ }
76
+ export declare const StepPanel: React.FC<StepPanelProps>;