@ashwa-io/ui 0.0.2 → 0.0.4

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 (72) hide show
  1. package/dist/components/atomic/Badge/Badge.d.ts +11 -0
  2. package/dist/components/atomic/Badge/Badge.js +31 -0
  3. package/dist/components/atomic/Badge/index.d.ts +2 -0
  4. package/dist/components/atomic/Button/Button.d.ts +3 -2
  5. package/dist/components/atomic/Button/Button.js +3 -10
  6. package/dist/components/atomic/Button/buttonVariant.d.ts +3 -0
  7. package/dist/components/atomic/Button/buttonVariant.js +10 -0
  8. package/dist/components/atomic/Button/index.d.ts +2 -1
  9. package/dist/components/atomic/Checkbox/Checkbox.d.ts +11 -0
  10. package/dist/components/atomic/Checkbox/Checkbox.js +32 -0
  11. package/dist/components/atomic/Checkbox/index.d.ts +2 -0
  12. package/dist/components/atomic/ColorInput/ColorInput.d.ts +15 -0
  13. package/dist/components/atomic/ColorInput/ColorInput.js +44 -0
  14. package/dist/components/atomic/ColorInput/colorHex.js +8 -0
  15. package/dist/components/atomic/ColorInput/index.d.ts +2 -0
  16. package/dist/components/atomic/Divider/Divider.d.ts +8 -0
  17. package/dist/components/atomic/Divider/Divider.js +12 -0
  18. package/dist/components/atomic/Divider/index.d.ts +2 -0
  19. package/dist/components/atomic/Heading/Heading.d.ts +12 -0
  20. package/dist/components/atomic/Heading/Heading.js +30 -0
  21. package/dist/components/atomic/Heading/index.d.ts +2 -0
  22. package/dist/components/atomic/IconButton/IconButton.d.ts +21 -0
  23. package/dist/components/atomic/IconButton/IconButton.js +34 -0
  24. package/dist/components/atomic/IconButton/index.d.ts +2 -0
  25. package/dist/components/atomic/Select/Select.d.ts +18 -0
  26. package/dist/components/atomic/Select/Select.js +47 -0
  27. package/dist/components/atomic/Select/index.d.ts +2 -0
  28. package/dist/components/atomic/Skeleton/Skeleton.d.ts +8 -0
  29. package/dist/components/atomic/Skeleton/Skeleton.js +17 -0
  30. package/dist/components/atomic/Skeleton/index.d.ts +2 -0
  31. package/dist/components/atomic/Spinner/Spinner.d.ts +10 -0
  32. package/dist/components/atomic/Spinner/Spinner.js +18 -0
  33. package/dist/components/atomic/Spinner/index.d.ts +2 -0
  34. package/dist/components/atomic/Switch/Switch.d.ts +11 -0
  35. package/dist/components/atomic/Switch/Switch.js +32 -0
  36. package/dist/components/atomic/Switch/index.d.ts +2 -0
  37. package/dist/components/atomic/Text/Text.d.ts +20 -0
  38. package/dist/components/atomic/Text/Text.js +33 -0
  39. package/dist/components/atomic/Text/index.d.ts +2 -0
  40. package/dist/components/atomic/TextArea/TextArea.d.ts +14 -0
  41. package/dist/components/atomic/TextArea/TextArea.js +35 -0
  42. package/dist/components/atomic/TextArea/index.d.ts +2 -0
  43. package/dist/components/atomic/TextInput/TextInput.d.ts +18 -0
  44. package/dist/components/atomic/TextInput/TextInput.js +42 -0
  45. package/dist/components/atomic/TextInput/index.d.ts +2 -0
  46. package/dist/components/layout/FormLayout/FormLayout.d.ts +9 -0
  47. package/dist/components/layout/FormLayout/FormLayout.js +15 -0
  48. package/dist/components/layout/FormLayout/index.d.ts +2 -0
  49. package/dist/components/layout/Stack/Stack.d.ts +22 -0
  50. package/dist/components/layout/Stack/Stack.js +62 -0
  51. package/dist/components/layout/Stack/index.d.ts +2 -0
  52. package/dist/components/molecule/FormField/FormField.d.ts +16 -0
  53. package/dist/components/molecule/FormField/FormField.js +47 -0
  54. package/dist/components/molecule/FormField/index.d.ts +2 -0
  55. package/dist/components/ui/badge.js +26 -0
  56. package/dist/components/ui/button.d.ts +2 -0
  57. package/dist/components/ui/button.js +1 -1
  58. package/dist/components/ui/checkbox.js +18 -0
  59. package/dist/components/ui/field.js +65 -0
  60. package/dist/components/ui/input.js +14 -0
  61. package/dist/components/ui/label.js +12 -0
  62. package/dist/components/ui/select.js +75 -0
  63. package/dist/components/ui/separator.js +13 -0
  64. package/dist/components/ui/skeleton.js +11 -0
  65. package/dist/components/ui/spinner.js +14 -0
  66. package/dist/components/ui/switch.js +18 -0
  67. package/dist/components/ui/textarea.js +12 -0
  68. package/dist/index.d.ts +36 -3
  69. package/dist/index.js +18 -1
  70. package/dist/lib/types.d.ts +16 -1
  71. package/package.json +1 -1
  72. package/src/styles/index.css +11 -0
