@elabs-ai/components-ui 4.0.0 → 4.1.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.
Files changed (223) hide show
  1. package/README.md +10 -8
  2. package/dist/chunk-JKPPTL63.js +48 -0
  3. package/dist/chunk-JKPPTL63.js.map +1 -0
  4. package/dist/form.d.ts +28 -0
  5. package/dist/form.js +123 -0
  6. package/dist/form.js.map +1 -0
  7. package/dist/index.d.ts +2485 -167
  8. package/dist/index.js +10716 -2706
  9. package/dist/index.js.map +1 -1
  10. package/package.json +21 -7
  11. package/src/_peer-deps.test.ts +59 -0
  12. package/src/blocks-comparison-table.stories.tsx +2 -2
  13. package/src/components/accordion/accordion.tsx +1 -1
  14. package/src/components/advanced-group/advanced-group.tsx +1 -1
  15. package/src/components/alert/alert.tsx +4 -1
  16. package/src/components/app-shell/app-shell.stories.tsx +44 -2
  17. package/src/components/app-shell/app-shell.tsx +35 -2
  18. package/src/components/app-sidebar/app-sidebar.stories.tsx +9 -1
  19. package/src/components/attribution-panel/attribution-panel.tsx +1 -1
  20. package/src/components/attribution-panel/attributions.generated.ts +81 -77
  21. package/src/components/badge/badge.stories.tsx +8 -0
  22. package/src/components/badge/badge.tsx +1 -1
  23. package/src/components/bento-grid/bento-grid.test.tsx +1 -1
  24. package/src/components/bento-grid/bento-grid.tsx +1 -1
  25. package/src/components/breadcrumb/breadcrumb.stories.tsx +38 -0
  26. package/src/components/breadcrumb/breadcrumb.test.tsx +24 -1
  27. package/src/components/breadcrumb/breadcrumb.tsx +7 -2
  28. package/src/components/button/button.stories.tsx +116 -8
  29. package/src/components/button/button.tsx +1 -1
  30. package/src/components/card/card.stories.tsx +11 -6
  31. package/src/components/card/card.tsx +1 -1
  32. package/src/components/change-review/change-review.stories.tsx +145 -1
  33. package/src/components/change-review/change-review.test.tsx +143 -0
  34. package/src/components/change-review/change-review.tsx +185 -4
  35. package/src/components/checkbox/checkbox.tsx +1 -1
  36. package/src/components/color-picker/color-picker.tsx +6 -5
  37. package/src/components/command/command.stories.tsx +16 -6
  38. package/src/components/command/command.test.tsx +73 -0
  39. package/src/components/command/command.tsx +30 -7
  40. package/src/components/command/index.ts +1 -0
  41. package/src/components/command-trigger/command-trigger.stories.tsx +39 -0
  42. package/src/components/command-trigger/command-trigger.test.tsx +18 -0
  43. package/src/components/command-trigger/command-trigger.tsx +70 -0
  44. package/src/components/command-trigger/index.ts +1 -0
  45. package/src/components/context-rail/context-rail.stories.tsx +285 -0
  46. package/src/components/context-rail/context-rail.test.tsx +263 -0
  47. package/src/components/context-rail/context-rail.tsx +678 -0
  48. package/src/components/context-rail/index.ts +1 -0
  49. package/src/components/copyable-value/copyable-value.tsx +1 -1
  50. package/src/components/dialog/dialog.tsx +2 -2
  51. package/src/components/dropdown-menu/dropdown-menu.stories.tsx +1 -1
  52. package/src/components/empty-state/empty-state.test.tsx +26 -0
  53. package/src/components/empty-state/empty-state.tsx +6 -1
  54. package/src/components/expand-dialog/expand-dialog.tsx +1 -2
  55. package/src/components/field/field-context.ts +59 -0
  56. package/src/components/field/field.stories.tsx +142 -0
  57. package/src/components/field/field.test.tsx +415 -0
  58. package/src/components/field/field.tsx +340 -0
  59. package/src/components/field/index.ts +9 -0
  60. package/src/components/field-row/field-row.stories.tsx +85 -1
  61. package/src/components/field-row/field-row.test.tsx +145 -0
  62. package/src/components/field-row/field-row.tsx +48 -6
  63. package/src/components/file-upload/file-upload.stories.tsx +16 -0
  64. package/src/components/file-upload/file-upload.test.tsx +7 -2
  65. package/src/components/file-upload/file-upload.tsx +15 -4
  66. package/src/components/form/form.tsx +5 -2
  67. package/src/components/icon-button/icon-button.test.tsx +1 -1
  68. package/src/components/icon-button/icon-button.tsx +2 -2
  69. package/src/components/input/input.stories.tsx +121 -0
  70. package/src/components/input/input.test.tsx +13 -0
  71. package/src/components/input/input.tsx +2 -2
  72. package/src/components/input-group/input-group.stories.tsx +74 -0
  73. package/src/components/input-group/input-group.tsx +13 -4
  74. package/src/components/input-otp/input-otp.tsx +5 -1
  75. package/src/components/keyboard-shortcuts/index.ts +6 -0
  76. package/src/components/keyboard-shortcuts/keyboard-shortcuts.stories.tsx +177 -0
  77. package/src/components/keyboard-shortcuts/keyboard-shortcuts.test.tsx +73 -0
  78. package/src/components/keyboard-shortcuts/keyboard-shortcuts.tsx +203 -0
  79. package/src/components/link-preview/link-preview.tsx +1 -1
  80. package/src/components/locale-provider/index.ts +6 -1
  81. package/src/components/locale-provider/locale-provider.stories.tsx +89 -1
  82. package/src/components/locale-provider/locale-provider.test.tsx +257 -1
  83. package/src/components/locale-provider/locale-provider.tsx +63 -8
  84. package/src/components/locale-provider/messages.ts +501 -2
  85. package/src/components/match-highlight/match-highlight.stories.tsx +1 -1
  86. package/src/components/mention-input/mention-input-mirror.stories.tsx +9 -1
  87. package/src/components/mention-input/mention-input.tsx +8 -38
  88. package/src/components/mention-input/mention-value.ts +8 -2
  89. package/src/components/metric-card/metric-card.stories.tsx +5 -3
  90. package/src/components/metric-card/metric-card.tsx +21 -2
  91. package/src/components/model-picker/model-picker.stories.tsx +63 -3
  92. package/src/components/model-picker/model-picker.test.tsx +63 -0
  93. package/src/components/model-picker/model-picker.tsx +62 -36
  94. package/src/components/nav-main/nav-main.tsx +1 -1
  95. package/src/components/nav-notifications/nav-notifications.stories.tsx +110 -0
  96. package/src/components/nav-notifications/nav-notifications.tsx +57 -5
  97. package/src/components/navigation-menu/navigation-menu.stories.tsx +22 -0
  98. package/src/components/navigation-menu/navigation-menu.test.tsx +174 -0
  99. package/src/components/navigation-menu/navigation-menu.tsx +189 -12
  100. package/src/components/page-shell/page-shell.stories.tsx +163 -0
  101. package/src/components/page-shell/page-shell.test.tsx +229 -0
  102. package/src/components/page-shell/page-shell.tsx +108 -25
  103. package/src/components/pagination/pagination.test.tsx +90 -0
  104. package/src/components/pagination/pagination.tsx +9 -5
  105. package/src/components/radio-group/radio-group.tsx +1 -1
  106. package/src/components/rating/rating.tsx +1 -1
  107. package/src/components/resizable/resizable.stories.tsx +114 -2
  108. package/src/components/resizable/resizable.tsx +1 -1
  109. package/src/components/revision-timeline/revision-timeline.stories.tsx +8 -1
  110. package/src/components/revision-timeline/revision-timeline.test.tsx +26 -0
  111. package/src/components/revision-timeline/revision-timeline.tsx +46 -3
  112. package/src/components/schema-form/from-json-schema.test.ts +390 -0
  113. package/src/components/schema-form/from-json-schema.ts +375 -0
  114. package/src/components/schema-form/index.ts +81 -0
  115. package/src/components/schema-form/schema-form-spec.ts +698 -0
  116. package/src/components/schema-form/schema-form.stories.tsx +566 -0
  117. package/src/components/schema-form/schema-form.test.tsx +900 -0
  118. package/src/components/schema-form/schema-form.tsx +1545 -0
  119. package/src/components/section-header/section-header.stories.tsx +37 -0
  120. package/src/components/section-header/section-header.tsx +12 -1
  121. package/src/components/select/select.tsx +6 -2
  122. package/src/components/sheet/sheet.tsx +1 -1
  123. package/src/components/side-dock/index.ts +1 -0
  124. package/src/components/side-dock/side-dock.stories.tsx +137 -0
  125. package/src/components/side-dock/side-dock.test.tsx +273 -0
  126. package/src/components/side-dock/side-dock.tsx +502 -0
  127. package/src/components/sidebar/index.ts +1 -0
  128. package/src/components/sidebar/sidebar-frame.test.tsx +162 -0
  129. package/src/components/sidebar/sidebar.stories.tsx +421 -1
  130. package/src/components/sidebar/sidebar.test.tsx +36 -1
  131. package/src/components/sidebar/sidebar.tsx +245 -33
  132. package/src/components/skip-link/index.ts +1 -0
  133. package/src/components/skip-link/skip-link.stories.tsx +106 -0
  134. package/src/components/skip-link/skip-link.test.tsx +20 -0
  135. package/src/components/skip-link/skip-link.tsx +34 -0
  136. package/src/components/slider/slider.tsx +1 -1
  137. package/src/components/split-panel/index.ts +6 -1
  138. package/src/components/split-panel/split-panel.stories.tsx +18 -2
  139. package/src/components/split-panel/split-panel.test.tsx +20 -0
  140. package/src/components/split-panel/split-panel.tsx +28 -8
  141. package/src/components/state-panel/state-panel.stories.tsx +52 -0
  142. package/src/components/state-panel/state-panel.test.tsx +125 -0
  143. package/src/components/state-panel/state-panel.tsx +96 -17
  144. package/src/components/status-badge/status-badge.stories.tsx +8 -0
  145. package/src/components/switch/switch.tsx +1 -1
  146. package/src/components/table/table.stories.tsx +62 -0
  147. package/src/components/table/table.test.tsx +142 -1
  148. package/src/components/table/table.tsx +60 -1
  149. package/src/components/tabs/tabs.tsx +8 -2
  150. package/src/components/tag-input/tag-input.tsx +3 -2
  151. package/src/components/team-switcher/team-switcher.tsx +34 -5
  152. package/src/components/textarea/textarea.tsx +1 -1
  153. package/src/components/theme-switcher/theme-switcher.tsx +6 -2
  154. package/src/components/theme-switcher/use-theme-transition.ts +2 -2
  155. package/src/components/timeline/timeline.stories.tsx +27 -0
  156. package/src/components/timeline/timeline.tsx +11 -1
  157. package/src/components/toggle/toggle.tsx +1 -1
  158. package/src/components/toolbar/toolbar.stories.tsx +10 -2
  159. package/src/components/tree/tree.stories.tsx +2 -2
  160. package/src/components/tree/tree.tsx +14 -9
  161. package/src/components/typography/prose.tsx +1 -1
  162. package/src/components/typography/typography.stories.tsx +228 -0
  163. package/src/components/view-toolbar/view-toolbar.stories.tsx +41 -1
  164. package/src/components/view-toolbar/view-toolbar.test.tsx +33 -0
  165. package/src/components/view-toolbar/view-toolbar.tsx +37 -4
  166. package/src/components/virtual-select/virtual-select.test.tsx +1 -1
  167. package/src/components/wizard/wizard.tsx +1 -1
  168. package/src/components/workspace-picker/index.ts +3 -0
  169. package/src/components/workspace-picker/workspace-picker-state.ts +50 -0
  170. package/src/components/workspace-picker/workspace-picker.stories.tsx +126 -0
  171. package/src/components/workspace-picker/workspace-picker.test.tsx +207 -0
  172. package/src/components/workspace-picker/workspace-picker.tsx +172 -0
  173. package/src/illustrations/empty-list-illustration.tsx +26 -0
  174. package/src/illustrations/error-illustration.tsx +60 -0
  175. package/src/illustrations/first-run-illustration.tsx +27 -0
  176. package/src/illustrations/illustration-base.tsx +108 -0
  177. package/src/illustrations/illustrations.stories.tsx +94 -0
  178. package/src/illustrations/illustrations.test.tsx +98 -0
  179. package/src/illustrations/index.ts +16 -0
  180. package/src/illustrations/no-access-illustration.tsx +45 -0
  181. package/src/illustrations/no-results-illustration.tsx +46 -0
  182. package/src/illustrations/offline-illustration.tsx +37 -0
  183. package/src/illustrations/success-illustration.tsx +40 -0
  184. package/src/index.ts +75 -2
  185. package/src/lib/agent-event-model.test.ts +12 -0
  186. package/src/lib/agent-event-model.ts +42 -0
  187. package/src/lib/approval-option.test.ts +17 -0
  188. package/src/lib/approval-option.ts +53 -0
  189. package/src/lib/check-result.ts +33 -0
  190. package/src/lib/diff-line.test.ts +36 -0
  191. package/src/lib/diff-line.ts +63 -0
  192. package/src/lib/diff-rows.test.ts +76 -0
  193. package/src/lib/diff-rows.ts +92 -0
  194. package/src/lib/format-duration.test.ts +22 -0
  195. package/src/lib/format-duration.ts +30 -0
  196. package/src/lib/has-renderable-content.test.ts +49 -0
  197. package/src/lib/has-renderable-content.ts +32 -0
  198. package/src/lib/operating-mode.test.ts +36 -0
  199. package/src/lib/operating-mode.ts +81 -0
  200. package/src/lib/optional-peer.ts +59 -0
  201. package/src/lib/session-launch.ts +37 -0
  202. package/src/lib/slash-command.test.ts +44 -0
  203. package/src/lib/slash-command.ts +45 -0
  204. package/src/lib/trigger-query.test.ts +94 -0
  205. package/src/lib/trigger-query.ts +88 -0
  206. package/src/lib/use-mobile.ts +12 -6
  207. package/src/motion.stories.tsx +6 -0
  208. package/src/templates-object-detail-hub.stories.tsx +2 -2
  209. package/src/templates-screen-states.stories.tsx +5 -5
  210. package/src/templates-settings.stories.tsx +1 -1
  211. package/src/blocks/sidebar-02/app-sidebar.tsx +0 -160
  212. package/src/blocks/sidebar-02/logo.tsx +0 -18
  213. package/src/blocks/sidebar-02/nav-main.tsx +0 -13
  214. package/src/blocks/sidebar-02/nav-notifications.tsx +0 -7
  215. package/src/blocks/sidebar-02/sidebar-02.stories.tsx +0 -23
  216. package/src/blocks/sidebar-02/team-switcher.tsx +0 -7
  217. package/src/blocks/sidebar-04/app-sidebar.tsx +0 -236
  218. package/src/blocks/sidebar-04/mail-context.tsx +0 -29
  219. package/src/blocks/sidebar-04/nav-user.tsx +0 -6
  220. package/src/blocks/sidebar-04/sidebar-04.stories.tsx +0 -150
  221. package/src/blocks/sidebar-05/app-sidebar.tsx +0 -375
  222. package/src/blocks/sidebar-05/sidebar-05.stories.tsx +0 -18
  223. package/src/blocks/sidebar-05/team-switcher.tsx +0 -6
