@boxcustodia/library 2.0.0-alpha.12 → 2.0.0-alpha.14

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 (174) hide show
  1. package/dist/index.cjs.js +1 -138
  2. package/dist/index.d.ts +1087 -720
  3. package/dist/index.es.js +7011 -56097
  4. package/dist/theme.css +1 -1
  5. package/package.json +34 -26
  6. package/src/__doc__/Examples.tsx +1 -1
  7. package/src/__doc__/Intro.mdx +3 -3
  8. package/src/__doc__/Tabs.mdx +112 -0
  9. package/src/__doc__/V2.mdx +1246 -0
  10. package/src/components/accordion/accordion.stories.tsx +143 -0
  11. package/src/components/accordion/accordion.tsx +135 -0
  12. package/src/components/accordion/index.ts +1 -0
  13. package/src/components/alert/alert.stories.tsx +24 -4
  14. package/src/components/alert/alert.tsx +17 -9
  15. package/src/components/alert-dialog/alert-dialog.stories.tsx +24 -0
  16. package/src/components/alert-dialog/alert-dialog.test.tsx +1 -1
  17. package/src/components/alert-dialog/alert-dialog.tsx +58 -10
  18. package/src/components/auto-complete/auto-complete.stories.tsx +616 -200
  19. package/src/components/auto-complete/auto-complete.tsx +420 -68
  20. package/src/components/auto-complete/index.ts +0 -1
  21. package/src/components/avatar/avatar.stories.tsx +162 -21
  22. package/src/components/avatar/avatar.tsx +79 -20
  23. package/src/components/button/button.stories.tsx +219 -294
  24. package/src/components/button/button.test.tsx +10 -17
  25. package/src/components/button/button.tsx +78 -19
  26. package/src/components/button/components/base-button.tsx +30 -53
  27. package/src/components/button/index.ts +0 -1
  28. package/src/components/calendar/calendar.stories.tsx +1 -1
  29. package/src/components/calendar/calendar.tsx +4 -4
  30. package/src/components/card/card.stories.tsx +141 -69
  31. package/src/components/card/card.tsx +155 -54
  32. package/src/components/center/center.stories.tsx +22 -39
  33. package/src/components/checkbox/checkbox.stories.tsx +25 -5
  34. package/src/components/checkbox/checkbox.tsx +76 -15
  35. package/src/components/checkbox-group/checkbox-group.stories.tsx +116 -28
  36. package/src/components/checkbox-group/checkbox-group.tsx +84 -3
  37. package/src/components/combobox/combobox.stories.tsx +33 -23
  38. package/src/components/combobox/combobox.tsx +99 -77
  39. package/src/components/date-picker/date-input.stories.tsx +14 -6
  40. package/src/components/date-picker/date-input.tsx +2 -2
  41. package/src/components/date-picker/date-picker.model.ts +13 -4
  42. package/src/components/date-picker/date-picker.stories.tsx +38 -12
  43. package/src/components/date-picker/date-picker.tsx +28 -14
  44. package/src/components/dialog/dialog.stories.tsx +18 -0
  45. package/src/components/dialog/dialog.test.tsx +1 -1
  46. package/src/components/dialog/dialog.tsx +51 -20
  47. package/src/components/divider/divider.stories.tsx +126 -51
  48. package/src/components/divider/divider.tsx +16 -16
  49. package/src/components/dropzone/dropzone.stories.tsx +71 -90
  50. package/src/components/dropzone/dropzone.tsx +383 -105
  51. package/src/components/dropzone/index.ts +0 -1
  52. package/src/components/empty/empty.stories.tsx +165 -0
  53. package/src/components/empty/empty.tsx +156 -0
  54. package/src/components/empty/index.ts +1 -0
  55. package/src/components/field/field.stories.tsx +227 -4
  56. package/src/components/field/field.tsx +77 -42
  57. package/src/components/form/form.stories.tsx +320 -197
  58. package/src/components/form/form.tsx +3 -23
  59. package/src/components/index.ts +2 -6
  60. package/src/components/input/input.stories.tsx +5 -5
  61. package/src/components/input/input.tsx +4 -4
  62. package/src/components/kbd/kbd.stories.tsx +1 -0
  63. package/src/components/label/label.stories.tsx +16 -0
  64. package/src/components/label/label.tsx +13 -2
  65. package/src/components/loader/loader.stories.tsx +7 -5
  66. package/src/components/loader/loader.tsx +8 -3
  67. package/src/components/menu/menu-primitives.tsx +207 -196
  68. package/src/components/menu/menu.stories.tsx +276 -146
  69. package/src/components/menu/menu.tsx +146 -54
  70. package/src/components/number-input/number-input.stories.tsx +27 -4
  71. package/src/components/number-input/number-input.test.tsx +2 -2
  72. package/src/components/number-input/number-input.tsx +31 -33
  73. package/src/components/otp/index.ts +1 -0
  74. package/src/components/otp/otp.stories.tsx +209 -0
  75. package/src/components/otp/otp.tsx +100 -0
  76. package/src/components/pagination/index.ts +1 -0
  77. package/src/components/pagination/pagination.model.ts +2 -0
  78. package/src/components/pagination/pagination.stories.tsx +154 -59
  79. package/src/components/pagination/pagination.test.tsx +122 -57
  80. package/src/components/pagination/pagination.tsx +575 -77
  81. package/src/components/password/password.stories.tsx +18 -3
  82. package/src/components/password/password.tsx +29 -9
  83. package/src/components/popover/popover.stories.tsx +26 -5
  84. package/src/components/popover/popover.tsx +15 -23
  85. package/src/components/progress/progress.stories.tsx +1 -0
  86. package/src/components/radio-group/index.ts +1 -0
  87. package/src/components/radio-group/radio-group.stories.tsx +251 -0
  88. package/src/components/radio-group/radio-group.tsx +212 -0
  89. package/src/components/scroll-area/scroll-area.stories.tsx +1 -0
  90. package/src/components/select/select.stories.tsx +118 -19
  91. package/src/components/select/select.tsx +67 -62
  92. package/src/components/skeleton/skeleton.stories.tsx +1 -0
  93. package/src/components/stack/stack.stories.tsx +179 -89
  94. package/src/components/stack/stack.tsx +2 -2
  95. package/src/components/stepper/index.ts +1 -1
  96. package/src/components/stepper/stepper.stories.tsx +767 -83
  97. package/src/components/stepper/stepper.test.tsx +18 -18
  98. package/src/components/stepper/stepper.tsx +554 -0
  99. package/src/components/switch/switch.stories.tsx +15 -1
  100. package/src/components/switch/switch.tsx +17 -4
  101. package/src/components/table/index.ts +0 -2
  102. package/src/components/table/table.stories.tsx +131 -18
  103. package/src/components/table/table.test.tsx +1 -1
  104. package/src/components/table/table.tsx +183 -77
  105. package/src/components/tabs/tabs.stories.tsx +373 -155
  106. package/src/components/tabs/tabs.test.tsx +12 -12
  107. package/src/components/tabs/tabs.tsx +72 -149
  108. package/src/components/tag/index.ts +0 -1
  109. package/src/components/tag/tag.stories.tsx +155 -120
  110. package/src/components/tag/tag.tsx +47 -95
  111. package/src/components/textarea/textarea.stories.tsx +8 -22
  112. package/src/components/textarea/textarea.tsx +17 -79
  113. package/src/components/timeline/timeline.stories.tsx +323 -42
  114. package/src/components/timeline/timeline.tsx +359 -132
  115. package/src/components/toast/toast.stories.tsx +1 -0
  116. package/src/components/tooltip/tooltip.tsx +11 -9
  117. package/src/components/tree/index.ts +0 -1
  118. package/src/components/tree/tree.stories.tsx +365 -408
  119. package/src/components/tree/tree.test.tsx +163 -0
  120. package/src/components/tree/tree.tsx +212 -36
  121. package/src/hooks/useAsync/__doc__/useAsync.stories.tsx +5 -5
  122. package/src/hooks/useClipboard/__doc__/useClipboard.stories.tsx +1 -3
  123. package/src/hooks/useDebounceCallback/__doc__/useDebouncedCallback.stories.tsx +6 -6
  124. package/src/hooks/useDocumentTitle/__doc__/useDocumentTitle.stories.tsx +1 -1
  125. package/src/hooks/useEventListener/__test__/useEventListener.test.tsx +1 -1
  126. package/src/hooks/useLocalStorage/__doc__/useLocalStorage.stories.tsx +1 -1
  127. package/src/hooks/usePagination/usePagination.tsx +36 -24
  128. package/src/styles/theme.css +1 -1
  129. package/src/utils/form.tsx +67 -37
  130. package/src/utils/index.ts +1 -1
  131. package/src/__doc__/Migration.mdx +0 -475
  132. package/src/components/auto-complete/auto-complete-primitives.tsx +0 -155
  133. package/src/components/background-image/background-image.stories.tsx +0 -21
  134. package/src/components/background-image/background-image.test.tsx +0 -29
  135. package/src/components/background-image/background-image.tsx +0 -23
  136. package/src/components/background-image/index.ts +0 -1
  137. package/src/components/button/button.variants.ts +0 -44
  138. package/src/components/button/components/loader-overlay.tsx +0 -21
  139. package/src/components/button/components/loading-icon.tsx +0 -47
  140. package/src/components/dropzone/upload-primitives.tsx +0 -310
  141. package/src/components/dropzone/use-dropzone.ts +0 -122
  142. package/src/components/empty-state/empty-state.stories.tsx +0 -56
  143. package/src/components/empty-state/empty-state.tsx +0 -39
  144. package/src/components/empty-state/index.ts +0 -1
  145. package/src/components/heading/heading.stories.tsx +0 -74
  146. package/src/components/heading/heading.tsx +0 -28
  147. package/src/components/heading/heading.variants.ts +0 -27
  148. package/src/components/heading/index.ts +0 -1
  149. package/src/components/kbd/kbd.variants.ts +0 -26
  150. package/src/components/menu/util/render-menu-item.tsx +0 -54
  151. package/src/components/multi-select/hooks/use-multi-select.ts +0 -66
  152. package/src/components/multi-select/index.ts +0 -1
  153. package/src/components/multi-select/multi-select.stories.tsx +0 -294
  154. package/src/components/multi-select/multi-select.tsx +0 -300
  155. package/src/components/multi-select/multi-select.variants.ts +0 -22
  156. package/src/components/pagination/components/pagination-option.tsx +0 -27
  157. package/src/components/show/index.ts +0 -1
  158. package/src/components/show/show.stories.tsx +0 -197
  159. package/src/components/show/show.test.tsx +0 -41
  160. package/src/components/show/show.tsx +0 -16
  161. package/src/components/stepper/Stepper.tsx +0 -190
  162. package/src/components/stepper/context/stepper-context.tsx +0 -11
  163. package/src/components/table/table-primitives.tsx +0 -122
  164. package/src/components/table/table.model.ts +0 -20
  165. package/src/components/table-pagination/index.ts +0 -2
  166. package/src/components/table-pagination/table-pagination.model.ts +0 -2
  167. package/src/components/table-pagination/table-pagination.stories.tsx +0 -23
  168. package/src/components/table-pagination/table-pagination.test.tsx +0 -32
  169. package/src/components/table-pagination/table-pagination.tsx +0 -108
  170. package/src/components/tabs/context/tabs-context.tsx +0 -14
  171. package/src/components/tag/tag.variants.ts +0 -31
  172. package/src/components/timeline/timeline-status.ts +0 -5
  173. package/src/components/tree/hooks/use-controllable-tree-state.ts +0 -80
  174. package/src/components/tree/tree-primitives.tsx +0 -126