@@ -0,0 +1,11 @@
1
+ import { IconComponent, Tone } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export interface BadgeProps {
4
+ children: React.ReactNode;
5
+ tone?: Tone;
6
+ /** Leading icon, decorative (aria-hidden). */
7
+ icon?: IconComponent;
8
+ id?: string;
9
+ 'data-testid'?: string;
10
+ }
11
+ export declare const Badge: React.FC<BadgeProps>;
@@ -0,0 +1,31 @@
1
+ import { Badge as Badge$1 } from "../../ui/badge.js";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ // src/components/atomic/Badge/Badge.tsx
4
+ const PRIMITIVE_VARIANT = {
5
+ neutral: "secondary",
6
+ brand: "secondary",
7
+ success: "secondary",
8
+ warning: "secondary",
9
+ danger: "destructive",
10
+ info: "secondary"
11
+ };
12
+ const TONE_CLASS = {
13
+ brand: "bg-brand-tint text-brand-tint-foreground",
14
+ success: "bg-success/10 text-success dark:bg-success/20",
15
+ warning: "bg-warning/10 text-warning dark:bg-warning/20",
16
+ info: "bg-info/10 text-info dark:bg-info/20"
17
+ };
18
+ const Badge = (props) => {
19
+ const { children, tone = "neutral", icon: Icon, id, "data-testid": testId } = props;
20
+ return /* @__PURE__ */ jsxs(Badge$1, {
21
+ id,
22
+ "data-testid": testId,
23
+ variant: PRIMITIVE_VARIANT[tone],
24
+ className: TONE_CLASS[tone],
25
+ children: [Icon && /* @__PURE__ */ jsx(Icon, {
26
+ "data-icon": "inline-start",
27
+ "aria-hidden": true
28
+ }), children]
29
+ });
30
+ };
31
+ export { Badge };
@@ -0,0 +1,2 @@
1
+ import { Badge, BadgeProps } from "./Badge.js";
2
+ export { Badge, type BadgeProps };
@@ -1,6 +1,6 @@
1
1
  import { IconComponent, Size } from "../../../lib/types.js";
2
+ import { ButtonVariant } from "./buttonVariant.js";
2
3
  import React from "react";