package/README.md CHANGED
@@ -6,15 +6,16 @@
6
6
  > Foundation + app UI (Button, Card, Dialog, Tabs, AppShell, …).
7
7
 
8
8
  Part of **brand-ui**, a source-owned, token-driven React component system.
9
- These packages are **private** and are not published to any registry they are
10
- consumed from this workspace. See `docs/CONSUMING.md`.
9
+ Published to the **public npm registry** under the `@elabs-ai` scopeit
10
+ installs like any other npm dependency, with no registry configuration and
11
+ no token required. See `docs/CONSUMING.md`.
11
12
 
12
13
  ## Install
13
14
 
14
- Inside this monorepo the packages resolve as workspace dependencies:
15
-
16
- ```json
17
- "@elabs-ai/components-ui": "workspace:*"
15
+ ```bash
16
+ pnpm add @elabs-ai/components-tokens @elabs-ai/components-ui
17
+ pnpm add @hookform/resolvers@"^3.9.1" # optional peer
18
+ pnpm add react-hook-form@"^7.54.2" # optional peer
18
19
  ```
19
20
 
20
21
  ## Set up styling (do not skip)
@@ -40,10 +41,11 @@ import { ThemeProvider } from "@elabs-ai/components-tokens";
40
41
  ## This package specifically
41
42
 
42
43
  - The class-merge helper is at `.../lib/cn` — a pure, server-safe entry point.
44
+ - `react-hook-form` / `@hookform/resolvers` are **optional peers** — install them only if you use `Form` (import it from `.../form`, not the main barrel). `FieldRow` is the headless, react-hook-form-free field primitive and needs neither.
43
45
 
44
46
  ## What's in it
45
47
 
46
- 354 exported components — including `Accordion`, `AccordionContent`, `AccordionItem`, `AccordionTrigger`, `AdvancedGroup`.
48
+ 379 exported components — including `Accordion`, `AccordionContent`, `AccordionItem`, `AccordionTrigger`, `AdvancedGroup`.
47
49
 
48
50
  Don't guess the API — ask the CLI:
49
51
 
@@ -73,6 +75,6 @@ prompt for migrating an existing project: `docs/CONSUMING.md`.
73
75
 
74
76
  ## License
75
77
 
76
- UNLICENSED — private.
78
+ MIT
77
79
 
78
80
  <!-- brand-ui:gen:readme:end -->
@@ -0,0 +1,48 @@
1
+ "use client";
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ // src/lib/cn.ts
9
+ import { clsx } from "clsx";
10
+ import { extendTailwindMerge } from "tailwind-merge";
11
+ var TEXT_ROLES = ["display", "title", "subtitle", "body", "caption", "meta", "kpi", "code"];
12
+ var twMerge = extendTailwindMerge({
13
+ extend: {
14
+ classGroups: {
15
+ "font-size": [{ text: TEXT_ROLES }],
16
+ // `font-display` is the display-face seam (sibling of font-mono, #187).
17
+ "font-family": [{ font: ["display"] }]
18
+ }
19
+ }
20
+ });
21
+ function cn(...inputs) {
22
+ return twMerge(clsx(inputs));
23
+ }
24
+
25
+ // src/components/label/label.tsx
26
+ import { forwardRef } from "react";
27
+ import * as LabelPrimitive from "@radix-ui/react-label";
28
+ import { jsx } from "react/jsx-runtime";
29
+ var Label = forwardRef(function Label2({ className, ...props }, ref) {
30
+ return /* @__PURE__ */ jsx(
31
+ LabelPrimitive.Root,
32
+ {
33
+ ref,
34
+ className: cn(
35
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
36
+ className
37
+ ),
38
+ ...props
39
+ }
40
+ );
41
+ });
42
+
43
+ export {
44
+ __export,
45
+ cn,
46
+ Label
47
+ };
48
+ //# sourceMappingURL=chunk-JKPPTL63.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/cn.ts","../src/components/label/label.tsx"],"sourcesContent":["import { clsx, type ClassValue } from \"clsx\";\nimport { extendTailwindMerge } from \"tailwind-merge\";\n\n/**\n * The semantic type roles (`--text-<role>` tokens → `text-<role>` utilities, #187).\n * tailwind-merge doesn't know custom theme keys, so without registration it\n * classifies `text-title` as a text COLOR — and `cn(\"text-kpi\", \"text-foreground\")`\n * would silently drop the role. Registering the roles in the `font-size` class\n * group makes role-vs-role and role-vs-raw-size conflicts resolve correctly while\n * keeping role + color independent.\n */\nconst TEXT_ROLES = [\"display\", \"title\", \"subtitle\", \"body\", \"caption\", \"meta\", \"kpi\", \"code\"];\n\nconst twMerge = extendTailwindMerge({\n extend: {\n classGroups: {\n \"font-size\": [{ text: TEXT_ROLES }],\n // `font-display` is the display-face seam (sibling of font-mono, #187).\n \"font-family\": [{ font: [\"display\"] }],\n },\n },\n});\n\n/**\n * Merge class names with conflict resolution. `clsx` handles conditionals;\n * `tailwind-merge` ensures later Tailwind utilities win (e.g. `p-2 p-4` -> `p-4`).\n * Use this in every component that accepts a `className` prop.\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import { forwardRef, type ComponentPropsWithoutRef, type ElementRef } from \"react\";\nimport * as LabelPrimitive from \"@radix-ui/react-label\";\nimport { cn } from \"../../lib/cn\";\n\nexport const Label = forwardRef<\n ElementRef<typeof LabelPrimitive.Root>,\n ComponentPropsWithoutRef<typeof LabelPrimitive.Root>\n>(function Label({ className, ...props }, ref) {\n return (\n <LabelPrimitive.Root\n ref={ref}\n className={cn(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n className,\n )}\n {...props}\n />\n );\n});\n"],"mappings":";;;;;;;;AAAA,SAAS,YAA6B;AACtC,SAAS,2BAA2B;AAUpC,IAAM,aAAa,CAAC,WAAW,SAAS,YAAY,QAAQ,WAAW,QAAQ,OAAO,MAAM;AAE5F,IAAM,UAAU,oBAAoB;AAAA,EAClC,QAAQ;AAAA,IACN,aAAa;AAAA,MACX,aAAa,CAAC,EAAE,MAAM,WAAW,CAAC;AAAA;AAAA,MAElC,eAAe,CAAC,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC;AAAA,IACvC;AAAA,EACF;AACF,CAAC;AAOM,SAAS,MAAM,QAA8B;AAClD,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;AC9BA,SAAS,kBAAkE;AAC3E,YAAY,oBAAoB;AAQ5B;AALG,IAAM,QAAQ,WAGnB,SAASA,OAAM,EAAE,WAAW,GAAG,MAAM,GAAG,KAAK;AAC7C,SACE;AAAA,IAAgB;AAAA,IAAf;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;","names":["Label"]}
package/dist/form.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ import * as _radix_ui_react_slot from '@radix-ui/react-slot';
2
+ import * as _radix_ui_react_label from '@radix-ui/react-label';
3
+ import * as react from 'react';
4
+ import { HTMLAttributes } from 'react';
5
+ import * as react_hook_form from 'react-hook-form';
6
+ import { FieldValues, FieldPath, ControllerProps } from 'react-hook-form';
7
+
8
+ declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransformedValues = TFieldValues>({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, }: react_hook_form.FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React.JSX.Element;
9
+ declare function FormField<TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>(props: ControllerProps<TFieldValues, TName>): react.JSX.Element;
10
+ declare function useFormField(): {
11
+ invalid: boolean;
12
+ isDirty: boolean;
13
+ isTouched: boolean;
14
+ isValidating: boolean;
15
+ error?: react_hook_form.FieldError;
16
+ id: string;
17
+ name: string;
18
+ formItemId: string;
19
+ formDescriptionId: string;
20
+ formMessageId: string;
21
+ };
22
+ declare const FormItem: react.ForwardRefExoticComponent<HTMLAttributes<HTMLDivElement> & react.RefAttributes<HTMLDivElement>>;
23
+ declare const FormLabel: react.ForwardRefExoticComponent<Omit<Omit<_radix_ui_react_label.LabelProps & react.RefAttributes<HTMLLabelElement>, "ref"> & react.RefAttributes<HTMLLabelElement>, "ref"> & react.RefAttributes<HTMLLabelElement>>;
24
+ declare const FormControl: react.ForwardRefExoticComponent<Omit<_radix_ui_react_slot.SlotProps & react.RefAttributes<HTMLElement>, "ref"> & react.RefAttributes<HTMLElement>>;
25
+ declare const FormDescription: react.ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & react.RefAttributes<HTMLParagraphElement>>;
26
+ declare const FormMessage: react.ForwardRefExoticComponent<HTMLAttributes<HTMLParagraphElement> & react.RefAttributes<HTMLParagraphElement>>;
27
+
28
+ export { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFormField };
package/dist/form.js ADDED
@@ -0,0 +1,123 @@
1
+ "use client";
2
+ import {
3
+ Label,
4
+ cn
5
+ } from "./chunk-JKPPTL63.js";
6
+
7
+ // src/components/form/form.tsx
8
+ import {
9
+ createContext,
10
+ forwardRef,
11
+ useContext,
12
+ useId
13
+ } from "react";
14
+ import { Slot } from "@radix-ui/react-slot";
15
+ import {
16
+ Controller,
17
+ FormProvider,
18
+ useFormContext
19
+ } from "react-hook-form";
20
+ import { jsx } from "react/jsx-runtime";
21
+ var Form = FormProvider;
22
+ var FormFieldContext = createContext({});
23
+ function FormField(props) {
24
+ return /* @__PURE__ */ jsx(FormFieldContext.Provider, { value: { name: props.name }, children: /* @__PURE__ */ jsx(Controller, { ...props }) });
25
+ }
26
+ var FormItemContext = createContext({});
27
+ function useFormField() {
28
+ const fieldContext = useContext(FormFieldContext);
29
+ const itemContext = useContext(FormItemContext);
30
+ const { getFieldState, formState } = useFormContext();
31
+ const fieldState = getFieldState(fieldContext.name, formState);
32
+ if (!fieldContext) throw new Error("useFormField should be used within <FormField>");
33
+ const { id } = itemContext;
34
+ return {
35
+ id,
36
+ name: fieldContext.name,
37
+ formItemId: `${id}-form-item`,
38
+ formDescriptionId: `${id}-form-item-description`,
39
+ formMessageId: `${id}-form-item-message`,
40
+ ...fieldState
41
+ };
42
+ }
43
+ var FormItem = forwardRef(
44
+ function FormItem2({ className, ...props }, ref) {
45
+ const id = useId();
46
+ return /* @__PURE__ */ jsx(FormItemContext.Provider, { value: { id }, children: /* @__PURE__ */ jsx("div", { ref, className: cn("space-y-2", className), ...props }) });
47
+ }
48
+ );
49
+ var FormLabel = forwardRef(function FormLabel2({ className, ...props }, ref) {
50
+ const { error, formItemId } = useFormField();
51
+ return /* @__PURE__ */ jsx(
52
+ Label,
53
+ {
54
+ ref,
55
+ htmlFor: formItemId,
56
+ className: cn(
57
+ "transition-colors duration-fast ease-standard",
58
+ // #124: the label's own error-state text, not a mark — ink rung.
59
+ error && "text-destructive-text",
60
+ className
61
+ ),
62
+ ...props
63
+ }
64
+ );
65
+ });
66
+ var FormControl = forwardRef(function FormControl2(props, ref) {
67
+ const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
68
+ return /* @__PURE__ */ jsx(
69
+ Slot,
70
+ {
71
+ ref,
72
+ id: formItemId,
73
+ "aria-describedby": error ? `${formDescriptionId} ${formMessageId}` : formDescriptionId,
74
+ "aria-invalid": !!error,
75
+ ...props
76
+ }
77
+ );
78
+ });
79
+ var FormDescription = forwardRef(function FormDescription2({ className, ...props }, ref) {
80
+ const { formDescriptionId } = useFormField();
81
+ return /* @__PURE__ */ jsx(
82
+ "p",
83
+ {
84
+ ref,
85
+ id: formDescriptionId,
86
+ className: cn("text-sm text-muted-foreground", className),
87
+ ...props
88
+ }
89
+ );
90
+ });
91
+ var FormMessage = forwardRef(
92
+ function FormMessage2({ className, children, ...props }, ref) {
93
+ const { error, formMessageId } = useFormField();
94
+ const body = error ? String(error?.message ?? "") : children;
95
+ if (!body) return null;
96
+ return /* @__PURE__ */ jsx(
97
+ "p",
98
+ {
99
+ ref,
100
+ id: formMessageId,
101
+ className: cn(
102
+ // #124: the error message body is running text — ink rung, not the
103
+ // 3:1 mark rung `text-destructive` guarantees.
104
+ "text-sm font-medium text-destructive-text animate-in fade-in slide-in-from-top-1 ease-entrance",
105
+ className
106
+ ),
107
+ ...props,
108
+ children: body
109
+ }
110
+ );
111
+ }
112
+ );
113
+ export {
114
+ Form,
115
+ FormControl,
116
+ FormDescription,
117
+ FormField,
118
+ FormItem,
119
+ FormLabel,
120
+ FormMessage,
121
+ useFormField
122
+ };
123
+ //# sourceMappingURL=form.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/form/form.tsx"],"sourcesContent":["import {\n createContext,\n forwardRef,\n useContext,\n useId,\n type ComponentPropsWithoutRef,\n type ElementRef,\n type HTMLAttributes,\n} from \"react\";\nimport { Slot } from \"@radix-ui/react-slot\";\nimport {\n Controller,\n FormProvider,\n useFormContext,\n type ControllerProps,\n type FieldPath,\n type FieldValues,\n} from \"react-hook-form\";\nimport { cn } from \"../../lib/cn\";\nimport { Label } from \"../label\";\n\nexport const Form = FormProvider;\n\ntype FormFieldContextValue<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> = { name: TName };\n\nconst FormFieldContext = createContext<FormFieldContextValue>({} as FormFieldContextValue);\n\nexport function FormField<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>(props: ControllerProps<TFieldValues, TName>) {\n return (\n <FormFieldContext.Provider value={{ name: props.name }}>\n <Controller {...props} />\n </FormFieldContext.Provider>\n );\n}\n\nconst FormItemContext = createContext<{ id: string }>({} as { id: string });\n\nexport function useFormField() {\n const fieldContext = useContext(FormFieldContext);\n const itemContext = useContext(FormItemContext);\n const { getFieldState, formState } = useFormContext();\n const fieldState = getFieldState(fieldContext.name, formState);\n if (!fieldContext) throw new Error(\"useFormField should be used within <FormField>\");\n const { id } = itemContext;\n return {\n id,\n name: fieldContext.name,\n formItemId: `${id}-form-item`,\n formDescriptionId: `${id}-form-item-description`,\n formMessageId: `${id}-form-item-message`,\n ...fieldState,\n };\n}\n\nexport const FormItem = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(\n function FormItem({ className, ...props }, ref) {\n const id = useId();\n return (\n <FormItemContext.Provider value={{ id }}>\n <div ref={ref} className={cn(\"space-y-2\", className)} {...props} />\n </FormItemContext.Provider>\n );\n },\n);\n\nexport const FormLabel = forwardRef<\n ElementRef<typeof Label>,\n ComponentPropsWithoutRef<typeof Label>\n>(function FormLabel({ className, ...props }, ref) {\n const { error, formItemId } = useFormField();\n return (\n <Label\n ref={ref}\n htmlFor={formItemId}\n className={cn(\n \"transition-colors duration-fast ease-standard\",\n // #124: the label's own error-state text, not a mark — ink rung.\n error && \"text-destructive-text\",\n className,\n )}\n {...props}\n />\n );\n});\n\nexport const FormControl = forwardRef<\n ElementRef<typeof Slot>,\n ComponentPropsWithoutRef<typeof Slot>\n>(function FormControl(props, ref) {\n const { error, formItemId, formDescriptionId, formMessageId } = useFormField();\n return (\n <Slot\n ref={ref}\n id={formItemId}\n aria-describedby={error ? `${formDescriptionId} ${formMessageId}` : formDescriptionId}\n aria-invalid={!!error}\n {...props}\n />\n );\n});\n\nexport const FormDescription = forwardRef<\n HTMLParagraphElement,\n HTMLAttributes<HTMLParagraphElement>\n>(function FormDescription({ className, ...props }, ref) {\n const { formDescriptionId } = useFormField();\n return (\n <p\n ref={ref}\n id={formDescriptionId}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n );\n});\n\nexport const FormMessage = forwardRef<HTMLParagraphElement, HTMLAttributes<HTMLParagraphElement>>(\n function FormMessage({ className, children, ...props }, ref) {\n const { error, formMessageId } = useFormField();\n const body = error ? String(error?.message ?? \"\") : children;\n if (!body) return null;\n return (\n <p\n ref={ref}\n id={formMessageId}\n className={cn(\n // #124: the error message body is running text — ink rung, not the\n // 3:1 mark rung `text-destructive` guarantees.\n \"text-sm font-medium text-destructive-text animate-in fade-in slide-in-from-top-1 ease-entrance\",\n className,\n )}\n {...props}\n >\n {body}\n </p>\n );\n },\n);\n"],"mappings":";;;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AACP,SAAS,YAAY;AACrB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAmBD;AAfC,IAAM,OAAO;AAOpB,IAAM,mBAAmB,cAAqC,CAAC,CAA0B;AAElF,SAAS,UAGd,OAA6C;AAC7C,SACE,oBAAC,iBAAiB,UAAjB,EAA0B,OAAO,EAAE,MAAM,MAAM,KAAK,GACnD,8BAAC,cAAY,GAAG,OAAO,GACzB;AAEJ;AAEA,IAAM,kBAAkB,cAA8B,CAAC,CAAmB;AAEnE,SAAS,eAAe;AAC7B,QAAM,eAAe,WAAW,gBAAgB;AAChD,QAAM,cAAc,WAAW,eAAe;AAC9C,QAAM,EAAE,eAAe,UAAU,IAAI,eAAe;AACpD,QAAM,aAAa,cAAc,aAAa,MAAM,SAAS;AAC7D,MAAI,CAAC,aAAc,OAAM,IAAI,MAAM,gDAAgD;AACnF,QAAM,EAAE,GAAG,IAAI;AACf,SAAO;AAAA,IACL;AAAA,IACA,MAAM,aAAa;AAAA,IACnB,YAAY,GAAG,EAAE;AAAA,IACjB,mBAAmB,GAAG,EAAE;AAAA,IACxB,eAAe,GAAG,EAAE;AAAA,IACpB,GAAG;AAAA,EACL;AACF;AAEO,IAAM,WAAW;AAAA,EACtB,SAASA,UAAS,EAAE,WAAW,GAAG,MAAM,GAAG,KAAK;AAC9C,UAAM,KAAK,MAAM;AACjB,WACE,oBAAC,gBAAgB,UAAhB,EAAyB,OAAO,EAAE,GAAG,GACpC,8BAAC,SAAI,KAAU,WAAW,GAAG,aAAa,SAAS,GAAI,GAAG,OAAO,GACnE;AAAA,EAEJ;AACF;AAEO,IAAM,YAAY,WAGvB,SAASC,WAAU,EAAE,WAAW,GAAG,MAAM,GAAG,KAAK;AACjD,QAAM,EAAE,OAAO,WAAW,IAAI,aAAa;AAC3C,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,SAAS;AAAA,MACT,WAAW;AAAA,QACT;AAAA;AAAA,QAEA,SAAS;AAAA,QACT;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;AAEM,IAAM,cAAc,WAGzB,SAASC,aAAY,OAAO,KAAK;AACjC,QAAM,EAAE,OAAO,YAAY,mBAAmB,cAAc,IAAI,aAAa;AAC7E,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,IAAI;AAAA,MACJ,oBAAkB,QAAQ,GAAG,iBAAiB,IAAI,aAAa,KAAK;AAAA,MACpE,gBAAc,CAAC,CAAC;AAAA,MACf,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;AAEM,IAAM,kBAAkB,WAG7B,SAASC,iBAAgB,EAAE,WAAW,GAAG,MAAM,GAAG,KAAK;AACvD,QAAM,EAAE,kBAAkB,IAAI,aAAa;AAC3C,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,IAAI;AAAA,MACJ,WAAW,GAAG,iCAAiC,SAAS;AAAA,MACvD,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;AAEM,IAAM,cAAc;AAAA,EACzB,SAASC,aAAY,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,KAAK;AAC3D,UAAM,EAAE,OAAO,cAAc,IAAI,aAAa;AAC9C,UAAM,OAAO,QAAQ,OAAO,OAAO,WAAW,EAAE,IAAI;AACpD,QAAI,CAAC,KAAM,QAAO;AAClB,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,IAAI;AAAA,QACJ,WAAW;AAAA;AAAA;AAAA,UAGT;AAAA,UACA;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AACF;","names":["FormItem","FormLabel","FormControl","FormDescription","FormMessage"]}