@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,35 @@
1
+ import { FormField } from "../../molecule/FormField/FormField.js";
2
+ import { Textarea } from "../../ui/textarea.js";
3
+ import { jsx } from "react/jsx-runtime";
4
+ // src/components/atomic/TextArea/TextArea.tsx
5
+ const TextArea = (props) => {
6
+ const { label, hideLabel, description, error, required, disabled, id, "data-testid": testId, value, onChange, onBlur, name, placeholder, rows = 3, maxLength, readOnly = false, ref } = props;
7
+ return /* @__PURE__ */ jsx(FormField, {
8
+ label,
9
+ hideLabel,
10
+ description,
11
+ error,
12
+ required,
13
+ disabled,
14
+ id,
15
+ "data-testid": testId,
16
+ children: (control) => /* @__PURE__ */ jsx(Textarea, {
17
+ ref,
18
+ id: control.id,
19
+ "aria-describedby": control["aria-describedby"],
20
+ "aria-invalid": control["aria-invalid"],
21
+ "aria-required": control["aria-required"],
22
+ disabled: control.disabled,
23
+ name,
24
+ value,
25
+ placeholder,
26
+ rows,
27
+ maxLength,
28
+ readOnly,
29
+ onChange: (event) => onChange(event.target.value),
30
+ onBlur,
31
+ className: "field-sizing-fixed"
32
+ })
33
+ });
34
+ };
35
+ export { TextArea };
@@ -0,0 +1,2 @@
1
+ import { TextArea, TextAreaProps } from "./TextArea.js";
2
+ export { TextArea, type TextAreaProps };
@@ -0,0 +1,18 @@
1
+ import { FieldBaseProps, IconComponent } from "../../../lib/types.js";
2
+ import React from "react";
3
+ export type TextInputType = 'text' | 'email' | 'password' | 'search' | 'tel' | 'url';
4
+ export interface TextInputProps extends FieldBaseProps {
5
+ value: string;
6
+ onChange: (value: string) => void;
7
+ onBlur?: () => void;
8
+ name?: string;
9
+ placeholder?: string;
10
+ type?: TextInputType;
11
+ /** Leading icon, decorative (aria-hidden). */
12
+ icon?: IconComponent;
13
+ readOnly?: boolean;
14
+ /** e.g. 'username', 'current-password' on login forms. */
15
+ autoComplete?: string;
16
+ ref?: React.Ref<HTMLInputElement>;
17
+ }
18
+ export declare const TextInput: React.FC<TextInputProps>;
@@ -0,0 +1,42 @@
1
+ import { FormField } from "../../molecule/FormField/FormField.js";
2
+ import { Input } from "../../ui/input.js";
3
+ import { cn } from "../../../lib/utils.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ // src/components/atomic/TextInput/TextInput.tsx
6
+ const TextInput = (props) => {
7
+ const { label, hideLabel, description, error, required, disabled, id, "data-testid": testId, value, onChange, onBlur, name, placeholder, type = "text", icon: Icon, readOnly = false, autoComplete, 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("div", {
18
+ className: "relative",
19
+ children: [Icon && /* @__PURE__ */ jsx(Icon, {
20
+ "aria-hidden": true,
21
+ className: "text-muted-foreground pointer-events-none absolute top-1/2 left-2.5 size-4 -translate-y-1/2"
22
+ }), /* @__PURE__ */ jsx(Input, {
23
+ ref,
24
+ id: control.id,
25
+ "aria-describedby": control["aria-describedby"],
26
+ "aria-invalid": control["aria-invalid"],
27
+ "aria-required": control["aria-required"],
28
+ disabled: control.disabled,
29
+ type,
30
+ name,
31
+ value,
32
+ placeholder,
33
+ readOnly,
34
+ autoComplete,
35
+ onChange: (event) => onChange(event.target.value),
36
+ onBlur,
37
+ className: cn(Icon && "pl-8")
38
+ })]
39
+ })
40
+ });
41
+ };
42
+ export { TextInput };
@@ -0,0 +1,2 @@
1
+ import { TextInput, TextInputProps, TextInputType } from "./TextInput.js";
2
+ export { TextInput, type TextInputProps, type TextInputType };
@@ -0,0 +1,9 @@
1
+ import React from "react";
2
+ export type FormLayoutDirection = 'vertical' | 'horizontal';
3
+ export interface FormLayoutProps {
4
+ children: React.ReactNode;
5
+ /** horizontal: fields side by side in equal columns from sm up, stacked on phones. */
6
+ direction?: FormLayoutDirection;
7
+ 'data-testid'?: string;
8
+ }
9
+ export declare const FormLayout: React.FC<FormLayoutProps>;
@@ -0,0 +1,15 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ // src/components/layout/FormLayout/FormLayout.tsx
3
+ const DIRECTION = {
4
+ vertical: "flex flex-col gap-5",
5
+ horizontal: "grid gap-5 sm:auto-cols-fr sm:grid-flow-col"
6
+ };
7
+ const FormLayout = (props) => {
8
+ const { children, direction = "vertical", "data-testid": testId } = props;
9
+ return /* @__PURE__ */ jsx("div", {
10
+ "data-testid": testId,
11
+ className: DIRECTION[direction],
12
+ children
13
+ });
14
+ };
15
+ export { FormLayout };
@@ -0,0 +1,2 @@
1
+ import { FormLayout, FormLayoutDirection, FormLayoutProps } from "./FormLayout.js";
2
+ export { FormLayout, type FormLayoutDirection, type FormLayoutProps };
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ export type StackGap = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 8;
3
+ export type StackAlign = 'start' | 'center' | 'end' | 'stretch' | 'baseline';
4
+ export type StackJustify = 'start' | 'center' | 'end' | 'between';
5
+ export interface StackProps {
6
+ children: React.ReactNode;
7
+ direction?: 'row' | 'column';
8
+ /** Tailwind spacing step (1 = 4px). */
9
+ gap?: StackGap;
10
+ /** Cross axis. */
11
+ align?: StackAlign;
12
+ /** Main axis. */
13
+ justify?: StackJustify;
14
+ wrap?: boolean;
15
+ id?: string;
16
+ 'data-testid'?: string;
17
+ }
18
+ export type HStackProps = Omit<StackProps, 'direction'>;
19
+ export type VStackProps = Omit<StackProps, 'direction'>;
20
+ export declare const Stack: React.FC<StackProps>;
21
+ export declare const HStack: React.FC<HStackProps>;
22
+ export declare const VStack: React.FC<VStackProps>;
@@ -0,0 +1,62 @@
1
+ import { cn } from "../../../lib/utils.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/components/layout/Stack/Stack.tsx
4
+ const GAP = {
5
+ 0: "gap-0",
6
+ 1: "gap-1",
7
+ 2: "gap-2",
8
+ 3: "gap-3",
9
+ 4: "gap-4",
10
+ 5: "gap-5",
11
+ 6: "gap-6",
12
+ 8: "gap-8"
13
+ };
14
+ const ALIGN = {
15
+ start: "items-start",
16
+ center: "items-center",
17
+ end: "items-end",
18
+ stretch: "items-stretch",
19
+ baseline: "items-baseline"
20
+ };
21
+ const JUSTIFY = {
22
+ start: "justify-start",
23
+ center: "justify-center",
24
+ end: "justify-end",
25
+ between: "justify-between"
26
+ };
27
+ const Stack = (props) => {
28
+ const { children, direction = "column", gap = 0, align, justify, wrap = false, id, "data-testid": testId } = props;
29
+ return /* @__PURE__ */ jsx("div", {
30
+ id,
31
+ "data-testid": testId,
32
+ className: cn("flex", direction === "row" ? "flex-row" : "flex-col", GAP[gap], align && ALIGN[align], justify && JUSTIFY[justify], wrap && "flex-wrap"),
33
+ children
34
+ });
35
+ };
36
+ const HStack = (props) => {
37
+ const { children, gap, align, justify, wrap, id, "data-testid": testId } = props;
38
+ return /* @__PURE__ */ jsx(Stack, {
39
+ direction: "row",
40
+ gap,
41
+ align,
42
+ justify,
43
+ wrap,
44
+ id,
45
+ "data-testid": testId,
46
+ children
47
+ });
48
+ };
49
+ const VStack = (props) => {
50
+ const { children, gap, align, justify, wrap, id, "data-testid": testId } = props;
51
+ return /* @__PURE__ */ jsx(Stack, {
52
+ direction: "column",
53
+ gap,
54
+ align,
55
+ justify,
56
+ wrap,
57
+ id,
58
+ "data-testid": testId,
59
+ children
60
+ });
61
+ };
62
+ export { HStack, Stack, VStack };
@@ -0,0 +1,2 @@
1
+ import { HStack, HStackProps, Stack, StackAlign, StackGap, StackJustify, StackProps, VStack, VStackProps } from "./Stack.js";
2
+ export { HStack, type HStackProps, Stack, type StackAlign, type StackGap, type StackJustify, type StackProps, VStack, type VStackProps };
@@ -0,0 +1,16 @@
1
+ import { FieldBaseProps } from "../../../lib/types.js";
2
+ import React from "react";
3
+ /** Wiring FormField hands to its control; pass each prop by name. */
4
+ export interface FormFieldControlProps {
5
+ id: string;
6
+ 'aria-describedby'?: string;
7
+ 'aria-invalid'?: true;
8
+ 'aria-required'?: true;
9
+ disabled?: boolean;
10
+ }
11
+ export interface FormFieldProps extends FieldBaseProps {
12
+ children: (control: FormFieldControlProps) => React.ReactNode;
13
+ /** horizontal puts the label beside the control (checkbox, switch). */
14
+ orientation?: 'vertical' | 'horizontal';
15
+ }
16
+ export declare const FormField: React.FC<FormFieldProps>;
@@ -0,0 +1,47 @@
1
+ import { Field, FieldContent, FieldDescription, FieldError, FieldLabel } from "../../ui/field.js";
2
+ import { cn } from "../../../lib/utils.js";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ import { useId } from "react";
5
+ // src/components/molecule/FormField/FormField.tsx
6
+ const FormField = (props) => {
7
+ const { children, label, hideLabel = false, description, error, required = false, disabled = false, orientation = "vertical", id: idProp, "data-testid": testId } = props;
8
+ const generatedId = useId();
9
+ const id = idProp ?? generatedId;
10
+ const descriptionId = description ? `${id}-description` : void 0;
11
+ const errorId = error ? `${id}-error` : void 0;
12
+ const control = children({
13
+ id,
14
+ "aria-describedby": [descriptionId, errorId].filter(Boolean).join(" ") || void 0,
15
+ "aria-invalid": error ? true : void 0,
16
+ "aria-required": required ? true : void 0,
17
+ disabled
18
+ });
19
+ const labelNode = /* @__PURE__ */ jsxs(FieldLabel, {
20
+ htmlFor: id,
21
+ className: cn(hideLabel && "sr-only"),
22
+ children: [label, required && /* @__PURE__ */ jsx("span", {
23
+ "aria-hidden": true,
24
+ className: "text-destructive",
25
+ children: "*"
26
+ })]
27
+ });
28
+ const helpNodes = /* @__PURE__ */ jsxs(Fragment, { children: [description && /* @__PURE__ */ jsx(FieldDescription, {
29
+ id: descriptionId,
30
+ children: description
31
+ }), error && /* @__PURE__ */ jsx(FieldError, {
32
+ id: errorId,
33
+ children: error
34
+ })] });
35
+ return /* @__PURE__ */ jsx(Field, {
36
+ orientation,
37
+ "data-invalid": error ? true : void 0,
38
+ "data-disabled": disabled || void 0,
39
+ "data-testid": testId,
40
+ children: orientation === "horizontal" ? /* @__PURE__ */ jsxs(Fragment, { children: [control, /* @__PURE__ */ jsxs(FieldContent, { children: [labelNode, helpNodes] })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
41
+ labelNode,
42
+ control,
43
+ helpNodes
44
+ ] })
45
+ });
46
+ };
47
+ export { FormField };
@@ -0,0 +1,2 @@
1
+ import { FormField, FormFieldControlProps, FormFieldProps } from "./FormField.js";
2
+ export { FormField, type FormFieldControlProps, type FormFieldProps };
@@ -0,0 +1,26 @@
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cva } from "class-variance-authority";
4
+ import { cn } from "cn";
5
+ // src/components/ui/badge.tsx
6
+ const badgeVariants = cva("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-4xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-all focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
7
+ variants: { variant: {
8
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
9
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
10
+ destructive: "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
11
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
12
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
13
+ link: "text-primary underline-offset-4 hover:underline"
14
+ } },
15
+ defaultVariants: { variant: "default" }
16
+ });
17
+ const Badge = ({ className, variant = "default", render, ...props }) => useRender({
18
+ defaultTagName: "span",
19
+ props: mergeProps({ className: cn(badgeVariants({ variant }), className) }, props),
20
+ render,
21
+ state: {
22
+ slot: "badge",
23
+ variant
24
+ }
25
+ });
26
+ export { Badge, badgeVariants };
@@ -0,0 +1,2 @@
1
+ import "class-variance-authority";
2
+ import "@base-ui/react/button";
@@ -1,7 +1,7 @@
1
- import { Button } from "@base-ui/react/button";
2
1
  import { cva } from "class-variance-authority";