@@ -1,99 +1,51 @@
1
- import { X } from "lucide-react";
1
+ import { mergeProps } from "@base-ui/react/merge-props";
2
+ import { useRender } from "@base-ui/react/use-render";
3
+ import { cva, type VariantProps } from "class-variance-authority";
2
4
  import { cn } from "../../lib";
3
- import { TagVariant, tagVariants } from "./tag.variants";
4
5
 
5
- type VariantProps = {
6
- color?: never;
7
- variant?: TagVariant["variant"];
8
- };
9
- type ColorProps = {
10
- color: string;
11
- variant?: "outline" | "borderless";
12
- };
13
- type StyleProps = ColorProps | VariantProps;
14
-
15
- type BaseProps = {
16
- icon?: React.ReactNode;
17
- rounded?: TagVariant["rounded"];
18
- } & StyleProps &
19
- React.HTMLAttributes<HTMLDivElement>;
20
-
21
- type ClosableProps = BaseProps & {
22
- closable: true;
23
- onClose: () => void;
24
- };
25
-
26
- type NonClosableProps = BaseProps & {
27
- closable?: false;
28
- onClose?: never;
29
- };
30
-
31
- type Props = ClosableProps | NonClosableProps;
32
-
33
- export const Tag = ({
6
+ const tagVariants = cva(
7
+ "group/tag 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-error aria-invalid:ring-error/20 dark:aria-invalid:ring-error/40 [&>svg]:pointer-events-none [&>svg]:size-3!",
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
12
+ secondary:
13
+ "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
14
+ error:
15
+ "bg-error/10 text-error focus-visible:ring-error/20 dark:bg-error/20 dark:focus-visible:ring-error/40 [a]:hover:bg-error/20",
16
+ outline:
17
+ "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
18
+ ghost:
19
+ "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
20
+ link: "text-primary underline-offset-4 hover:underline",
21
+ },
22
+ },
23
+ defaultVariants: {
24
+ variant: "default",
25
+ },
26
+ },
27
+ );
28
+
29
+ function Tag({
34
30
  className,
35
- color,
36
- variant,
37
- rounded,
38
- icon,
39
- closable,
40
- onClose,
41
- children,
31
+ variant = "default",
32
+ render,
42
33
  ...props
43
- }: Props) => {
44
- const withTextColored =
45
- !!color && (variant === "outline" || variant === "borderless");
46
- const withBgColored = !!color && !variant;
47
-
48
- return (
49
- <div
50
- data-slot="tag"
51
- className={cn(
52
- tagVariants({ variant, rounded }),
53
- withTextColored && `bg-white`,
54
- withBgColored && ` text-white`,
55
- !!icon && "pl-1.5",
56
- !!closable && "pr-1.5",
57
- className,
58
- )}
59
- style={{
60
- ...(withTextColored && {
61
- color: color,
62
- borderColor: color,
63
- }),
64
- ...(withBgColored && {
65
- borderColor: color,
66
- backgroundColor: color,
67
- }),
68
- }}
69
- {...props}
70
- >
71
- {icon}
72
- {children}
73
- {closable && (
74
- <button
75
- type="button"
76
- data-slot="tag-close"
77
- className="z-10 h-4 w-4 cursor-pointer"
78
- onClick={(e) => {
79
- e.stopPropagation();
80
- onClose();
81
- }}
82
- >
83
- <X data-slot="tag-close-icon" />
84
- </button>
85
- )}
86
-
87
- <span
88
- data-slot="tag-overlay"
89
- className="w-full h-full absolute top-0 left-0"
90
- style={{
91
- ...(withTextColored && {
92
- opacity: 0.13,
93
- backgroundColor: color,
94
- }),
95
- }}
96
- />
97
- </div>
98
- );
99
- };
34
+ }: useRender.ComponentProps<"span"> & VariantProps<typeof tagVariants>) {
35
+ return useRender({
36
+ defaultTagName: "span",
37
+ props: mergeProps<"span">(
38
+ {
39
+ className: cn(tagVariants({ variant }), className),
40
+ },
41
+ props,
42
+ ),
43
+ render,
44
+ state: {
45
+ slot: "tag",
46
+ variant,
47
+ },
48
+ });
49
+ }
50
+
51
+ export { Tag, tagVariants };
@@ -1,15 +1,13 @@
1
1
  import type { Meta, StoryObj } from "@storybook/react-vite";