3
- export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';
4
4
  export interface ButtonProps {
5
5
  variant?: ButtonVariant;
6
6
  size?: Size;
@@ -19,4 +19,5 @@ export interface ButtonProps {
19
19
  'aria-describedby'?: string;
20
20
  'data-testid'?: string;
21
21
  }
22
- export declare const Button: React.FC<ButtonProps>;
22
+ export declare const Button: React.FC<ButtonProps>;
23
+ export type { ButtonVariant };
@@ -1,16 +1,9 @@
1
1
  import { Button as Button$1 } from "../../ui/button.js";
2
2
  import { cn } from "../../../lib/utils.js";
3
- import { LoaderCircleIcon } from "lucide-react";
3
+ import { BUTTON_VARIANT } from "./buttonVariant.js";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
+ import { LoaderCircleIcon } from "lucide-react";
5
6
  // src/components/atomic/Button/Button.tsx
6
- const VARIANT = {
7
- primary: "default",
8
- secondary: "secondary",
9
- outline: "outline",
10
- ghost: "ghost",
11
- destructive: "destructive",
12
- link: "link"
13
- };
14
7
  const VARIANT_CLASS = { link: "text-brand-text" };
15
8
  const SIZE = {
16
9
  sm: "sm",
@@ -24,7 +17,7 @@ const Button = (props) => {
24
17
  ref,
25
18
  id,
26
19
  type,
27
- variant: VARIANT[variant],
20
+ variant: BUTTON_VARIANT[variant],
28
21
  size: SIZE[size],
29
22
  className: cn(VARIANT_CLASS[variant], fullWidth && "w-full"),
30
23
  disabled: disabled || loading,
@@ -0,0 +1,3 @@
1
+ import "../../ui/button.js";
2
+ import "react";
3
+ export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';
@@ -0,0 +1,10 @@
1
+ // src/components/atomic/Button/buttonVariant.ts
2
+ const BUTTON_VARIANT = {
3
+ primary: "default",
4
+ secondary: "secondary",
5
+ outline: "outline",
6
+ ghost: "ghost",
7
+ destructive: "destructive",
8
+ link: "link"
9
+ };
10
+ export { BUTTON_VARIANT };
@@ -1,2 +1,3 @@
1
- import { Button, ButtonProps, ButtonVariant } from "./Button.js";
1
+ import { ButtonVariant } from "./buttonVariant.js";
2
+ import { Button, ButtonProps } from "./Button.js";
2
3
  export { Button, type ButtonProps, type ButtonVariant };
@@ -0,0 +1,11 @@
1
+ import { FieldBaseProps } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export interface CheckboxProps extends FieldBaseProps {
4
+ value: boolean;
5
+ onChange: (value: boolean) => void;
6
+ onBlur?: () => void;
7
+ name?: string;
8
+ readOnly?: boolean;
9
+ ref?: React.Ref<HTMLElement>;
10
+ }
11
+ export declare const Checkbox: React.FC<CheckboxProps>;
@@ -0,0 +1,32 @@
1
+ import { FormField } from "../../molecule/FormField/FormField.js";
2
+ import { Checkbox as Checkbox$1 } from "../../ui/checkbox.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ // src/components/atomic/Checkbox/Checkbox.tsx
5
+ const Checkbox = (props) => {
6
+ const { label, hideLabel, description, error, required, disabled, id, "data-testid": testId, value, onChange, onBlur, name, readOnly = false, ref } = props;
7
+ return /* @__PURE__ */ jsx(FormField, {
8
+ orientation: "horizontal",
9
+ label,
10
+ hideLabel,
11
+ description,
12
+ error,
13
+ required,
14
+ disabled,
15
+ id,
16
+ "data-testid": testId,
17
+ children: (control) => /* @__PURE__ */ jsx(Checkbox$1, {
18
+ ref,
19
+ id: control.id,
20
+ "aria-describedby": control["aria-describedby"],
21
+ "aria-invalid": control["aria-invalid"],
22
+ "aria-required": control["aria-required"],
23
+ disabled: control.disabled,
24
+ checked: value,
25
+ onCheckedChange: (checked) => onChange(checked),
26
+ onBlur,
27
+ name,
28
+ readOnly
29
+ })
30
+ });
31
+ };
32
+ export { Checkbox };
@@ -0,0 +1,2 @@
1
+ import { Checkbox, CheckboxProps } from "./Checkbox.js";
2
+ export { Checkbox, type CheckboxProps };
@@ -0,0 +1,15 @@
1
+ import { FieldBaseProps } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export interface ColorInputProps extends FieldBaseProps {
4
+ /** 6-digit hex, e.g. '#1a73e8' (orgs.primaryColor), or the text being typed. */
5
+ value: string;
6
+ /**
7
+ * A valid 6-digit hex arrives normalized ('#1a73e8'); anything else arrives as typed, so the
8
+ * form's validation can flag it (e.g. `validate: v => /^#[0-9a-f]{6}$/.test(v) || '…'`).
9
+ */
10
+ onChange: (value: string) => void;
11
+ onBlur?: () => void;
12
+ name?: string;
13
+ ref?: React.Ref<HTMLInputElement>;
14
+ }
15
+ export declare const ColorInput: React.FC<ColorInputProps>;
@@ -0,0 +1,44 @@
1
+ import { FormField } from "../../molecule/FormField/FormField.js";
2
+ import { Input } from "../../ui/input.js";
3
+ import { normalizeHex } from "./colorHex.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ // src/components/atomic/ColorInput/ColorInput.tsx
6
+ const ColorInput = (props) => {
7
+ const { label, hideLabel, description, error, required, disabled, id, "data-testid": testId, value, onChange, onBlur, name, ref } = props;
8
+ const handleText = (next) => onChange(normalizeHex(next) ?? next);
9
+ return /* @__PURE__ */ jsx(FormField, {
10
+ label,
11
+ hideLabel,
12
+ description,
13
+ error,
14
+ required,
15
+ disabled,
16
+ id,
17
+ "data-testid": testId,
18
+ children: (control) => /* @__PURE__ */ jsxs("div", {
19
+ className: "flex items-center gap-2",
20
+ children: [/* @__PURE__ */ jsx("input", {
21
+ type: "color",
22
+ "aria-label": `${label} picker`,
23
+ value: normalizeHex(value) ?? "#000000",
24
+ disabled: control.disabled,
25
+ onChange: (event) => handleText(event.target.value),
26
+ className: "border-input h-8 w-10 shrink-0 cursor-pointer rounded-lg border bg-transparent p-0.5 disabled:cursor-not-allowed disabled:opacity-50"
27
+ }), /* @__PURE__ */ jsx(Input, {
28
+ ref,
29
+ id: control.id,
30
+ "aria-describedby": control["aria-describedby"],
31
+ "aria-invalid": control["aria-invalid"],
32
+ "aria-required": control["aria-required"],
33
+ disabled: control.disabled,
34
+ name,
35
+ value,
36
+ spellCheck: false,
37
+ autoComplete: "off",
38
+ onChange: (event) => handleText(event.target.value),
39
+ onBlur
40
+ })]
41
+ })
42
+ });
43
+ };
44
+ export { ColorInput };
@@ -0,0 +1,8 @@
1
+ // src/components/atomic/ColorInput/colorHex.ts
2
+ const HEX6 = /^#?([0-9a-f]{6})$/i;
3
+ /** '#1A73E8' | '1a73e8' → '#1a73e8'; anything that is not 6 hex digits → null. */
4
+ const normalizeHex = (input) => {
5
+ const match = HEX6.exec(input.trim());
6
+ return match ? `#${match[1].toLowerCase()}` : null;
7
+ };
8
+ export { normalizeHex };
@@ -0,0 +1,2 @@
1
+ import { ColorInput, ColorInputProps } from "./ColorInput.js";
2
+ export { ColorInput, type ColorInputProps };
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ export interface DividerProps {
3
+ /** A vertical divider stretches to its flex row's height. */
4
+ orientation?: 'horizontal' | 'vertical';
5
+ id?: string;
6
+ 'data-testid'?: string;
7
+ }
8
+ export declare const Divider: React.FC<DividerProps>;
@@ -0,0 +1,12 @@
1
+ import { Separator } from "../../ui/separator.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/components/atomic/Divider/Divider.tsx
4
+ const Divider = (props) => {
5
+ const { orientation = "horizontal", id, "data-testid": testId } = props;
6
+ return /* @__PURE__ */ jsx(Separator, {
7
+ orientation,
8
+ id,
9
+ "data-testid": testId
10
+ });
11
+ };
12
+ export { Divider };
@@ -0,0 +1,2 @@
1
+ import { Divider, DividerProps } from "./Divider.js";
2
+ export { Divider, type DividerProps };
@@ -0,0 +1,12 @@
1
+ import React from "react";
2
+ export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
3
+ export interface HeadingProps {
4
+ children: React.ReactNode;
5
+ /** Renders h1–h6; the visual size follows the level. */
6
+ level: HeadingLevel;
7
+ /** One line with an ellipsis; the parent must constrain the width. */
8
+ truncate?: boolean;
9
+ id?: string;
10
+ 'data-testid'?: string;
11
+ }
12
+ export declare const Heading: React.FC<HeadingProps>;
@@ -0,0 +1,30 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/components/atomic/Heading/Heading.tsx
4
+ const ELEMENT = {
5
+ 1: "h1",
6
+ 2: "h2",
7
+ 3: "h3",
8
+ 4: "h4",
9
+ 5: "h5",
10
+ 6: "h6"
11
+ };
12
+ const SIZE = {
13
+ 1: "text-2xl tracking-tight",
14
+ 2: "text-xl tracking-tight",
15
+ 3: "text-lg",
16
+ 4: "text-base",
17
+ 5: "text-sm",
18
+ 6: "text-xs"
19
+ };
20
+ const Heading = (props) => {
21
+ const { children, level, truncate = false, id, "data-testid": testId } = props;
22
+ const Element = ELEMENT[level];
23
+ return /* @__PURE__ */ jsx(Element, {
24
+ id,
25
+ "data-testid": testId,
26
+ className: cn("font-heading text-foreground font-semibold", SIZE[level], truncate && "truncate"),
27
+ children
28
+ });
29
+ };
30
+ export { Heading };
@@ -0,0 +1,2 @@
1
+ import { Heading, HeadingLevel, HeadingProps } from "./Heading.js";
2
+ export { Heading, type HeadingLevel, type HeadingProps };
@@ -0,0 +1,21 @@
1
+ import { ButtonVariant } from "../Button/buttonVariant.js";
2
+ import { IconComponent, Size } from "../../../lib/types.js";
3
+ import React from "react";
4
+ export type IconButtonVariant = Exclude<ButtonVariant, 'link'>;
5
+ export interface IconButtonProps {
6
+ icon: IconComponent;
7
+ /** Required: an icon-only button has no other accessible name. */
8
+ 'aria-label': string;
9
+ variant?: IconButtonVariant;
10
+ size?: Size;
11
+ /** Disables the button, sets aria-busy and swaps the icon for a spinner. */
12
+ loading?: boolean;
13
+ disabled?: boolean;
14
+ type?: 'button' | 'submit';
15
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
16
+ ref?: React.Ref<HTMLButtonElement>;
17
+ id?: string;
18
+ 'aria-describedby'?: string;
19
+ 'data-testid'?: string;
20
+ }
21
+ export declare const IconButton: React.FC<IconButtonProps>;
@@ -0,0 +1,34 @@
1
+ import { BUTTON_VARIANT } from "../Button/buttonVariant.js";
2
+ import { Button } from "../../ui/button.js";
3
+ import { cn } from "../../../lib/utils.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { LoaderCircleIcon } from "lucide-react";
6
+ // src/components/atomic/IconButton/IconButton.tsx
7
+ const SIZE = {
8
+ sm: "icon-sm",
9
+ md: "icon",
10
+ lg: "icon-lg"
11
+ };
12
+ const IconButton = (props) => {
13
+ const { icon, "aria-label": ariaLabel, variant = "ghost", size = "md", loading = false, disabled = false, type = "button", onClick, ref, id, "aria-describedby": ariaDescribedBy, "data-testid": testId } = props;
14
+ const Icon = loading ? LoaderCircleIcon : icon;
15
+ return /* @__PURE__ */ jsx(Button, {
16
+ ref,
17
+ id,
18
+ type,
19
+ variant: BUTTON_VARIANT[variant],
20
+ size: SIZE[size],
21
+ disabled: disabled || loading,
22
+ focusableWhenDisabled: loading,
23
+ "aria-busy": loading || void 0,
24
+ "aria-label": ariaLabel,
25
+ "aria-describedby": ariaDescribedBy,
26
+ "data-testid": testId,
27
+ onClick,
28
+ children: /* @__PURE__ */ jsx(Icon, {
29
+ "aria-hidden": true,
30
+ className: cn(loading && "animate-spin")
31
+ })
32
+ });
33
+ };
34
+ export { IconButton };
@@ -0,0 +1,2 @@
1
+ import { IconButton, IconButtonProps, IconButtonVariant } from "./IconButton.js";
2
+ export { IconButton, type IconButtonProps, type IconButtonVariant };
@@ -0,0 +1,18 @@
1
+ import { FieldBaseProps } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export interface SelectOption {
4
+ value: string;
5
+ label: string;
6
+ disabled?: boolean;
7
+ }
8
+ export interface SelectProps extends FieldBaseProps {
9
+ options: SelectOption[];
10
+ /** null = nothing picked; the placeholder shows. */
11
+ value: string | null;
12
+ onChange: (value: string) => void;
13
+ onBlur?: () => void;
14
+ name?: string;
15
+ placeholder?: string;
16
+ ref?: React.Ref<HTMLButtonElement>;
17
+ }
18
+ export declare const Select: React.FC<SelectProps>;
@@ -0,0 +1,47 @@
1
+ import { FormField } from "../../molecule/FormField/FormField.js";
2
+ import { Select as Select$1, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/select.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ // src/components/atomic/Select/Select.tsx
5
+ const LEFT_FIELD_REASONS = /* @__PURE__ */ new Set(["outside-press", "focus-out"]);
6
+ const Select = (props) => {
7
+ const { label, hideLabel, description, error, required, disabled, id, "data-testid": testId, options, value, onChange, onBlur, name, placeholder, ref } = props;
8
+ return /* @__PURE__ */ jsx(FormField, {
9
+ label,
10
+ hideLabel,
11
+ description,
12
+ error,
13
+ required,
14
+ disabled,
15
+ id,
16
+ "data-testid": testId,
17
+ children: (control) => /* @__PURE__ */ jsxs(Select$1, {
18
+ items: options,
19
+ value,
20
+ onValueChange: (next) => {
21
+ if (next !== null) onChange(next);
22
+ },
23
+ onOpenChange: (open, details) => {
24
+ if (!open && LEFT_FIELD_REASONS.has(details.reason)) onBlur?.();
25
+ },
26
+ name,
27
+ disabled: control.disabled,
28
+ children: [/* @__PURE__ */ jsx(SelectTrigger, {
29
+ ref,
30
+ id: control.id,
31
+ "aria-describedby": control["aria-describedby"],
32
+ "aria-invalid": control["aria-invalid"],
33
+ "aria-required": control["aria-required"],
34
+ onBlur: (event) => {
35
+ if (!event.relatedTarget?.closest("[data-slot=\"select-content\"]")) onBlur?.();
36
+ },
37
+ className: "w-full",
38
+ children: /* @__PURE__ */ jsx(SelectValue, { placeholder })
39
+ }), /* @__PURE__ */ jsx(SelectContent, { children: options.map((option) => /* @__PURE__ */ jsx(SelectItem, {
40
+ value: option.value,
41
+ disabled: option.disabled,
42
+ children: option.label
43
+ }, option.value)) })]
44
+ })
45
+ });
46
+ };
47
+ export { Select };
@@ -0,0 +1,2 @@
1
+ import { Select, SelectOption, SelectProps } from "./Select.js";
2
+ export { Select, type SelectOption, type SelectProps };
@@ -0,0 +1,8 @@
1
+ import React from "react";
2
+ export type SkeletonShape = 'text' | 'circle' | 'block';
3
+ export interface SkeletonProps {
4
+ /** Fills the wrapper's width; the app sizes it with a plain div. */
5
+ shape?: SkeletonShape;
6
+ 'data-testid'?: string;
7
+ }
8
+ export declare const Skeleton: React.FC<SkeletonProps>;
@@ -0,0 +1,17 @@
1
+ import { Skeleton as Skeleton$1 } from "../../ui/skeleton.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/components/atomic/Skeleton/Skeleton.tsx
4
+ const SHAPE = {
5
+ text: "h-4 w-full",
6
+ circle: "aspect-square w-full rounded-full",
7
+ block: "size-full"
8
+ };
9
+ const Skeleton = (props) => {
10
+ const { shape = "text", "data-testid": testId } = props;
11
+ return /* @__PURE__ */ jsx(Skeleton$1, {
12
+ "aria-hidden": true,
13
+ "data-testid": testId,
14
+ className: SHAPE[shape]
15
+ });
16
+ };
17
+ export { Skeleton };
@@ -0,0 +1,2 @@
1
+ import { Skeleton, SkeletonProps, SkeletonShape } from "./Skeleton.js";
2
+ export { Skeleton, type SkeletonProps, type SkeletonShape };
@@ -0,0 +1,10 @@
1
+ import { Size } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export interface SpinnerProps {
4
+ size?: Size;
5
+ /** Accessible name announced by screen readers. */
6
+ label?: string;
7
+ id?: string;
8
+ 'data-testid'?: string;
9
+ }
10
+ export declare const Spinner: React.FC<SpinnerProps>;
@@ -0,0 +1,18 @@
1
+ import { Spinner as Spinner$1 } from "../../ui/spinner.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/components/atomic/Spinner/Spinner.tsx
4
+ const SIZE = {
5
+ sm: "size-4",
6
+ md: "size-5",
7
+ lg: "size-8"
8
+ };
9
+ const Spinner = (props) => {
10
+ const { size = "md", label = "Loading", id, "data-testid": testId } = props;
11
+ return /* @__PURE__ */ jsx(Spinner$1, {
12
+ id,
13
+ "data-testid": testId,
14
+ "aria-label": label,
15
+ className: SIZE[size]
16
+ });
17
+ };
18
+ export { Spinner };
@@ -0,0 +1,2 @@
1
+ import { Spinner, SpinnerProps } from "./Spinner.js";
2
+ export { Spinner, type SpinnerProps };
@@ -0,0 +1,11 @@
1
+ import { FieldBaseProps } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export interface SwitchProps extends FieldBaseProps {
4
+ value: boolean;
5
+ onChange: (value: boolean) => void;
6
+ onBlur?: () => void;
7
+ name?: string;
8
+ readOnly?: boolean;
9
+ ref?: React.Ref<HTMLElement>;
10
+ }
11
+ export declare const Switch: React.FC<SwitchProps>;
@@ -0,0 +1,32 @@
1
+ import { FormField } from "../../molecule/FormField/FormField.js";
2
+ import { Switch as Switch$1 } from "../../ui/switch.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ // src/components/atomic/Switch/Switch.tsx
5
+ const Switch = (props) => {
6
+ const { label, hideLabel, description, error, required, disabled, id, "data-testid": testId, value, onChange, onBlur, name, readOnly = false, ref } = props;
7
+ return /* @__PURE__ */ jsx(FormField, {
8
+ orientation: "horizontal",
9
+ label,
10
+ hideLabel,
11
+ description,
12
+ error,
13
+ required,
14
+ disabled,
15
+ id,
16
+ "data-testid": testId,
17
+ children: (control) => /* @__PURE__ */ jsx(Switch$1, {
18
+ ref,
19
+ id: control.id,
20
+ "aria-describedby": control["aria-describedby"],
21
+ "aria-invalid": control["aria-invalid"],
22
+ "aria-required": control["aria-required"],
23
+ disabled: control.disabled,
24
+ checked: value,
25
+ onCheckedChange: (checked) => onChange(checked),
26
+ onBlur,
27
+ name,
28
+ readOnly
29
+ })
30
+ });
31
+ };
32
+ export { Switch };
@@ -0,0 +1,2 @@
1
+ import { Switch, SwitchProps } from "./Switch.js";
2
+ export { Switch, type SwitchProps };
@@ -0,0 +1,20 @@
1
+ import { Tone } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export type TextSize = 'xs' | 'sm' | 'md' | 'lg';
4
+ export type TextTone = Tone | 'muted';
5
+ export type TextWeight = 'normal' | 'medium' | 'semibold';
6
+ export interface TextProps {
7
+ children: React.ReactNode;
8
+ as?: 'p' | 'span' | 'div';
9
+ /** Leave unset to inherit the parent's size (the page default is md). */
10
+ size?: TextSize;
11
+ /** Leave unset to inherit the parent's colour. */
12
+ tone?: TextTone;
13
+ /** Leave unset to inherit the parent's weight. */
14
+ weight?: TextWeight;
15
+ /** One line with an ellipsis; the parent must constrain the width. */
16
+ truncate?: boolean;
17
+ id?: string;
18
+ 'data-testid'?: string;
19
+ }
20
+ export declare const Text: React.FC<TextProps>;
@@ -0,0 +1,33 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/components/atomic/Text/Text.tsx
4
+ const SIZE = {
5
+ xs: "text-xs",
6
+ sm: "text-sm",
7
+ md: "text-base",
8
+ lg: "text-lg"
9
+ };
10
+ const TONE = {
11
+ neutral: "text-foreground",
12
+ muted: "text-muted-foreground",
13
+ brand: "text-brand-text",
14
+ success: "text-success",
15
+ warning: "text-warning",
16
+ danger: "text-destructive",
17
+ info: "text-info"
18
+ };
19
+ const WEIGHT = {
20
+ normal: "font-normal",
21
+ medium: "font-medium",
22
+ semibold: "font-semibold"
23
+ };
24
+ const Text = (props) => {
25
+ const { children, as: Element = "p", size, tone, weight, truncate = false, id, "data-testid": testId } = props;
26
+ return /* @__PURE__ */ jsx(Element, {
27
+ id,
28
+ "data-testid": testId,
29
+ className: cn(size && SIZE[size], tone && TONE[tone], weight && WEIGHT[weight], truncate && "block truncate"),
30
+ children
31
+ });
32
+ };
33
+ export { Text };
@@ -0,0 +1,2 @@
1
+ import { Text, TextProps, TextSize, TextTone, TextWeight } from "./Text.js";
2
+ export { Text, type TextProps, type TextSize, type TextTone, type TextWeight };
@@ -0,0 +1,14 @@
1
+ import { FieldBaseProps } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export interface TextAreaProps extends FieldBaseProps {
4
+ value: string;
5
+ onChange: (value: string) => void;
6
+ onBlur?: () => void;
7
+ name?: string;
8
+ placeholder?: string;
9
+ rows?: number;
10
+ maxLength?: number;
11
+ readOnly?: boolean;
12
+ ref?: React.Ref<HTMLTextAreaElement>;
13
+ }
14
+ export declare const TextArea: React.FC<TextAreaProps>;