3
2
  import { cn } from "cn";
4
3
  import { jsx } from "react/jsx-runtime";
4
+ import { Button } from "@base-ui/react/button";
5
5
  // src/components/ui/button.tsx
6
6
  const buttonVariants = cva("group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", {
7
7
  variants: {
@@ -0,0 +1,18 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { CheckIcon } from "lucide-react";
4
+ import { Checkbox } from "@base-ui/react/checkbox";
5
+ // src/components/ui/checkbox.tsx
6
+ const Checkbox$1 = ({ className, ...props }) => {
7
+ return /* @__PURE__ */ jsx(Checkbox.Root, {
8
+ "data-slot": "checkbox",
9
+ className: cn("peer border-input group-has-[:focus-visible]/field-label:not-data-checked:border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground group-has-[:focus-visible]/field-label:data-checked:border-primary dark:data-checked:bg-primary relative flex size-4 shrink-0 items-center justify-center rounded-[4px] border transition-colors outline-none group-has-disabled/field:opacity-50 group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3", className),
10
+ ...props,
11
+ children: /* @__PURE__ */ jsx(Checkbox.Indicator, {
12
+ "data-slot": "checkbox-indicator",
13
+ className: "grid place-content-center text-current transition-none [&>svg]:size-3.5",
14
+ children: /* @__PURE__ */ jsx(CheckIcon, {})
15
+ })
16
+ });
17
+ };
18
+ export { Checkbox$1 as Checkbox };
@@ -0,0 +1,65 @@
1
+ import { Label } from "./label.js";
2
+ import { cva } from "class-variance-authority";
3
+ import { cn } from "cn";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { useMemo } from "react";
6
+ // src/components/ui/field.tsx
7
+ const fieldVariants = cva("group/field flex w-full gap-2 data-[invalid=true]:text-destructive", {
8
+ variants: { orientation: {
9
+ vertical: "flex-col *:w-full [&>.sr-only]:w-auto",
10
+ horizontal: "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
11
+ responsive: "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px"
12
+ } },
13
+ defaultVariants: { orientation: "vertical" }
14
+ });
15
+ const Field = ({ className, orientation = "vertical", ...props }) => {
16
+ return /* @__PURE__ */ jsx("div", {
17
+ role: "group",
18
+ "data-slot": "field",
19
+ "data-orientation": orientation,
20
+ className: cn(fieldVariants({ orientation }), className),
21
+ ...props
22
+ });
23
+ };
24
+ const FieldContent = ({ className, ...props }) => {
25
+ return /* @__PURE__ */ jsx("div", {
26
+ "data-slot": "field-content",
27
+ className: cn("group/field-content flex flex-1 flex-col gap-0.5 leading-snug", className),
28
+ ...props
29
+ });
30
+ };
31
+ const FieldLabel = ({ className, ...props }) => {
32
+ return /* @__PURE__ */ jsx(Label, {
33
+ "data-slot": "field-label",
34
+ className: cn("group/field-label peer/field-label has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:not-has-[:disabled,[data-disabled]]:hover:bg-muted/50 has-[>[data-slot=field]]:has-[:focus-visible]:border-ring has-[>[data-slot=field]]:has-[:focus-visible]:ring-ring/50 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10 flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border has-[>[data-slot=field]]:has-[:focus-visible]:ring-3 *:data-[slot=field]:p-2.5", "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col", className),
35
+ ...props
36
+ });
37
+ };
38
+ const FieldDescription = ({ className, ...props }) => {
39
+ return /* @__PURE__ */ jsx("p", {
40
+ "data-slot": "field-description",
41
+ className: cn("text-muted-foreground text-left text-sm leading-normal font-normal group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5", "last:mt-0 nth-last-2:-mt-1", "[&>a:hover]:text-primary [&>a]:underline [&>a]:underline-offset-4", className),
42
+ ...props
43
+ });
44
+ };
45
+ const FieldError = ({ className, children, errors, ...props }) => {
46
+ const content = useMemo(() => {
47
+ if (children) return children;
48
+ if (!errors?.length) return null;
49
+ const uniqueErrors = [...new Map(errors.map((error) => [error?.message, error])).values()];
50
+ if (uniqueErrors?.length == 1) return uniqueErrors[0]?.message;
51
+ return /* @__PURE__ */ jsx("ul", {
52
+ className: "ml-4 flex list-disc flex-col gap-1",
53
+ children: uniqueErrors.map((error, index) => error?.message && /* @__PURE__ */ jsx("li", { children: error.message }, index))
54
+ });
55
+ }, [children, errors]);
56
+ if (!content) return null;
57
+ return /* @__PURE__ */ jsx("div", {
58
+ role: "alert",
59
+ "data-slot": "field-error",
60
+ className: cn("text-destructive text-sm font-normal", className),
61
+ ...props,
62
+ children: content
63
+ });
64
+ };
65
+ export { Field, FieldContent, FieldDescription, FieldError, FieldLabel };
@@ -0,0 +1,14 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import "react";
4
+ import { Input } from "@base-ui/react/input";
5
+ // src/components/ui/input.tsx
6
+ const Input$1 = ({ className, type, ...props }) => {
7
+ return /* @__PURE__ */ jsx(Input, {
8
+ type,
9
+ "data-slot": "input",
10
+ className: cn("border-input file:text-foreground placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 disabled:bg-input/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 h-8 w-full min-w-0 rounded-lg border bg-transparent px-2.5 py-1 text-base transition-colors outline-none file:inline-flex file:h-6 file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm", className),
11
+ ...props
12
+ });
13
+ };
14
+ export { Input$1 as Input };
@@ -0,0 +1,12 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import "react";
4
+ // src/components/ui/label.tsx
5
+ const Label = ({ className, ...props }) => {
6
+ return /* @__PURE__ */ jsx("label", {
7
+ "data-slot": "label",
8
+ className: cn("flex items-center gap-2 text-sm leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50", className),
9
+ ...props
10
+ });
11
+ };
12
+ export { Label };
@@ -0,0 +1,75 @@
1
+ import { cn } from "cn";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react";
4
+ import "react";
5
+ import { Select } from "@base-ui/react/select";
6
+ // src/components/ui/select.tsx
7
+ const Select$1 = Select.Root;
8
+ const SelectValue = ({ className, ...props }) => {
9
+ return /* @__PURE__ */ jsx(Select.Value, {
10
+ "data-slot": "select-value",
11
+ className: cn("flex flex-1 text-left", className),
12
+ ...props
13
+ });
14
+ };
15
+ const SelectTrigger = ({ className, size = "default", children, ...props }) => {
16
+ return /* @__PURE__ */ jsxs(Select.Trigger, {
17
+ "data-slot": "select-trigger",
18
+ "data-size": size,
19
+ className: cn("border-input focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 flex w-fit items-center justify-between gap-1.5 rounded-lg border bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap transition-colors outline-none select-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 data-[size=default]:h-8 data-[size=sm]:h-7 data-[size=sm]:rounded-[min(var(--radius-md),10px)] *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", className),
20
+ ...props,
21
+ children: [children, /* @__PURE__ */ jsx(Select.Icon, { render: /* @__PURE__ */ jsx(ChevronDownIcon, { className: "text-muted-foreground pointer-events-none size-4" }) })]
22
+ });
23
+ };
24
+ const SelectContent = ({ className, children, side = "bottom", sideOffset = 4, align = "center", alignOffset = 0, alignItemWithTrigger = true, ...props }) => {
25
+ return /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, {
26
+ side,
27
+ sideOffset,
28
+ align,
29
+ alignOffset,
30
+ alignItemWithTrigger,
31
+ className: "isolate z-50",
32
+ children: /* @__PURE__ */ jsxs(Select.Popup, {
33
+ "data-slot": "select-content",
34
+ "data-align-trigger": alignItemWithTrigger,
35
+ className: cn("bg-popover text-popover-foreground ring-foreground/10 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95 relative isolate z-50 max-h-(--available-height) w-(--anchor-width) min-w-36 origin-(--transform-origin) overflow-x-hidden overflow-y-auto rounded-lg shadow-md ring-1 duration-100 data-[align-trigger=true]:animate-none", className),
36
+ ...props,
37
+ children: [
38
+ /* @__PURE__ */ jsx(SelectScrollUpButton, {}),
39
+ /* @__PURE__ */ jsx(Select.List, { children }),
40
+ /* @__PURE__ */ jsx(SelectScrollDownButton, {})
41
+ ]
42
+ })
43
+ }) });
44
+ };
45
+ const SelectItem = ({ className, children, ...props }) => {
46
+ return /* @__PURE__ */ jsxs(Select.Item, {
47
+ "data-slot": "select-item",
48
+ className: cn("focus:bg-accent focus:text-accent-foreground not-data-[variant=destructive]:focus:**:text-accent-foreground relative flex w-full cursor-default items-center gap-1.5 rounded-md py-1 pr-8 pl-1.5 text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2", className),
49
+ ...props,
50
+ children: [/* @__PURE__ */ jsx(Select.ItemText, {
51
+ className: "flex flex-1 shrink-0 gap-2 whitespace-nowrap",
52
+ children
53
+ }), /* @__PURE__ */ jsx(Select.ItemIndicator, {
54
+ render: /* @__PURE__ */ jsx("span", { className: "pointer-events-none absolute right-2 flex size-4 items-center justify-center" }),
55
+ children: /* @__PURE__ */ jsx(CheckIcon, { className: "pointer-events-none" })
56
+ })]
57
+ });
58
+ };
59
+ const SelectScrollUpButton = ({ className, ...props }) => {
60
+ return /* @__PURE__ */ jsx(Select.ScrollUpArrow, {
61
+ "data-slot": "select-scroll-up-button",
62
+ className: cn("bg-popover top-0 z-10 flex w-full cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4", className),
63
+ ...props,
64
+ children: /* @__PURE__ */ jsx(ChevronUpIcon, {})
65
+ });
66
+ };
67
+ const SelectScrollDownButton = ({ className, ...props }) => {
68
+ return /* @__PURE__ */ jsx(Select.ScrollDownArrow, {
69
+ "data-slot": "select-scroll-down-button",
70
+ className: cn("bg-popover bottom-0 z-10 flex w-full cursor-default items-center justify-center py-1 [&_svg:not([class*='size-'])]:size-4", className),
71
+ ...props,
72
+ children: /* @__PURE__ */ jsx(ChevronDownIcon, {})
73
+ });
74
+ };
75
+ export { Select$1 as Select, SelectContent, SelectItem, SelectScrollDownButton, SelectScrollUpButton, SelectTrigger, SelectValue };
@@ -0,0 +1,13 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Separator } from "@base-ui/react/separator";
4
+ // src/components/ui/separator.tsx
5
+ const Separator$1 = ({ className, orientation = "horizontal", ...props }) => {
6
+ return /* @__PURE__ */ jsx(Separator, {
7
+ "data-slot": "separator",
8
+ orientation,
9
+ className: cn("bg-border shrink-0 data-horizontal:h-px data-horizontal:w-full data-vertical:w-px data-vertical:self-stretch", className),
10
+ ...props
11
+ });
12
+ };
13
+ export { Separator$1 as Separator };
@@ -0,0 +1,11 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ // src/components/ui/skeleton.tsx
4
+ const Skeleton = ({ className, ...props }) => {
5
+ return /* @__PURE__ */ jsx("div", {
6
+ "data-slot": "skeleton",
7
+ className: cn("bg-muted animate-pulse rounded-md", className),
8
+ ...props
9
+ });
10
+ };
11
+ export { Skeleton };
@@ -0,0 +1,14 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { Loader2Icon } from "lucide-react";
4
+ // src/components/ui/spinner.tsx
5
+ const Spinner = ({ className, ...props }) => {
6
+ return /* @__PURE__ */ jsx(Loader2Icon, {
7
+ "data-slot": "spinner",
8
+ role: "status",
9
+ "aria-label": "Loading",
10
+ className: cn("size-4 animate-spin", className),
11
+ ...props
12
+ });
13
+ };
14
+ export { Spinner };
@@ -0,0 +1,18 @@
1
+ "use client";
2
+ import { cn } from "cn";
3
+ import { jsx } from "react/jsx-runtime";
4
+ import { Switch } from "@base-ui/react/switch";
5
+ // src/components/ui/switch.tsx
6
+ const Switch$1 = ({ className, size = "default", ...props }) => {
7
+ return /* @__PURE__ */ jsx(Switch.Root, {
8
+ "data-slot": "switch",
9
+ "data-size": size,
10
+ className: cn("peer group/switch focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:bg-primary data-unchecked:bg-input dark:data-unchecked:bg-input/80 relative inline-flex shrink-0 items-center rounded-full border border-transparent transition-all outline-none group-has-[:focus-visible]/field-label:border-transparent group-has-[:focus-visible]/field-label:ring-0 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:ring-3 aria-invalid:ring-3 data-disabled:cursor-not-allowed data-disabled:opacity-50 data-[size=default]:h-[18.4px] data-[size=default]:w-[32px] data-[size=sm]:h-[14px] data-[size=sm]:w-[24px]", className),
11
+ ...props,
12
+ children: /* @__PURE__ */ jsx(Switch.Thumb, {
13
+ "data-slot": "switch-thumb",
14
+ className: "bg-background dark:data-checked:bg-primary-foreground dark:data-unchecked:bg-foreground pointer-events-none block rounded-full ring-0 transition-transform group-data-[size=default]/switch:size-4 group-data-[size=sm]/switch:size-3 group-data-[size=default]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=sm]/switch:data-checked:translate-x-[calc(100%-2px)] group-data-[size=default]/switch:data-unchecked:translate-x-0 group-data-[size=sm]/switch:data-unchecked:translate-x-0"
15
+ })
16
+ });
17
+ };
18
+ export { Switch$1 as Switch };
@@ -0,0 +1,12 @@
1
+ import { cn } from "cn";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import "react";
4
+ // src/components/ui/textarea.tsx
5
+ const Textarea = ({ className, ...props }) => {
6
+ return /* @__PURE__ */ jsx("textarea", {
7
+ "data-slot": "textarea",
8
+ className: cn("border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 disabled:bg-input/50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:bg-input/30 dark:disabled:bg-input/80 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 flex field-sizing-content min-h-16 w-full rounded-lg border bg-transparent px-2.5 py-2 text-base transition-colors outline-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 md:text-sm", className),
9
+ ...props
10
+ });
11
+ };
12
+ export { Textarea };