2
2
  import { useState } from "react";
3
- import { Textarea, TextareaControl, TextareaField } from "../../components";
3
+ import { Textarea } from "../../components";
4
4
 
5
5
  /**
6
- * Multi-line text input built on Base UI's Field.Control.
7
- * Shares the same border, focus, error, and disabled states as `Input`.
6
+ * Multi-line text input. Shares border, focus, error, and disabled states with `Input`.
8
7
  * Error state is driven by `aria-invalid` — pass it directly or wire via a `Field` context.
9
- * Use `controlProps` to pass extra props to the outer wrapper `span`.
10
8
  *
11
- * `onChange` receives `(value: string, event: ChangeEvent<HTMLTextAreaElement>)` — not the
12
- * native event directly. This matches the `Input` component API.
9
+ * `onValueChange` receives `(value: string, event: ChangeEvent<HTMLTextAreaElement>)` — not
10
+ * the native event directly. This matches the `Input` component API.
13
11
  */
14
12
  const meta: Meta<typeof Textarea> = {
15
13
  title: "Components/Textarea",
@@ -49,25 +47,13 @@ export const Error: Story = {
49
47
  };
50
48
 
51
49
  /**
52
- * `onChange` fires with `(value: string, event)` — the extracted string value comes first,
53
- * matching the `Input` component signature. Use `value` + `onChange` for controlled usage;
54
- * `defaultValue` for uncontrolled.
50
+ * `onValueChange` fires with `(value: string, event)` — the extracted string value comes
51
+ * first, matching the `Input` component signature. Use `value` + `onValueChange` for
52
+ * controlled usage; `defaultValue` for uncontrolled.
55
53
  */
56
54
  export const Controlled: Story = {
57
55
  render: () => {
58
56
  const [value, setValue] = useState<string>("");
59
- return <Textarea value={value} onChange={setValue} />;
57
+ return <Textarea value={value} onValueChange={setValue} />;
60
58
  },
61
59
  };
62
-
63
- /**
64
- * Use `TextareaControl` and `TextareaField` directly when you need to inject
65
- * elements inside the wrapper (e.g., a character counter overlay).
66
- */
67
- export const Primitive: Story = {
68
- render: (args) => (
69
- <TextareaControl>
70
- <TextareaField {...args} />
71
- </TextareaControl>
72
- ),
73
- };
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { Field as FieldPrimitive } from "@base-ui/react/field";
4
- import { mergeProps } from "@base-ui/react/merge-props";
3
+ import { Field } from "@base-ui/react/field";
5
4
  import {
6
5
  type ChangeEvent,
7
6
  type ComponentProps,
@@ -9,97 +8,36 @@ import {
9
8
  } from "react";
10
9
  import { cn } from "../../lib";
11
10
 
12
- // ─── Primitives ───────────────────────────────────────────────────────────────
13
-
14
- export function TextareaControl({
15
- className,
16
- unstyled = false,
17
- children,
18
- ...props
19
- }: ComponentProps<"span"> & { unstyled?: boolean }): ReactElement {
20
- return (
21
- <span
22
- className={
23
- cn(
24
- !unstyled &&
25
- "relative inline-flex w-full rounded-md border border-input bg-background text-sm transition-shadow has-focus-visible:border-ring has-aria-invalid:border-error has-focus-visible:has-aria-invalid:ring-error/20 has-disabled:cursor-not-allowed has-disabled:opacity-50",
26
- className,
27
- ) || undefined
28
- }
29
- data-slot="textarea-control"
30
- {...props}
31
- >
32
- {children}
33
- </span>
34
- );
35
- }
36
-
37
- export type TextareaFieldProps = Omit<
38
- ComponentProps<"textarea">,
39
- "onChange"
40
- > & {
41
- onChange?: (value: string, event: ChangeEvent<HTMLTextAreaElement>) => void;
11
+ export type TextareaProps = Omit<ComponentProps<"textarea">, "onChange"> & {
12
+ onValueChange?: (
13
+ value: string,
14
+ event: ChangeEvent<HTMLTextAreaElement>,
15
+ ) => void;
42
16
  };
43
17
 
44
- export function TextareaField({
18
+ export function Textarea({
45
19
  className,
46
- ref,
47
- onChange,
20
+ onValueChange,
48
21
  ...props
49
- }: TextareaFieldProps): ReactElement {
50
- const handleChange = onChange
22
+ }: TextareaProps): ReactElement {
23
+ const handleChange = onValueChange
51
24
  ? (event: ChangeEvent<HTMLTextAreaElement>) =>
52
- onChange(event.target.value, event)
25
+ onValueChange(event.target.value, event)
53
26
  : undefined;
54
27
 
55
28
  return (
56
- <FieldPrimitive.Control
57
- ref={ref}
58
- value={props.value}
59
- defaultValue={props.defaultValue}
60
- disabled={props.disabled}
61
- id={props.id}
62
- name={props.name}
63
- render={(defaultProps: ComponentProps<"textarea">) => (
29
+ <Field.Control
30
+ render={
64
31
  <textarea
32
+ data-slot="textarea"
65
33
  className={cn(
66
- "field-sizing-content min-h-17.5 w-full rounded-[inherit] px-[calc(--spacing(3)-1px)] py-[calc(--spacing(1.5)-1px)] outline-none placeholder:text-muted-foreground max-sm:min-h-20.5",
34
+ "flex field-sizing-content min-h-16 w-full rounded-md border border-input bg-background px-3 py-2 text-sm outline-none transition-shadow placeholder:text-muted-foreground focus-visible:border-ring aria-invalid:border-error focus-visible:aria-invalid:ring-error/20 disabled:cursor-not-allowed disabled:opacity-50",
67
35
  className,
68
36
  )}
69
- data-slot="textarea"
70
- {...mergeProps(defaultProps, props)}
71
37
  onChange={handleChange}
38
+ {...props}
72
39
  />
73
- )}
40
+ }
74
41
  />
75
42
  );
76
43
  }
77
-
78
- // ─── Composite ────────────────────────────────────────────────────────────────
79
-
80
- export type TextareaProps = TextareaFieldProps & {
81
- unstyled?: boolean;
82
- controlProps?: ComponentProps<typeof TextareaControl>;
83
- };
84
-
85
- export function Textarea({
86
- className,
87
- unstyled = false,
88
- ref,
89
- controlProps,
90
- ...props
91
- }: TextareaProps): ReactElement {
92
- return (
93
- <TextareaControl
94
- unstyled={unstyled}
95
- className={className}
96
- {...controlProps}
97
- >
98
- <TextareaField ref={ref} {...props} />
99
- </TextareaControl>
100
- );
101
- }
102
-
103
- // ─── Exports ──────────────────────────────────────────────────────────────────
104
-
105
- export { FieldPrimitive };