@7onic-ui/react 0.3.10 → 0.3.11

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 (54) hide show
  1. package/README.md +2 -2
  2. package/dist/{chunk-GRCJ35DX.mjs → chunk-2WIIXHOV.mjs} +7 -3
  3. package/dist/chunk-2WIIXHOV.mjs.map +1 -0
  4. package/dist/{chunk-DTLNWOTR.mjs → chunk-C5D3VRNJ.mjs} +29 -7
  5. package/dist/chunk-C5D3VRNJ.mjs.map +1 -0
  6. package/dist/{chunk-T546XBQG.mjs → chunk-EG2GTK65.mjs} +3 -3
  7. package/dist/{chunk-T546XBQG.mjs.map → chunk-EG2GTK65.mjs.map} +1 -1
  8. package/dist/{chunk-UWTT5AE6.mjs → chunk-HS2VRYSX.mjs} +7 -4
  9. package/dist/chunk-HS2VRYSX.mjs.map +1 -0
  10. package/dist/{chunk-N4K2BDGM.mjs → chunk-IHHI3LIN.mjs} +5 -3
  11. package/dist/chunk-IHHI3LIN.mjs.map +1 -0
  12. package/dist/{chunk-VUPGBB5X.mjs → chunk-IJ2FZ3L5.mjs} +11 -2
  13. package/dist/chunk-IJ2FZ3L5.mjs.map +1 -0
  14. package/dist/{chunk-IY3R2VGB.mjs → chunk-L55ABE4H.mjs} +14 -3
  15. package/dist/chunk-L55ABE4H.mjs.map +1 -0
  16. package/dist/{chunk-DRVHHEAY.mjs → chunk-ND6TUVP2.mjs} +7 -4
  17. package/dist/chunk-ND6TUVP2.mjs.map +1 -0
  18. package/dist/{chunk-234NAXGV.mjs → chunk-R7FJEO4K.mjs} +1 -1
  19. package/dist/chunk-R7FJEO4K.mjs.map +1 -0
  20. package/dist/{chunk-WWSN5YME.mjs → chunk-SDDAGZWA.mjs} +5 -3
  21. package/dist/chunk-SDDAGZWA.mjs.map +1 -0
  22. package/dist/{chunk-Z6JWWCNL.mjs → chunk-T5A4APEL.mjs} +35 -3
  23. package/dist/chunk-T5A4APEL.mjs.map +1 -0
  24. package/dist/{chunk-MRUVGHGP.mjs → chunk-YZ7HHFKA.mjs} +7 -7
  25. package/dist/chunk-YZ7HHFKA.mjs.map +1 -0
  26. package/dist/components/chat-input.mjs +1 -1
  27. package/dist/components/chat-message.mjs +1 -1
  28. package/dist/components/checkbox.mjs +2 -2
  29. package/dist/components/field.mjs +5 -3
  30. package/dist/components/input.mjs +2 -2
  31. package/dist/components/navigation-menu.mjs +1 -1
  32. package/dist/components/pagination.mjs +1 -1
  33. package/dist/components/radio-group.mjs +2 -2
  34. package/dist/components/select.mjs +2 -1
  35. package/dist/components/slider.mjs +2 -1
  36. package/dist/components/switch.mjs +2 -2
  37. package/dist/components/textarea.mjs +2 -2
  38. package/dist/index.d.ts +11 -2
  39. package/dist/index.js +95 -21
  40. package/dist/index.js.map +1 -1
  41. package/dist/index.mjs +12 -12
  42. package/llms.txt +27 -9
  43. package/package.json +11 -12
  44. package/dist/chunk-234NAXGV.mjs.map +0 -1
  45. package/dist/chunk-DRVHHEAY.mjs.map +0 -1
  46. package/dist/chunk-DTLNWOTR.mjs.map +0 -1
  47. package/dist/chunk-GRCJ35DX.mjs.map +0 -1
  48. package/dist/chunk-IY3R2VGB.mjs.map +0 -1
  49. package/dist/chunk-MRUVGHGP.mjs.map +0 -1
  50. package/dist/chunk-N4K2BDGM.mjs.map +0 -1
  51. package/dist/chunk-UWTT5AE6.mjs.map +0 -1
  52. package/dist/chunk-VUPGBB5X.mjs.map +0 -1
  53. package/dist/chunk-WWSN5YME.mjs.map +0 -1
  54. package/dist/chunk-Z6JWWCNL.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/select.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SelectPrimitive from '@radix-ui/react-select'\nimport { cn } from '@/lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\n// Radius (matches Input — set at Root, propagates to Trigger and Content)\ntype SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'\n\nconst triggerRadiusMap: Record<SelectRadius, string> = {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-full',\n}\n\n// Auto-mapping: root radius → content radius (3 levels)\ntype SelectContentRadius = 'md' | 'lg' | 'xl'\n\nconst contentRadiusFromRoot: Record<SelectRadius, SelectContentRadius> = {\n none: 'md',\n sm: 'md',\n base: 'md',\n default: 'md',\n lg: 'lg',\n xl: 'xl',\n '2xl': 'xl',\n '3xl': 'xl',\n full: 'xl',\n}\n\nconst contentRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded-md', // 6px\n lg: 'rounded-lg', // 8px\n xl: 'rounded-xl', // 12px\n}\n\nconst itemRadiusMap: Record<SelectContentRadius, string> = {\n md: 'rounded', // 4px — perceptual balance (67%)\n lg: 'rounded-md', // 6px — perceptual balance (75%)\n xl: 'rounded-lg', // 8px — perceptual balance (67%)\n}\n\n// Size variants (matches Input component)\ntype SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl'\n\n// Trigger sizes (identical to Input)\nconst triggerSizeMap: Record<SelectSize, string> = {\n xs: 'h-9 px-3 text-sm', // 36px\n sm: 'h-10 px-3 text-md', // 40px\n default: 'h-11 px-4 text-base', // 44px\n lg: 'h-12 px-4 text-base', // 48px\n xl: 'h-14 px-4 text-base', // 56px\n}\n\n// Trigger icon sizes (matches Input icon pattern)\nconst triggerIconSizeMap: Record<SelectSize, string> = {\n xs: 'icon-xs', // 14px\n sm: 'icon-xs', // 14px\n default: 'icon-sm', // 16px\n lg: 'icon-sm', // 16px\n xl: 'icon-sm', // 16px\n}\n\n// Auto-mapping: trigger size → content item size (3 levels)\ntype SelectItemSize = 'sm' | 'md' | 'lg'\n\nconst itemSizeFromTrigger: Record<SelectSize, SelectItemSize> = {\n xs: 'sm',\n sm: 'sm',\n default: 'md',\n lg: 'md',\n xl: 'lg',\n}\n\n// Item sizes (font matches Trigger for seamless selection, padding controls density)\nconst itemSizeMap: Record<SelectItemSize, string> = {\n sm: 'pl-2 pr-6 py-1.5 text-sm',\n md: 'pl-3 pr-8 py-1.5 text-base',\n lg: 'pl-3 pr-10 py-2.5 text-base',\n}\n\n// Item indicator (check mark) — right-aligned\nconst indicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-2 h-3 w-3',\n md: 'right-2 h-3.5 w-3.5',\n lg: 'right-3 h-4 w-4',\n}\n\n// Label sizes\nconst labelSizeMap: Record<SelectItemSize, string> = {\n sm: 'px-2 py-1.5 text-xs',\n md: 'px-2 py-1.5 text-xs',\n lg: 'px-3 py-2.5 text-xs',\n}\n\n// Flush mode — items span full width, no inner radius\nconst flushItemPaddingMap: Record<SelectItemSize, string> = {\n sm: 'pl-3 pr-7',\n md: 'pl-4 pr-9',\n lg: 'pl-4 pr-11',\n}\n\nconst flushIndicatorSizeMap: Record<SelectItemSize, string> = {\n sm: 'right-3 h-3 w-3',\n md: 'right-3 h-3.5 w-3.5',\n lg: 'right-4 h-4 w-4',\n}\n\nconst flushLabelPaddingMap: Record<SelectItemSize, string> = {\n sm: 'px-3',\n md: 'px-3',\n lg: 'px-4',\n}\n\n// Root context — set at Root, consumed by Trigger and Content\nconst SelectRootContext = React.createContext<{\n size: SelectSize\n radius: SelectRadius\n}>({ size: 'default', radius: 'default' })\n\n// Style context — set at Content, consumed by Item/Label\nconst SelectStyleContext = React.createContext<{\n contentRadius: SelectContentRadius\n itemSize: SelectItemSize\n flush: boolean\n}>({ contentRadius: 'xl', itemSize: 'md', flush: false })\n\n// Root — state management + size/radius context. Inside a Field it inherits the\n// Field's disabled state, like Input and Textarea.\nconst Select = ({\n size = 'default',\n radius = 'default',\n disabled,\n ...props\n}: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {\n size?: SelectSize\n radius?: SelectRadius\n}) => {\n const fieldContext = useFieldContext()\n return (\n <SelectRootContext.Provider value={{ size, radius }}>\n <SelectPrimitive.Root disabled={disabled ?? fieldContext?.disabled} {...props} />\n </SelectRootContext.Provider>\n )\n}\n\n// Value — displays selected value or placeholder\nconst SelectValue = SelectPrimitive.Value\n\n// Group — groups related items\nconst SelectGroup = SelectPrimitive.Group\n\n// Trigger — the element that opens the select (reads size + radius from context)\nconst SelectTrigger = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Trigger>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>\n>(({ className, children, id, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectRootContext)\n // Inside a Field the trigger takes the Field id, so FieldLabel names it\n const fieldContext = useFieldContext()\n useFieldControl('single', Boolean(fieldContext) && !id)\n return (\n <SelectPrimitive.Trigger\n ref={ref}\n id={id ?? fieldContext?.id}\n className={cn(\n 'flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted',\n 'border border-border',\n triggerRadiusMap[radius],\n 'transition-colors duration-micro outline-transparent',\n 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)] focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'data-[placeholder]:text-foreground/30',\n triggerSizeMap[size],\n className\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <svg\n className={cn('ml-2 shrink-0 text-text-muted', triggerIconSizeMap[size])}\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth={2}\n aria-hidden=\"true\"\n >\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n )\n})\nSelectTrigger.displayName = SelectPrimitive.Trigger.displayName\n\n// ScrollUpButton — scroll indicator at top\nconst SelectScrollUpButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollUpButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 15l7-7 7 7\" />\n </svg>\n </SelectPrimitive.ScrollUpButton>\n))\nSelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName\n\n// ScrollDownButton — scroll indicator at bottom\nconst SelectScrollDownButton = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>\n>(({ className, ...props }, ref) => (\n <SelectPrimitive.ScrollDownButton\n ref={ref}\n className={cn('flex items-center justify-center py-1 cursor-default', className)}\n {...props}\n >\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M19 9l-7 7-7-7\" />\n </svg>\n </SelectPrimitive.ScrollDownButton>\n))\nSelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName\n\n// Content — the floating panel (reads size + radius from context, auto-maps both)\nconst SelectContent = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content> & {\n flush?: boolean\n }\n>(({ className, children, position = 'popper', sideOffset = 1, flush = false, onCloseAutoFocus, ...props }, ref) => {\n const { size, radius } = React.useContext(SelectRootContext)\n const itemSize = itemSizeFromTrigger[size]\n const contentRadius = contentRadiusFromRoot[radius]\n return (\n <SelectPrimitive.Portal>\n <SelectStyleContext.Provider value={{ contentRadius, itemSize, flush }}>\n <SelectPrimitive.Content\n ref={ref}\n onCloseAutoFocus={(e) => {\n e.preventDefault()\n onCloseAutoFocus?.(e)\n }}\n className={cn(\n 'relative z-popover min-w-[var(--radix-select-trigger-width)] overflow-hidden border border-border bg-background text-foreground shadow-lg',\n flush ? 'py-1' : 'p-1',\n contentRadiusMap[contentRadius],\n position === 'popper' &&\n 'max-h-[var(--radix-select-content-available-height)]',\n className\n )}\n position={position}\n sideOffset={sideOffset}\n {...props}\n >\n <SelectScrollUpButton />\n <SelectPrimitive.Viewport\n className={cn(\n position === 'popper' &&\n 'h-[var(--radix-select-content-available-height)] w-full'\n )}\n >\n {children}\n </SelectPrimitive.Viewport>\n <SelectScrollDownButton />\n </SelectPrimitive.Content>\n </SelectStyleContext.Provider>\n </SelectPrimitive.Portal>\n )\n})\nSelectContent.displayName = SelectPrimitive.Content.displayName\n\n// Item — a single selectable item (with right-aligned check indicator)\nconst SelectItem = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Item>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => {\n const { contentRadius, itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n 'relative flex w-full cursor-default select-none items-center outline-none',\n itemSizeMap[itemSize],\n !flush && itemRadiusMap[contentRadius],\n flush && flushItemPaddingMap[itemSize],\n 'transition-colors duration-fast',\n 'focus:bg-background-muted',\n 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',\n className\n )}\n {...props}\n >\n <SelectPrimitive.ItemText className=\"truncate\">{children}</SelectPrimitive.ItemText>\n <span className={cn('absolute flex items-center justify-center', flush ? flushIndicatorSizeMap[itemSize] : indicatorSizeMap[itemSize])}>\n <SelectPrimitive.ItemIndicator>\n <svg className=\"icon-xs\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3} aria-hidden=\"true\">\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n </SelectPrimitive.ItemIndicator>\n </span>\n </SelectPrimitive.Item>\n )\n})\nSelectItem.displayName = SelectPrimitive.Item.displayName\n\n// Label — non-interactive group heading\nconst SelectLabel = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Label>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>\n>(({ className, ...props }, ref) => {\n const { itemSize, flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Label\n ref={ref}\n className={cn(\n 'font-semibold text-text-muted',\n labelSizeMap[itemSize],\n flush && flushLabelPaddingMap[itemSize],\n className\n )}\n {...props}\n />\n )\n})\nSelectLabel.displayName = SelectPrimitive.Label.displayName\n\n// Separator — visual divider between groups\nconst SelectSeparator = React.forwardRef<\n React.ElementRef<typeof SelectPrimitive.Separator>,\n React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>\n>(({ className, ...props }, ref) => {\n const { flush } = React.useContext(SelectStyleContext)\n return (\n <SelectPrimitive.Separator\n ref={ref}\n className={cn('h-px bg-border my-1', !flush && '-mx-1', className)}\n {...props}\n />\n )\n})\nSelectSeparator.displayName = SelectPrimitive.Separator.displayName\n\nexport type { SelectRadius, SelectSize }\n\nexport {\n Select,\n SelectTrigger,\n SelectValue,\n SelectContent,\n SelectItem,\n SelectGroup,\n SelectLabel,\n SelectSeparator,\n}\n"],"mappings":";;;;;;;;;;AAEA,YAAY,WAAW;AACvB,YAAY,qBAAqB;AAOjC,IAAM,mBAAiD;AAAA,EACrD,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AACR;AAKA,IAAM,wBAAmE;AAAA,EACvE,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,OAAO;AAAA,EACP,MAAM;AACR;AAEA,IAAM,mBAAwD;AAAA,EAC5D,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AACN;AAEA,IAAM,gBAAqD;AAAA,EACzD,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AACN;AAMA,IAAM,iBAA6C;AAAA,EACjD,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,SAAS;AAAA;AAAA,EACT,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AACN;AAGA,IAAM,qBAAiD;AAAA,EACrD,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,SAAS;AAAA;AAAA,EACT,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AACN;AAKA,IAAM,sBAA0D;AAAA,EAC9D,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,cAA8C;AAAA,EAClD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,mBAAmD;AAAA,EACvD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,eAA+C;AAAA,EACnD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,sBAAsD;AAAA,EAC1D,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,IAAM,wBAAwD;AAAA,EAC5D,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,IAAM,uBAAuD;AAAA,EAC3D,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,oBAA0B,oBAG7B,EAAE,MAAM,WAAW,QAAQ,UAAU,CAAC;AAGzC,IAAM,qBAA2B,oBAI9B,EAAE,eAAe,MAAM,UAAU,MAAM,OAAO,MAAM,CAAC;AAIxD,IAAM,SAAS,CAAC;AAAA,EACd,OAAO;AAAA,EACP,SAAS;AAAA,EACT;AAAA,EACA,GAAG;AACL,MAGM;AACJ,QAAM,eAAe,gBAAgB;AACrC,SACE,oCAAC,kBAAkB,UAAlB,EAA2B,OAAO,EAAE,MAAM,OAAO,KAChD,oCAAiB,sBAAhB,EAAqB,UAAU,YAAY,cAAc,UAAW,GAAG,OAAO,CACjF;AAEJ;AAGA,IAAM,cAA8B;AAGpC,IAAM,cAA8B;AAGpC,IAAM,gBAAsB,iBAG1B,CAAC,EAAE,WAAW,UAAU,IAAI,GAAG,MAAM,GAAG,QAAQ;AAChD,QAAM,EAAE,MAAM,OAAO,IAAU,iBAAW,iBAAiB;AAE3D,QAAM,eAAe,gBAAgB;AACrC,kBAAgB,UAAU,QAAQ,YAAY,KAAK,CAAC,EAAE;AACtD,SACE;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,IAAI,MAAM,cAAc;AAAA,MACxB,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,iBAAiB,MAAM;AAAA,QACvB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe,IAAI;AAAA,QACnB;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,IAEH;AAAA,IACD,oCAAiB,sBAAhB,EAAqB,SAAO,QAC3B;AAAA,MAAC;AAAA;AAAA,QACC,WAAW,GAAG,iCAAiC,mBAAmB,IAAI,CAAC;AAAA,QACvE,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,QAAO;AAAA,QACP,aAAa;AAAA,QACb,eAAY;AAAA;AAAA,MAEZ,oCAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB;AAAA,IACxE,CACF;AAAA,EACF;AAEJ,CAAC;AACD,cAAc,cAA8B,wBAAQ;AAGpD,IAAM,uBAA6B,iBAGjC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,wDAAwD,SAAS;AAAA,IAC9E,GAAG;AAAA;AAAA,EAEJ,oCAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAAG,eAAY,UACzG,oCAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,iBAAgB,CACvE;AACF,CACD;AACD,qBAAqB,cAA8B,+BAAe;AAGlE,IAAM,yBAA+B,iBAGnC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,wDAAwD,SAAS;AAAA,IAC9E,GAAG;AAAA;AAAA,EAEJ,oCAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAAG,eAAY,UACzG,oCAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB,CACxE;AACF,CACD;AACD,uBAAuB,cAA8B,iCAAiB;AAGtE,IAAM,gBAAsB,iBAK1B,CAAC,EAAE,WAAW,UAAU,WAAW,UAAU,aAAa,GAAG,QAAQ,OAAO,kBAAkB,GAAG,MAAM,GAAG,QAAQ;AAClH,QAAM,EAAE,MAAM,OAAO,IAAU,iBAAW,iBAAiB;AAC3D,QAAM,WAAW,oBAAoB,IAAI;AACzC,QAAM,gBAAgB,sBAAsB,MAAM;AAClD,SACE,oCAAiB,wBAAhB,MACC,oCAAC,mBAAmB,UAAnB,EAA4B,OAAO,EAAE,eAAe,UAAU,MAAM,KACnE;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,kBAAkB,CAAC,MAAM;AACvB,UAAE,eAAe;AACjB,2BAAmB,CAAC;AAAA,MACtB;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,QAAQ,SAAS;AAAA,QACjB,iBAAiB,aAAa;AAAA,QAC9B,aAAa,YACX;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,MACC,GAAG;AAAA;AAAA,IAEJ,oCAAC,0BAAqB;AAAA,IACtB;AAAA,MAAiB;AAAA,MAAhB;AAAA,QACC,WAAW;AAAA,UACT,aAAa,YACX;AAAA,QACJ;AAAA;AAAA,MAEC;AAAA,IACH;AAAA,IACA,oCAAC,4BAAuB;AAAA,EAC1B,CACF,CACF;AAEJ,CAAC;AACD,cAAc,cAA8B,wBAAQ;AAGpD,IAAM,aAAmB,iBAGvB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QAAQ;AAC5C,QAAM,EAAE,eAAe,UAAU,MAAM,IAAU,iBAAW,kBAAkB;AAC9E,SACE;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,YAAY,QAAQ;AAAA,QACpB,CAAC,SAAS,cAAc,aAAa;AAAA,QACrC,SAAS,oBAAoB,QAAQ;AAAA,QACrC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,IAEJ,oCAAiB,0BAAhB,EAAyB,WAAU,cAAY,QAAS;AAAA,IACzD,oCAAC,UAAK,WAAW,GAAG,6CAA6C,QAAQ,sBAAsB,QAAQ,IAAI,iBAAiB,QAAQ,CAAC,KACnI,oCAAiB,+BAAhB,MACC,oCAAC,SAAI,WAAU,WAAU,MAAK,QAAO,SAAQ,aAAY,QAAO,gBAAe,aAAa,GAAG,eAAY,UACzG,oCAAC,UAAK,eAAc,SAAQ,gBAAe,SAAQ,GAAE,kBAAiB,CACxE,CACF,CACF;AAAA,EACF;AAEJ,CAAC;AACD,WAAW,cAA8B,qBAAK;AAG9C,IAAM,cAAoB,iBAGxB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAAQ;AAClC,QAAM,EAAE,UAAU,MAAM,IAAU,iBAAW,kBAAkB;AAC/D,SACE;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,aAAa,QAAQ;AAAA,QACrB,SAAS,qBAAqB,QAAQ;AAAA,QACtC;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;AACD,YAAY,cAA8B,sBAAM;AAGhD,IAAM,kBAAwB,iBAG5B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAAQ;AAClC,QAAM,EAAE,MAAM,IAAU,iBAAW,kBAAkB;AACrD,SACE;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW,GAAG,uBAAuB,CAAC,SAAS,SAAS,SAAS;AAAA,MAChE,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;AACD,gBAAgB,cAA8B,0BAAU;","names":[]}
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import {
3
- useFieldContext
4
- } from "./chunk-Z6JWWCNL.mjs";
3
+ useFieldContext,
4
+ useFieldControl
5
+ } from "./chunk-T5A4APEL.mjs";
5
6
  import {
6
7
  cn
7
8
  } from "./chunk-53MIUPSY.mjs";
@@ -84,7 +85,9 @@ var Switch = React.forwardRef(({ className, size, label, labelPosition = "end",
84
85
  const resolvedSize = size || "default";
85
86
  const resolvedDisabled = disabled ?? fieldContext?.disabled;
86
87
  const generatedId = React.useId();
87
- const switchId = id ?? fieldContext?.id ?? generatedId;
88
+ const hasOwnLabel = Boolean(label || startLabel || endLabel);
89
+ const switchId = id ?? (hasOwnLabel ? generatedId : fieldContext?.id ?? generatedId);
90
+ useFieldControl(hasOwnLabel ? "group" : "single", Boolean(fieldContext) && (hasOwnLabel || !id));
88
91
  const switchEl = /* @__PURE__ */ React.createElement(
89
92
  SwitchPrimitive.Root,
90
93
  {
@@ -142,4 +145,4 @@ export {
142
145
  switchVariants,
143
146
  Switch
144
147
  };
145
- //# sourceMappingURL=chunk-DRVHHEAY.mjs.map
148
+ //# sourceMappingURL=chunk-ND6TUVP2.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/switch.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport * as SwitchPrimitive from '@radix-ui/react-switch'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\n// Switch track variants\nconst switchVariants = cva(\n [\n 'group peer inline-flex shrink-0 cursor-pointer items-center rounded-full',\n 'border border-transparent transition-all duration-normal ease-out',\n 'focus-visible:focus-ring',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'data-[state=unchecked]:bg-border',\n ].join(' '),\n {\n variants: {\n size: {\n sm: 'w-[var(--component-switch-track-sm-width)] h-[var(--component-switch-track-sm-height)]',\n default: 'w-[var(--component-switch-track-default-width)] h-[var(--component-switch-track-default-height)]',\n lg: 'w-[var(--component-switch-track-lg-width)] h-[var(--component-switch-track-lg-height)]',\n },\n },\n defaultVariants: {\n size: 'default',\n },\n }\n)\n\n// Thumb sizes\nconst thumbSizes = {\n sm: 'w-[var(--component-switch-thumb-sm)] h-[var(--component-switch-thumb-sm)]',\n default: 'w-[var(--component-switch-thumb-default)] h-[var(--component-switch-thumb-default)]',\n lg: 'w-[var(--component-switch-thumb-lg)] h-[var(--component-switch-thumb-lg)]',\n}\n\n// Thumb translate when checked: track_width - thumb_size - 2px (border 1px × 2)\nconst thumbTranslate = {\n sm: 'data-[state=checked]:translate-x-[calc(var(--component-switch-track-sm-width)_-_var(--component-switch-thumb-sm)_-_2px)]',\n default: 'data-[state=checked]:translate-x-[calc(var(--component-switch-track-default-width)_-_var(--component-switch-thumb-default)_-_2px)]',\n lg: 'data-[state=checked]:translate-x-[calc(var(--component-switch-track-lg-width)_-_var(--component-switch-thumb-lg)_-_2px)]',\n}\n\n// Gap between switch and label\nconst gapSizes = {\n sm: 'gap-2', // 8px\n default: 'gap-2.5', // 10px\n lg: 'gap-3', // 12px\n}\n\n// Label font sizes\nconst labelSizes = {\n sm: 'text-xs', // 12px\n default: 'text-md', // 14px\n lg: 'text-base', // 16px\n}\n\nexport type SwitchLabelPosition = 'start' | 'end' | 'top' | 'bottom'\nexport type SwitchColor = 'default' | 'primary' | 'success' | 'warning' | 'error'\n\n// Checked track color per color variant\nconst checkedTrackColors: Record<SwitchColor, string> = {\n default: 'data-[state=checked]:bg-foreground',\n primary: 'data-[state=checked]:bg-primary',\n success: 'data-[state=checked]:bg-success',\n warning: 'data-[state=checked]:bg-warning',\n error: 'data-[state=checked]:bg-error',\n}\n\n// Checked icon color per color variant\nconst checkedIconColors: Record<SwitchColor, string> = {\n default: 'text-foreground',\n primary: 'text-primary',\n success: 'text-success',\n warning: 'text-warning',\n error: 'text-error',\n}\n\n// Icon sizes per thumb size\nconst iconSizes = {\n sm: 'hidden', // 12px thumb — too small for icons\n default: 'w-2.5 h-2.5', // 10px icon in 16px thumb\n lg: 'w-3.5 h-3.5', // 14px icon in 20px thumb\n}\n\nexport interface SwitchProps\n extends React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>,\n VariantProps<typeof switchVariants> {\n label?: string\n labelPosition?: SwitchLabelPosition\n startLabel?: string\n endLabel?: string\n checkedIcon?: React.ReactNode\n uncheckedIcon?: React.ReactNode\n color?: SwitchColor\n}\n\nconst Switch = React.forwardRef<\n React.ElementRef<typeof SwitchPrimitive.Root>,\n SwitchProps\n>(({ className, size, label, labelPosition = 'end', startLabel, endLabel, checkedIcon, uncheckedIcon, color = 'default', disabled, id, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedSize = size || 'default'\n const resolvedDisabled = disabled ?? fieldContext?.disabled\n const generatedId = React.useId()\n // With its own label the switch is one item of a group: keep a unique id. Only a\n // bare switch labelled by FieldLabel takes the Field id.\n const hasOwnLabel = Boolean(label || startLabel || endLabel)\n const switchId = id ?? (hasOwnLabel ? generatedId : fieldContext?.id ?? generatedId)\n useFieldControl(hasOwnLabel ? 'group' : 'single', Boolean(fieldContext) && (hasOwnLabel || !id))\n\n const switchEl = (\n <SwitchPrimitive.Root\n ref={ref}\n id={switchId}\n disabled={resolvedDisabled}\n className={cn(switchVariants({ size }), checkedTrackColors[color], className)}\n {...props}\n >\n <SwitchPrimitive.Thumb\n className={cn(\n 'group/thumb pointer-events-none flex items-center justify-center rounded-full shadow-sm ring-0',\n color === 'default' ? 'bg-background' : 'bg-primary-foreground',\n 'transition-transform duration-normal ease-out',\n 'data-[state=unchecked]:translate-x-0',\n thumbSizes[resolvedSize],\n thumbTranslate[resolvedSize]\n )}\n >\n {(checkedIcon || uncheckedIcon) && resolvedSize !== 'sm' && (\n <>\n {checkedIcon && (\n <span className={cn(\n iconSizes[resolvedSize],\n checkedIconColors[color],\n 'hidden group-data-[state=checked]/thumb:block',\n )}>\n {checkedIcon}\n </span>\n )}\n {uncheckedIcon && (\n <span className={cn(\n iconSizes[resolvedSize],\n 'text-text-muted',\n 'hidden group-data-[state=unchecked]/thumb:block',\n )}>\n {uncheckedIcon}\n </span>\n )}\n </>\n )}\n </SwitchPrimitive.Thumb>\n </SwitchPrimitive.Root>\n )\n\n const labelClassName = cn(\n labelSizes[resolvedSize],\n 'text-text-muted cursor-pointer select-none transition-colors duration-micro',\n 'group-hover/switch:text-foreground',\n resolvedDisabled && 'opacity-50 cursor-not-allowed'\n )\n\n // Sides mode: startLabel / endLabel\n if (startLabel || endLabel) {\n return (\n <div className={cn('group/switch flex items-center', gapSizes[resolvedSize])}>\n {startLabel && (\n <label htmlFor={switchId} className={labelClassName}>\n {startLabel}\n </label>\n )}\n <div className=\"flex items-center\">\n {switchEl}\n </div>\n {endLabel && (\n <label htmlFor={switchId} className={labelClassName}>\n {endLabel}\n </label>\n )}\n </div>\n )\n }\n\n if (!label) return switchEl\n\n const isVertical = labelPosition === 'top' || labelPosition === 'bottom'\n const isReversed = labelPosition === 'start' || labelPosition === 'top'\n\n return (\n <div className={cn(\n 'group/switch flex',\n isVertical ? 'flex-col items-start gap-1.5' : 'items-center',\n isReversed && (isVertical ? 'flex-col-reverse' : 'flex-row-reverse'),\n !isVertical && gapSizes[resolvedSize],\n )}>\n <div className=\"flex items-center\">\n {switchEl}\n </div>\n <label htmlFor={switchId} className={labelClassName}>\n {label}\n </label>\n </div>\n )\n})\nSwitch.displayName = 'Switch'\n\nexport { Switch, switchVariants }\n"],"mappings":"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","names":[]}
@@ -249,4 +249,4 @@ export {
249
249
  ChatMessageContent,
250
250
  ChatMessageFooter
251
251
  };
252
- //# sourceMappingURL=chunk-234NAXGV.mjs.map
252
+ //# sourceMappingURL=chunk-R7FJEO4K.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/chat-message.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar'\nimport { TypingIndicator, type TypingIndicatorProps } from '@/components/ui/typing-indicator'\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ChatMessageRole = 'user' | 'assistant'\nexport type ChatMessageVariant = 'bubble' | 'flat'\nexport type ChatMessageColor = 'default' | 'muted' | 'primary' | 'dark'\nexport type ChatMessageSize = 'sm' | 'default' | 'lg'\nexport type ChatMessageRadius = 'md' | 'lg' | 'xl' | '2xl'\nexport type ChatMessageAvatarSize = 'sm' | 'md' | 'lg'\n\n/** Built-in status presets (pass as string to Footer.status for auto-rendering) */\nexport type ChatMessageStatus = 'sending' | 'sent' | 'read' | 'error'\n\n// ============================================================================\n// Context — propagates root props to sub-components\n// ============================================================================\n\ninterface ChatMessageContextValue {\n role: ChatMessageRole\n variant: ChatMessageVariant\n color: ChatMessageColor\n size: ChatMessageSize\n radius: ChatMessageRadius\n tail: boolean\n typing: boolean | Omit<TypingIndicatorProps, 'className'>\n actions?: React.ReactNode\n}\n\nconst ChatMessageContext = React.createContext<ChatMessageContextValue>({\n role: 'assistant',\n variant: 'bubble',\n color: 'default',\n size: 'default',\n radius: '2xl',\n tail: true,\n typing: false,\n actions: undefined,\n})\n\n// ============================================================================\n// Size maps\n// ============================================================================\n\n/** Bubble padding per size */\nconst bubblePaddingMap: Record<ChatMessageSize, string> = {\n sm: 'px-3 py-1.5',\n default: 'px-3.5 py-2',\n lg: 'px-4 py-2.5',\n}\n\n/** Bubble text class per size */\nconst bubbleTextMap: Record<ChatMessageSize, string> = {\n sm: 'text-sm',\n default: 'text-md',\n lg: 'text-base',\n}\n\n/** Footer text size per size */\nconst footerTextMap: Record<ChatMessageSize, string> = {\n sm: 'text-2xs',\n default: 'text-2xs',\n lg: 'text-xs',\n}\n\n/** Gap between avatar and content per message size */\nconst rowGapMap: Record<ChatMessageSize, string> = {\n sm: 'gap-2',\n default: 'gap-2.5',\n lg: 'gap-3',\n}\n\n/** Gap override when avatarSize is explicitly set */\nconst avatarGapMap: Record<ChatMessageAvatarSize, string> = {\n sm: 'gap-1.5',\n md: 'gap-2.5',\n lg: 'gap-3',\n}\n\n// ============================================================================\n// Chat avatar sizes (independent from message size)\n// ============================================================================\n\nconst chatAvatarSizeMap: Record<ChatMessageAvatarSize, string> = {\n sm: 'w-6 h-6', // 24px\n md: 'w-7 h-7', // 28px\n lg: 'w-8 h-8', // 32px\n}\n\nconst chatAvatarFontMap: Record<ChatMessageAvatarSize, string> = {\n sm: 'text-2xs',\n md: 'text-2xs',\n lg: 'text-xs',\n}\n\n// ============================================================================\n// Bubble radius — static maps for Tailwind JIT scanner compatibility\n// ============================================================================\n\n/**\n * Asymmetric with tail: tail corner = rounded-none (0px).\n * assistant → tail at bottom-left | user → tail at bottom-right\n */\nconst bubbleRadiusTailMap: Record<ChatMessageRadius, Record<ChatMessageRole, string>> = {\n md: { assistant: 'rounded-tl-md rounded-tr-md rounded-br-md rounded-bl-none', user: 'rounded-tl-md rounded-tr-md rounded-br-none rounded-bl-md' },\n lg: { assistant: 'rounded-tl-lg rounded-tr-lg rounded-br-lg rounded-bl-none', user: 'rounded-tl-lg rounded-tr-lg rounded-br-none rounded-bl-lg' },\n xl: { assistant: 'rounded-tl-xl rounded-tr-xl rounded-br-xl rounded-bl-none', user: 'rounded-tl-xl rounded-tr-xl rounded-br-none rounded-bl-xl' },\n '2xl': { assistant: 'rounded-tl-2xl rounded-tr-2xl rounded-br-2xl rounded-bl-none', user: 'rounded-tl-2xl rounded-tr-2xl rounded-br-none rounded-bl-2xl' },\n}\n\n/** Symmetric: all corners same radius */\nconst bubbleRadiusSymMap: Record<ChatMessageRadius, string> = {\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n}\n\n// ============================================================================\n// Bubble color helper — applies to both roles uniformly\n// ============================================================================\n\nfunction getBubbleColors(color: ChatMessageColor, variant: ChatMessageVariant): string {\n if (variant === 'flat') {\n return color === 'muted' ? 'bg-background-muted text-foreground' : 'text-foreground'\n }\n switch (color) {\n case 'default': return 'bg-background-paper border border-border text-foreground'\n case 'muted': return 'bg-background-muted text-foreground'\n case 'primary': return 'bg-primary text-primary-foreground'\n case 'dark': return 'bg-foreground text-background'\n }\n}\n\n// ============================================================================\n// Built-in status labels\n// ============================================================================\n\nconst builtInStatusLabels: Record<string, { label: string; className: string }> = {\n sending: { label: 'Sending...', className: 'text-text-subtle' },\n sent: { label: 'Sent', className: 'text-text-subtle' },\n read: { label: 'Read', className: 'text-text-subtle' },\n error: { label: 'Failed', className: 'text-error' },\n}\n\n// ============================================================================\n// TypingIndicator size mapping (chat sizes → indicator sizes)\n// ============================================================================\n\nconst typingSizeMap: Record<ChatMessageSize, 'sm' | 'default' | 'lg'> = {\n sm: 'sm',\n default: 'sm',\n lg: 'default',\n}\n\n/** Minimum bubble width when typing — accounts for dot size + padding per chat size */\nconst typingMinWidthMap: Record<ChatMessageSize, string> = {\n sm: 'min-w-12',\n default: 'min-w-12',\n lg: 'min-w-16',\n}\n\n// ============================================================================\n// Props interfaces\n// ============================================================================\n\nexport interface ChatMessageRootProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Sender role — controls alignment (left=assistant, right=user) */\n role?: ChatMessageRole\n /** Bubble visual style */\n variant?: ChatMessageVariant\n /** Bubble background color */\n color?: ChatMessageColor\n /** Size scale — affects text and padding */\n size?: ChatMessageSize\n /** Bubble corner radius */\n radius?: ChatMessageRadius\n /** Asymmetric tail corner (radius=0 on the avatar side) */\n tail?: boolean\n /** Show typing indicator inside Content. Pass true for defaults, or TypingIndicatorProps for custom. */\n typing?: boolean | Omit<TypingIndicatorProps, 'className'>\n /** Avatar size — overrides default gap between avatar and bubble */\n avatarSize?: ChatMessageAvatarSize\n /** Action buttons revealed on hover */\n actions?: React.ReactNode\n}\n\nexport interface ChatMessageAvatarProps {\n /** Avatar size: sm(24px), md(28px), lg(32px) */\n size?: ChatMessageAvatarSize\n /** Image URL */\n src?: string\n /** Alt text for avatar image */\n alt?: string\n /** Initials to display when no image (1–2 characters) */\n initials?: string\n /** Custom icon or ReactNode to render inside the avatar */\n icon?: React.ReactNode\n /** Additional CSS classes */\n className?: string\n}\n\nexport interface ChatMessageContentProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport interface ChatMessageFooterProps extends React.HTMLAttributes<HTMLDivElement> {\n /** Pre-formatted timestamp string (e.g. \"12:34 PM\") */\n timestamp?: string\n /** Status: built-in preset ('sending' | 'sent' | 'read' | 'error') or custom ReactNode */\n status?: React.ReactNode\n /** Size override (defaults to context value from ChatMessage root) */\n size?: ChatMessageSize\n}\n\n// ============================================================================\n// ChatMessage Root\n// ============================================================================\n\nconst ChatMessage = React.forwardRef<HTMLDivElement, ChatMessageRootProps>(\n (\n {\n className,\n role = 'assistant',\n variant = 'bubble',\n color = 'default',\n size = 'default',\n radius = '2xl',\n tail = true,\n typing = false,\n avatarSize,\n actions,\n children,\n ...props\n },\n ref\n ) => {\n const ctx = React.useMemo<ChatMessageContextValue>(\n () => ({ role, variant, color, size, radius, tail, typing, actions }),\n [role, variant, color, size, radius, tail, typing, actions]\n )\n\n const gapClass = avatarSize ? avatarGapMap[avatarSize] : rowGapMap[size]\n\n return (\n <ChatMessageContext.Provider value={ctx}>\n <div\n ref={ref}\n className={cn(\n 'group/message flex items-end',\n gapClass,\n role === 'user' && variant !== 'flat' ? 'flex-row-reverse' : 'flex-row',\n className\n )}\n {...props}\n >\n {children}\n </div>\n </ChatMessageContext.Provider>\n )\n }\n)\nChatMessage.displayName = 'ChatMessage'\n\n// ============================================================================\n// Default AI sparkle icon\n// ============================================================================\n\nfunction DefaultAiIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-3/5 h-3/5\" aria-hidden=\"true\">\n <path d=\"M12 3l1.8 5.4 5.4 1.8-5.4 1.8L12 17.4l-1.8-5.4L4.8 10.2l5.4-1.8z\" />\n <path d=\"M19.5 3.5l.8 2.4 2.4.8-2.4.8L19.5 10l-.8-2.5-2.4-.8 2.4-.8z\" opacity=\".6\" />\n <path d=\"M4.5 14.5l.7 2 2 .7-2 .7L4.5 20l-.7-2-2-.7 2-.7z\" opacity=\".4\" />\n </svg>\n )\n}\n\n// ============================================================================\n// ChatMessageAvatar — wraps Avatar component with chat-specific sizes\n// ============================================================================\n\nconst ChatMessageAvatar = React.forwardRef<HTMLSpanElement, ChatMessageAvatarProps>(\n ({ className, size: avatarSize = 'md', src, alt = 'Avatar', initials, icon }, ref) => (\n <Avatar\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ref={ref as any}\n aria-hidden=\"true\"\n className={cn(chatAvatarSizeMap[avatarSize], 'shrink-0', className)}\n >\n {src && <AvatarImage src={src} alt={alt} />}\n <AvatarFallback className={cn('font-semibold', chatAvatarFontMap[avatarSize])}>\n {icon ?? (initials || <DefaultAiIcon />)}\n </AvatarFallback>\n </Avatar>\n )\n)\nChatMessageAvatar.displayName = 'ChatMessageAvatar'\n\n// ============================================================================\n// ChatMessageContent\n// ============================================================================\n\nconst ChatMessageContent = React.forwardRef<HTMLDivElement, ChatMessageContentProps>(\n ({ className, children, ...props }, ref) => {\n const { role, variant, color, size, radius, tail, typing, actions } = React.useContext(ChatMessageContext)\n const isTyping = !!typing\n const typingProps = typeof typing === 'object' ? typing : {}\n\n // Dark bubble backgrounds need inverted typing dot colors\n const isDarkBg = color === 'primary' || color === 'dark'\n const invertDots = variant === 'bubble' && isDarkBg\n\n // flat variant never has a tail (asymmetric corner)\n const effectiveTail = variant === 'flat' ? false : tail\n const radiusClasses = effectiveTail\n ? bubbleRadiusTailMap[radius][role]\n : bubbleRadiusSymMap[radius]\n\n const bubble = (\n <div\n ref={ref}\n className={cn(\n bubbleTextMap[size],\n variant === 'bubble' && 'max-w-[75%]',\n isTyping && [typingMinWidthMap[size], 'text-center'],\n getBubbleColors(color, variant),\n (variant === 'bubble' || variant === 'flat') && bubblePaddingMap[size],\n (variant === 'bubble' || (variant === 'flat' && color === 'muted')) && radiusClasses,\n className\n )}\n {...props}\n >\n {isTyping ? (\n <TypingIndicator\n size={typingSizeMap[size]}\n color=\"muted\"\n {...typingProps}\n className={cn('align-middle', invertDots && '[&>div>div]:bg-current')}\n />\n ) : children}\n </div>\n )\n\n if (!actions) return bubble\n\n return (\n <div className={cn('flex items-end gap-1.5', role === 'user' && variant !== 'flat' ? 'flex-row-reverse' : 'flex-row')}>\n {bubble}\n <div className={cn(\n 'shrink-0 flex items-center gap-1 pb-0.5',\n 'opacity-0 group-hover/message:opacity-100',\n 'transition-opacity duration-normal',\n )}>\n {actions}\n </div>\n </div>\n )\n }\n)\nChatMessageContent.displayName = 'ChatMessageContent'\n\n// ============================================================================\n// ChatMessageFooter\n// ============================================================================\n\nconst ChatMessageFooter = React.forwardRef<HTMLDivElement, ChatMessageFooterProps>(\n (\n {\n className,\n timestamp,\n status,\n role: roleProp,\n size: sizeProp,\n children,\n ...props\n },\n ref\n ) => {\n const ctx = React.useContext(ChatMessageContext)\n const role = roleProp ?? ctx.role\n const size = sizeProp ?? ctx.size\n const variant = ctx.variant\n\n // Resolve status: built-in preset string → label, or pass-through ReactNode\n const statusContent = React.useMemo(() => {\n if (status == null) return null\n if (typeof status === 'string' && status in builtInStatusLabels) {\n const { label, className: cls } = builtInStatusLabels[status]\n return <span className={cls}>{label}</span>\n }\n return status\n }, [status])\n\n return (\n <div\n ref={ref}\n className={cn(\n 'flex items-center gap-1 select-none',\n footerTextMap[size],\n 'text-text-subtle',\n role === 'user' && variant !== 'flat' ? 'justify-end' : 'justify-start',\n className\n )}\n {...props}\n >\n {children}\n {statusContent}\n {timestamp && <span>{timestamp}</span>}\n </div>\n )\n }\n)\nChatMessageFooter.displayName = 'ChatMessageFooter'\n\nexport {\n ChatMessage,\n ChatMessageAvatar,\n ChatMessageContent,\n ChatMessageFooter,\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
  import {
3
- useFieldContext
4
- } from "./chunk-Z6JWWCNL.mjs";
3
+ useFieldContext,
4
+ useFieldControl
5
+ } from "./chunk-T5A4APEL.mjs";
5
6
  import {
6
7
  cn
7
8
  } from "./chunk-53MIUPSY.mjs";
@@ -119,6 +120,7 @@ var Input = React.forwardRef(
119
120
  const resolvedError = error ?? fieldContext?.error;
120
121
  const resolvedState = resolvedError ? "error" : state;
121
122
  const inputId = id ?? fieldContext?.id;
123
+ useFieldControl("single", Boolean(fieldContext) && !id);
122
124
  const isDisabled = props.disabled ?? fieldContext?.disabled;
123
125
  const pointerRef = React.useRef(false);
124
126
  const windowBlurredRef = React.useRef(false);
@@ -219,4 +221,4 @@ export {
219
221
  inputVariants,
220
222
  Input
221
223
  };
222
- //# sourceMappingURL=chunk-WWSN5YME.mjs.map
224
+ //# sourceMappingURL=chunk-SDDAGZWA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/input.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\nimport { useFieldContext, useFieldControl } from './field'\n\nconst inputVariants = cva(\n [\n 'flex w-full bg-background text-foreground placeholder:text-foreground/30',\n 'border transition-colors duration-micro outline-transparent',\n 'focus:[outline:2px_solid_transparent]',\n 'disabled:cursor-not-allowed disabled:opacity-50 disabled:bg-background-muted',\n 'file:border-0 file:bg-transparent file:text-sm file:font-semibold',\n ].join(' '),\n {\n variants: {\n variant: {\n default: 'border-border hover:border-border-strong',\n filled: 'border-transparent bg-background-muted',\n },\n focusRing: {\n true: '',\n false: '',\n },\n size: {\n xs: 'h-9 px-3 text-sm', // 36px / 12px padding / 13px font (3.0:1)\n sm: 'h-10 px-3 text-md', // 40px / 12px padding / 14px font (3.3:1)\n default: 'h-11 px-4 text-base', // 44px / 16px padding / 16px font (2.75:1)\n lg: 'h-12 px-4 text-base', // 48px / 16px padding / 16px font (3.0:1)\n xl: 'h-14 px-4 text-base', // 56px / 16px padding / 16px font (3.5:1)\n },\n radius: {\n none: 'rounded-none',\n sm: 'rounded-sm',\n base: 'rounded',\n default: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n '3xl': 'rounded-3xl',\n full: 'rounded-full',\n },\n state: {\n default: '',\n error: 'border-error hover:border-error focus:border-error shadow-[0_0_0_2px_var(--color-focus-ring-error)]',\n },\n },\n compoundVariants: [\n // focusRing: true → show custom focus ring\n { focusRing: true, className: 'focus-visible:shadow-[0_0_0_2px_var(--color-focus-ring)]' },\n // focusRing: false → keep same state as hover\n { variant: 'default', focusRing: false, className: 'focus:border-border-strong' },\n // filled + error\n {\n variant: 'filled',\n state: 'error',\n className: 'border-transparent hover:border-transparent focus:border-transparent bg-[var(--color-error-bg)] hover:bg-[var(--color-error-bg)] focus:bg-[var(--color-error-bg)] shadow-none',\n },\n ],\n defaultVariants: {\n variant: 'default',\n size: 'default',\n radius: 'default',\n state: 'default',\n focusRing: false,\n },\n }\n)\n\nexport interface InputProps\n extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'>,\n VariantProps<typeof inputVariants> {\n leftIcon?: React.ReactNode\n rightIcon?: React.ReactNode\n error?: boolean\n focusRing?: boolean\n}\n\n// Icon size for input (2-step scale)\n// xs~sm: 14px, default~xl: 16px\nconst iconSizeClasses = {\n xs: 'icon-xs', // 14px\n sm: 'icon-xs', // 14px\n default: 'icon-sm', // 16px\n lg: 'icon-sm', // 16px\n xl: 'icon-sm', // 16px\n}\n\n// Icon padding (padding + icon + gap)\nconst iconPaddingClasses = {\n xs: { left: 'pl-8', right: 'pr-8' }, // 12px + 14px icon + 6px gap = 32px\n sm: { left: 'pl-9', right: 'pr-9' }, // 12px + 14px icon + 8px gap = 34px → 36px\n default: { left: 'pl-10', right: 'pr-10' }, // 16px + 16px icon + 8px gap = 40px\n lg: { left: 'pl-10', right: 'pr-10' }, // 16px + 16px icon + 8px gap = 40px\n xl: { left: 'pl-10', right: 'pr-10' }, // 16px + 16px icon + 8px gap = 40px\n}\n\n// Icon position (matches horizontal padding)\nconst iconPositionClasses = {\n xs: { left: 'left-3', right: 'right-3' }, // 12px\n sm: { left: 'left-3', right: 'right-3' }, // 12px\n default: { left: 'left-4', right: 'right-4' }, // 16px\n lg: { left: 'left-4', right: 'right-4' }, // 16px\n xl: { left: 'left-4', right: 'right-4' }, // 16px\n}\n\nconst Input = React.forwardRef<HTMLInputElement, InputProps>(\n ({ className, variant, size, radius, state, type, leftIcon, rightIcon, error, focusRing, id, onPointerDown, onFocus, onBlur, ...props }, ref) => {\n const fieldContext = useFieldContext()\n const resolvedSize = size || 'default'\n const resolvedError = error ?? fieldContext?.error\n const resolvedState = resolvedError ? 'error' : state\n const inputId = id ?? fieldContext?.id\n useFieldControl('single', Boolean(fieldContext) && !id)\n const isDisabled = props.disabled ?? fieldContext?.disabled\n\n // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)\n const pointerRef = React.useRef(false)\n const windowBlurredRef = React.useRef(false)\n const [keyboardFocus, setKeyboardFocus] = React.useState(false)\n\n // Track window blur/focus to distinguish Tab navigation from window re-activation\n React.useEffect(() => {\n const onBlur = () => { windowBlurredRef.current = true }\n const onFocus = () => { requestAnimationFrame(() => { windowBlurredRef.current = false }) }\n window.addEventListener('blur', onBlur)\n window.addEventListener('focus', onFocus)\n return () => { window.removeEventListener('blur', onBlur); window.removeEventListener('focus', onFocus) }\n }, [])\n\n const handlePointerDown = React.useCallback((e: React.PointerEvent<HTMLInputElement>) => {\n pointerRef.current = true\n onPointerDown?.(e)\n }, [onPointerDown])\n\n const handleFocus = React.useCallback((e: React.FocusEvent<HTMLInputElement>) => {\n if (!pointerRef.current && !focusRing && !windowBlurredRef.current) {\n setKeyboardFocus(true)\n }\n pointerRef.current = false\n onFocus?.(e)\n }, [focusRing, onFocus])\n\n const handleBlur = React.useCallback((e: React.FocusEvent<HTMLInputElement>) => {\n setKeyboardFocus(false)\n pointerRef.current = false\n onBlur?.(e)\n }, [onBlur])\n\n // Build aria-describedby from context\n const ariaDescribedBy = fieldContext\n ? [\n resolvedError ? `${fieldContext.id}-error` : null,\n ]\n .filter(Boolean)\n .join(' ') || undefined\n : undefined\n\n const focusHandlers = {\n onPointerDown: handlePointerDown,\n onFocus: handleFocus,\n onBlur: handleBlur,\n }\n\n // If icons are present, wrap input in a container\n if (leftIcon || rightIcon) {\n return (\n <div className=\"relative w-full\">\n {leftIcon && (\n <div className={cn(\n 'absolute top-1/2 -translate-y-1/2 pointer-events-none text-text-muted z-10',\n iconPositionClasses[resolvedSize].left,\n `[&>svg]:${iconSizeClasses[resolvedSize]}`\n )}>\n {leftIcon}\n </div>\n )}\n <input\n type={type}\n id={inputId}\n className={cn(\n inputVariants({ variant, size, radius, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n leftIcon && iconPaddingClasses[resolvedSize].left,\n rightIcon && iconPaddingClasses[resolvedSize].right,\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n {...focusHandlers}\n {...props}\n />\n {rightIcon && (\n <div className={cn(\n 'absolute top-1/2 -translate-y-1/2 pointer-events-none text-text-muted z-10',\n iconPositionClasses[resolvedSize].right,\n `[&>svg]:${iconSizeClasses[resolvedSize]}`\n )}>\n {rightIcon}\n </div>\n )}\n </div>\n )\n }\n\n return (\n <input\n type={type}\n id={inputId}\n className={cn(\n inputVariants({ variant, size, radius, state: resolvedState, focusRing }),\n keyboardFocus && 'shadow-[0_0_0_2px_var(--color-focus-ring)]',\n className\n )}\n aria-invalid={resolvedError || undefined}\n aria-describedby={ariaDescribedBy}\n disabled={isDisabled}\n ref={ref}\n {...focusHandlers}\n {...props}\n />\n )\n }\n)\nInput.displayName = 'Input'\n\nexport { Input, inputVariants }\n"],"mappings":"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","names":["onBlur","onFocus"]}
@@ -10,6 +10,14 @@ var FieldContext = React.createContext(null);
10
10
  function useFieldContext() {
11
11
  return React.useContext(FieldContext);
12
12
  }
13
+ function useFieldControl(kind, enabled) {
14
+ const context = useFieldContext();
15
+ const register = context?.registerControl;
16
+ React.useEffect(() => {
17
+ if (!enabled || !register) return;
18
+ return register(kind);
19
+ }, [enabled, register, kind]);
20
+ }
13
21
  var fieldVariants = cva("flex flex-col", {
14
22
  variants: {
15
23
  gap: {
@@ -27,10 +35,30 @@ var fieldVariants = cva("flex flex-col", {
27
35
  var Field = React.forwardRef(
28
36
  ({ className, gap, error, disabled, children, ...props }, ref) => {
29
37
  const id = React.useId();
30
- return /* @__PURE__ */ React.createElement(FieldContext.Provider, { value: { id, error, disabled } }, /* @__PURE__ */ React.createElement(
38
+ const labelId = `${id}-label`;
39
+ const [labelCount, setLabelCount] = React.useState(0);
40
+ const [counts, setCounts] = React.useState({ single: 0, group: 0, labelled: 0 });
41
+ const registerLabel = React.useCallback(() => {
42
+ setLabelCount((n) => n + 1);
43
+ return () => setLabelCount((n) => n - 1);
44
+ }, []);
45
+ const registerControl = React.useCallback((kind) => {
46
+ setCounts((c) => ({ ...c, [kind]: c[kind] + 1 }));
47
+ return () => setCounts((c) => ({ ...c, [kind]: c[kind] - 1 }));
48
+ }, []);
49
+ const hasLabel = labelCount > 0;
50
+ const isGroup = counts.single === 0 && (counts.group > 0 || counts.labelled > 0);
51
+ const asGroup = counts.single === 0 && counts.group > 0;
52
+ const contextValue = React.useMemo(
53
+ () => ({ id, labelId, error, disabled, hasLabel, isGroup, registerLabel, registerControl }),
54
+ [id, labelId, error, disabled, hasLabel, isGroup, registerLabel, registerControl]
55
+ );
56
+ return /* @__PURE__ */ React.createElement(FieldContext.Provider, { value: contextValue }, /* @__PURE__ */ React.createElement(
31
57
  "div",
32
58
  {
33
59
  ref,
60
+ role: asGroup ? "group" : void 0,
61
+ "aria-labelledby": asGroup && hasLabel ? labelId : void 0,
34
62
  className: cn(fieldVariants({ gap }), className),
35
63
  "data-error": error || void 0,
36
64
  "data-disabled": disabled || void 0,
@@ -44,11 +72,14 @@ Field.displayName = "Field";
44
72
  var FieldLabel = React.forwardRef(
45
73
  ({ className, required, children, ...props }, ref) => {
46
74
  const context = useFieldContext();
75
+ const registerLabel = context?.registerLabel;
76
+ React.useEffect(() => registerLabel?.(), [registerLabel]);
47
77
  return /* @__PURE__ */ React.createElement(
48
78
  "label",
49
79
  {
50
80
  ref,
51
- htmlFor: context?.id,
81
+ id: context?.labelId,
82
+ htmlFor: context && !context.isGroup ? context.id : void 0,
52
83
  className: cn(
53
84
  "text-md font-semibold text-foreground",
54
85
  // 14px - primary field identifier
@@ -100,9 +131,10 @@ FieldCharCount.displayName = "FieldCharCount";
100
131
 
101
132
  export {
102
133
  useFieldContext,
134
+ useFieldControl,
103
135
  Field,
104
136
  FieldLabel,
105
137
  FieldError,
106
138
  FieldCharCount
107
139
  };
108
- //# sourceMappingURL=chunk-Z6JWWCNL.mjs.map
140
+ //# sourceMappingURL=chunk-T5A4APEL.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/field.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\n// Field Context for sharing state between components\ninterface FieldContextValue {\n id: string\n /** id of the FieldLabel, for aria-labelledby on grouped controls */\n labelId: string\n error?: boolean\n disabled?: boolean\n /** A FieldLabel is rendered inside this Field */\n hasLabel: boolean\n /** The Field holds labelled checkboxes / switches / a radio group and no single input */\n isGroup: boolean\n registerLabel: () => () => void\n registerControl: (kind: FieldControlKind) => () => void\n}\n\ntype FieldControlKind = 'single' | 'group' | 'labelled'\n\nconst FieldContext = React.createContext<FieldContextValue | null>(null)\n\nfunction useFieldContext() {\n return React.useContext(FieldContext)\n}\n\n// Controls tell their Field what they are, so FieldLabel can point at the right thing.\n// 'single': one input that takes the Field id (Input, Textarea, a bare Checkbox / Switch);\n// FieldLabel targets it with htmlFor.\n// 'group': a Checkbox / Switch with its own label keeps a unique id; the Field becomes\n// role=\"group\" named by FieldLabel instead of every item sharing one id.\n// 'labelled': a RadioGroup names itself from FieldLabel (aria-labelledby).\n// A single input wins: with one present, FieldLabel keeps pointing at it.\nfunction useFieldControl(kind: FieldControlKind, enabled: boolean) {\n const context = useFieldContext()\n const register = context?.registerControl\n React.useEffect(() => {\n if (!enabled || !register) return\n return register(kind)\n }, [enabled, register, kind])\n}\n\n// Field wrapper\nconst fieldVariants = cva('flex flex-col', {\n variants: {\n gap: {\n none: 'gap-0',\n xs: 'gap-1',\n sm: 'gap-1.5',\n default: 'gap-2',\n lg: 'gap-3',\n },\n },\n defaultVariants: {\n gap: 'default',\n },\n})\n\nexport interface FieldProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof fieldVariants> {\n error?: boolean\n disabled?: boolean\n}\n\nconst Field = React.forwardRef<HTMLDivElement, FieldProps>(\n ({ className, gap, error, disabled, children, ...props }, ref) => {\n const id = React.useId()\n const labelId = `${id}-label`\n const [labelCount, setLabelCount] = React.useState(0)\n const [counts, setCounts] = React.useState({ single: 0, group: 0, labelled: 0 })\n\n const registerLabel = React.useCallback(() => {\n setLabelCount((n) => n + 1)\n return () => setLabelCount((n) => n - 1)\n }, [])\n const registerControl = React.useCallback((kind: FieldControlKind) => {\n setCounts((c) => ({ ...c, [kind]: c[kind] + 1 }))\n return () => setCounts((c) => ({ ...c, [kind]: c[kind] - 1 }))\n }, [])\n\n const hasLabel = labelCount > 0\n const isGroup = counts.single === 0 && (counts.group > 0 || counts.labelled > 0)\n const asGroup = counts.single === 0 && counts.group > 0\n const contextValue = React.useMemo(\n () => ({ id, labelId, error, disabled, hasLabel, isGroup, registerLabel, registerControl }),\n [id, labelId, error, disabled, hasLabel, isGroup, registerLabel, registerControl]\n )\n\n return (\n <FieldContext.Provider value={contextValue}>\n <div\n ref={ref}\n role={asGroup ? 'group' : undefined}\n aria-labelledby={asGroup && hasLabel ? labelId : undefined}\n className={cn(fieldVariants({ gap }), className)}\n data-error={error || undefined}\n data-disabled={disabled || undefined}\n {...props}\n >\n {children}\n </div>\n </FieldContext.Provider>\n )\n }\n)\nField.displayName = 'Field'\n\n// Field Label\nexport interface FieldLabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {\n required?: boolean\n}\n\nconst FieldLabel = React.forwardRef<HTMLLabelElement, FieldLabelProps>(\n ({ className, required, children, ...props }, ref) => {\n const context = useFieldContext()\n const registerLabel = context?.registerLabel\n React.useEffect(() => registerLabel?.(), [registerLabel])\n\n return (\n <label\n ref={ref}\n id={context?.labelId}\n // Grouped controls have their own labels; the group title targets no input\n htmlFor={context && !context.isGroup ? context.id : undefined}\n className={cn(\n 'text-md font-semibold text-foreground', // 14px - primary field identifier\n context?.disabled && 'opacity-50 cursor-not-allowed',\n className\n )}\n {...props}\n >\n {children}\n {required && <span className=\"text-error ml-0.5\">*</span>}\n </label>\n )\n }\n)\nFieldLabel.displayName = 'FieldLabel'\n\n// Field Error\nconst FieldError = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, children, ...props }, ref) => {\n const context = useFieldContext()\n\n if (!children) return null\n\n return (\n <p\n ref={ref}\n id={context ? `${context.id}-error` : undefined}\n role=\"alert\"\n className={cn('text-xs text-error pl-1', className)} // 12px - color-distinguished, left-aligned with input text\n {...props}\n >\n {children}\n </p>\n )\n})\nFieldError.displayName = 'FieldError'\n\n// Field Character Count\nconst FieldCharCount = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n const context = useFieldContext()\n\n return (\n <p\n ref={ref}\n id={context ? `${context.id}-charcount` : undefined}\n className={cn(\n 'text-xs text-text-muted text-right pr-1 -mt-1', // 12px - right-aligned, 4px gap from input (gap-2 8px - mt-1 4px)\n context?.disabled && 'opacity-50',\n className\n )}\n {...props}\n />\n )\n})\nFieldCharCount.displayName = 'FieldCharCount'\n\nexport { Field, FieldLabel, FieldError, FieldCharCount, useFieldContext, useFieldControl }\n"],"mappings":"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","names":[]}
@@ -193,6 +193,10 @@ var ChatInput = React.forwardRef(
193
193
  }
194
194
  );
195
195
  ChatInput.displayName = "ChatInput";
196
+ function assignRef(ref, value) {
197
+ if (typeof ref === "function") ref(value);
198
+ else if (ref) ref.current = value;
199
+ }
196
200
  var ChatInputField = React.forwardRef(
197
201
  ({
198
202
  className,
@@ -215,12 +219,8 @@ var ChatInputField = React.forwardRef(
215
219
  const setRef = React.useCallback(
216
220
  (el) => {
217
221
  internalRef.current = el;
218
- ctx._fieldRef.current = el;
219
- if (typeof forwardedRef === "function") {
220
- forwardedRef(el);
221
- } else if (forwardedRef) {
222
- forwardedRef.current = el;
223
- }
222
+ assignRef(ctx._fieldRef, el);
223
+ assignRef(forwardedRef, el);
224
224
  },
225
225
  // eslint-disable-next-line react-hooks/exhaustive-deps
226
226
  [forwardedRef]
@@ -372,4 +372,4 @@ export {
372
372
  ChatInputField,
373
373
  ChatInputSubmit
374
374
  };
375
- //# sourceMappingURL=chunk-MRUVGHGP.mjs.map
375
+ //# sourceMappingURL=chunk-YZ7HHFKA.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/ui/chat-input.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { cva, type VariantProps } from 'class-variance-authority'\nimport { cn } from '@/lib/utils'\n\n// ============================================================================\n// Size maps\n// ============================================================================\n\n/** Textarea padding per size */\nconst fieldPaddingMap = {\n sm: 'pt-2.5 px-3 text-md',\n default: 'pt-3 px-4 text-md',\n lg: 'pt-4 px-5 text-base',\n} as const\n\n/** Submit row padding per size */\nconst submitWrapperMap = {\n sm: 'px-2.5 pb-2.5',\n default: 'px-3 pb-3',\n lg: 'px-4 pb-4',\n} as const\n\n/** Submit button dimensions per size */\nconst submitSizeMap = {\n sm: 'h-7 w-7',\n default: 'h-8 w-8',\n lg: 'h-9 w-9',\n} as const\n\n/** Submit button radius — auto-calculated from container radius (min rounded-md) */\nconst submitRadiusMap = {\n sm: 'rounded-md',\n md: 'rounded-md',\n lg: 'rounded-md',\n xl: 'rounded-lg',\n '2xl': 'rounded-xl',\n full: 'rounded-full',\n} as const\n\n/** Submit button radius — direct class map for explicit buttonRadius prop */\nconst buttonRadiusClassMap: Record<ChatInputRadius, string> = {\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n full: 'rounded-full',\n}\n\n/** Submit icon size class per size */\nconst submitIconSizeMap = {\n sm: 'icon-xs',\n default: 'icon-xs',\n lg: 'icon-sm',\n} as const\n\n/** Character count text size per size */\nconst countStyleMap = {\n sm: 'text-xs',\n default: 'text-xs',\n lg: 'text-sm',\n} as const\n\n/** Approximate line-height (px) per size for auto-resize */\nconst lineHeightMap = {\n sm: 20,\n default: 22,\n lg: 24,\n} as const\n\n/** Field padding in inline layout — horizontal only (vertical centering via flex) */\nconst inlineFieldPaddingMap = {\n sm: 'px-3 text-md',\n default: 'px-4 text-md',\n lg: 'px-5 text-base',\n} as const\n\n/** Submit wrapper padding in inline layout — symmetric vertical */\nconst submitWrapperInlineMap = {\n sm: 'px-2.5 py-2.5',\n default: 'px-3 py-3',\n lg: 'px-4 py-4',\n} as const\n\n// ============================================================================\n// CVA — root container variants\n// ============================================================================\n\nconst chatInputVariants = cva(\n [\n 'flex flex-col w-full overflow-hidden cursor-text',\n 'transition-colors duration-micro',\n ].join(' '),\n {\n variants: {\n variant: {\n outline: [\n 'border border-border bg-background',\n 'hover:border-border-strong',\n 'focus-within:border-border-strong focus-within:hover:border-border-strong',\n ].join(' '),\n filled: [\n 'border border-transparent bg-background-muted',\n 'focus-within:border-border',\n ].join(' '),\n },\n radius: {\n sm: 'rounded-sm',\n md: 'rounded-md',\n lg: 'rounded-lg',\n xl: 'rounded-xl',\n '2xl': 'rounded-2xl',\n full: 'rounded-full',\n },\n },\n defaultVariants: {\n variant: 'outline',\n radius: 'xl',\n },\n }\n)\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport type ChatInputSize = 'sm' | 'default' | 'lg'\nexport type ChatInputVariant = 'outline' | 'filled'\nexport type ChatInputRadius = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full'\nexport type ChatInputColor = 'default' | 'primary'\nexport type ChatInputLayout = 'default' | 'inline'\n\n// ============================================================================\n// Context\n// ============================================================================\n\ninterface ChatInputContextValue {\n size: ChatInputSize\n color: ChatInputColor\n layout: ChatInputLayout\n radius: ChatInputRadius\n disabled: boolean\n isEmpty: boolean\n charCount: number\n showCount: boolean\n maxLength: number | undefined\n _setIsEmpty: React.Dispatch<React.SetStateAction<boolean>>\n _setCharCount: React.Dispatch<React.SetStateAction<number>>\n _setShowCount: React.Dispatch<React.SetStateAction<boolean>>\n _setMaxLength: React.Dispatch<React.SetStateAction<number | undefined>>\n _fieldRef: React.MutableRefObject<HTMLTextAreaElement | null>\n _handleSubmit: () => void\n}\n\nconst ChatInputContext = React.createContext<ChatInputContextValue>({\n size: 'default',\n color: 'default',\n layout: 'default',\n radius: 'xl',\n disabled: false,\n isEmpty: true,\n charCount: 0,\n showCount: false,\n maxLength: undefined,\n _setIsEmpty: () => {},\n _setCharCount: () => {},\n _setShowCount: () => {},\n _setMaxLength: () => {},\n _fieldRef: { current: null },\n _handleSubmit: () => {},\n})\n\n// ============================================================================\n// Props interfaces\n// ============================================================================\n\nexport interface ChatInputRootProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSubmit'>,\n VariantProps<typeof chatInputVariants> {\n /** Visual style of the container */\n variant?: ChatInputVariant\n /** Corner radius */\n radius?: ChatInputRadius\n /** Size scale */\n size?: ChatInputSize\n /** Submit button color — default (dark) or primary (brand) */\n color?: ChatInputColor\n /** Layout direction — default (stacked) or inline (field + button side by side) */\n layout?: ChatInputLayout\n /** Disable all interaction */\n disabled?: boolean\n /** Called when the user submits (Enter key or Submit button) — receives current field value */\n onSubmit?: (value: string) => void\n}\n\nexport interface ChatInputFieldProps\n extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'children'> {\n /** Maximum visible rows before the field scrolls */\n maxRows?: number\n /** Show character counter — requires maxLength to be set */\n showCount?: boolean\n}\n\nexport interface ChatInputSubmitProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n /** Show loading/stop state — keeps button enabled so user can stop generation */\n loading?: boolean\n /** Called when clicked during loading state (e.g., stop generation) */\n onStop?: () => void\n /** Override the auto-calculated button radius */\n buttonRadius?: ChatInputRadius\n}\n\n// ============================================================================\n// ChatInput — Root container\n// ============================================================================\n\nconst ChatInput = React.forwardRef<HTMLDivElement, ChatInputRootProps>(\n (\n {\n className,\n variant = 'outline',\n radius = 'xl',\n size = 'default',\n color = 'default',\n layout = 'default',\n disabled = false,\n onSubmit,\n children,\n ...props\n },\n ref\n ) => {\n const [isEmpty, setIsEmpty] = React.useState(true)\n const [charCount, setCharCount] = React.useState(0)\n const [showCount, setShowCount] = React.useState(false)\n const [maxLength, setMaxLength] = React.useState<number | undefined>(undefined)\n const fieldRef = React.useRef<HTMLTextAreaElement | null>(null)\n\n const handleSubmit = React.useCallback(() => {\n const el = fieldRef.current\n if (!el || disabled) return\n const value = el.value.trim()\n if (!value) return\n onSubmit?.(value)\n // Auto-clear in uncontrolled mode\n // Controlled-mode users should clear value inside their onSubmit callback\n el.value = ''\n el.style.height = 'auto'\n setIsEmpty(true)\n setCharCount(0)\n }, [disabled, onSubmit])\n\n const contextValue = React.useMemo<ChatInputContextValue>(\n () => ({\n size,\n color,\n layout,\n radius,\n disabled,\n isEmpty,\n charCount,\n showCount,\n maxLength,\n _setIsEmpty: setIsEmpty,\n _setCharCount: setCharCount,\n _setShowCount: setShowCount,\n _setMaxLength: setMaxLength,\n _fieldRef: fieldRef,\n _handleSubmit: handleSubmit,\n }),\n [size, color, layout, radius, disabled, isEmpty, charCount, showCount, maxLength, handleSubmit]\n )\n\n const handleContainerClick = React.useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n // Focus the textarea when clicking anywhere in the container (not on a button)\n if (!disabled && !(e.target as HTMLElement).closest('button')) {\n fieldRef.current?.focus()\n }\n },\n [disabled]\n )\n\n return (\n <ChatInputContext.Provider value={contextValue}>\n <div\n ref={ref}\n data-disabled={disabled || undefined}\n onClick={handleContainerClick}\n className={cn(\n chatInputVariants({ variant, radius }),\n layout === 'inline' && 'flex-row',\n disabled && 'opacity-50 pointer-events-none',\n className\n )}\n {...props}\n >\n {children}\n </div>\n </ChatInputContext.Provider>\n )\n }\n)\nChatInput.displayName = 'ChatInput'\n\n// Writes a node into a callback or object ref. Kept outside the component: React\n// Compiler rules flag assigning `.current` on refs that come from props or context.\nfunction assignRef<T>(ref: React.Ref<T> | undefined, value: T | null) {\n if (typeof ref === 'function') ref(value)\n else if (ref) (ref as React.MutableRefObject<T | null>).current = value\n}\n\n// ============================================================================\n// ChatInputField — Auto-resizing textarea\n// ============================================================================\n\nconst ChatInputField = React.forwardRef<HTMLTextAreaElement, ChatInputFieldProps>(\n (\n {\n className,\n maxRows = 8,\n showCount = false,\n maxLength,\n placeholder,\n onChange,\n onKeyDown,\n disabled,\n ...props\n },\n forwardedRef\n ) => {\n const ctx = React.useContext(ChatInputContext)\n const internalRef = React.useRef<HTMLTextAreaElement | null>(null)\n const isDisabled = disabled ?? ctx.disabled\n\n // Sync showCount + maxLength into root context on mount/update\n React.useEffect(() => {\n ctx._setShowCount(showCount)\n ctx._setMaxLength(maxLength)\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [showCount, maxLength])\n\n // Merge forwarded ref + internal ref + context field ref\n const setRef = React.useCallback(\n (el: HTMLTextAreaElement | null) => {\n internalRef.current = el\n assignRef(ctx._fieldRef, el)\n assignRef(forwardedRef, el)\n },\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [forwardedRef]\n )\n\n // Adjust textarea height to content, bounded by maxRows\n const autoResize = React.useCallback(() => {\n const el = internalRef.current\n if (!el) return\n el.style.height = 'auto'\n const maxHeight = maxRows * lineHeightMap[ctx.size]\n const newHeight = Math.min(el.scrollHeight, maxHeight)\n el.style.height = `${newHeight}px`\n el.style.overflowY = el.scrollHeight > maxHeight ? 'auto' : 'hidden'\n }, [ctx.size, maxRows])\n\n const handleChange = React.useCallback(\n (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n const val = e.target.value\n ctx._setIsEmpty(val.trim() === '')\n ctx._setCharCount(val.length)\n autoResize()\n onChange?.(e)\n },\n [ctx, autoResize, onChange]\n )\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLTextAreaElement>) => {\n // Enter = submit | Shift+Enter = new line\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n ctx._handleSubmit()\n }\n onKeyDown?.(e)\n },\n [ctx, onKeyDown]\n )\n\n return (\n <div className={cn('flex-1 min-w-0', ctx.layout === 'inline' && 'flex items-center self-stretch')}>\n <textarea\n ref={setRef}\n rows={1}\n placeholder={placeholder}\n maxLength={maxLength}\n disabled={isDisabled}\n className={cn(\n 'w-full bg-transparent text-foreground placeholder:text-foreground/30',\n 'resize-none outline-none focus:outline-none',\n 'disabled:cursor-not-allowed',\n 'overflow-hidden',\n ctx.layout === 'inline' ? inlineFieldPaddingMap[ctx.size] : fieldPaddingMap[ctx.size],\n className\n )}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n {...props}\n />\n </div>\n )\n }\n)\nChatInputField.displayName = 'ChatInputField'\n\n// ============================================================================\n// ChatInputSubmit — Send / stop button\n// ============================================================================\n\nconst ChatInputSubmit = React.forwardRef<HTMLButtonElement, ChatInputSubmitProps>(\n (\n {\n className,\n loading = false,\n onStop,\n children,\n disabled,\n onClick,\n buttonRadius,\n ...props\n },\n ref\n ) => {\n const ctx = React.useContext(ChatInputContext)\n\n // Disabled: context disabled | user prop | empty field (only when not loading)\n const isDisabled = (disabled ?? ctx.disabled) || (!loading && ctx.isEmpty)\n\n const handleClick = React.useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n if (loading) {\n onStop?.()\n } else if (!isDisabled) {\n ctx._handleSubmit()\n }\n onClick?.(e)\n },\n [ctx, isDisabled, loading, onStop, onClick]\n )\n\n return (\n <div className={cn('flex items-center justify-end gap-2 shrink-0 cursor-default', ctx.layout === 'inline' ? submitWrapperInlineMap[ctx.size] : submitWrapperMap[ctx.size])}>\n {ctx.showCount && ctx.maxLength != null && (\n <span className={cn('text-text-subtle select-none', countStyleMap[ctx.size])}>\n {ctx.charCount} / {ctx.maxLength}\n </span>\n )}\n <button\n ref={ref}\n type=\"button\"\n disabled={isDisabled && !loading}\n aria-label={loading ? 'Stop generating' : 'Send message'}\n className={cn(\n 'inline-flex items-center justify-center shrink-0',\n buttonRadius ? buttonRadiusClassMap[buttonRadius] : submitRadiusMap[ctx.radius],\n 'transition-all duration-fast',\n 'focus-visible:outline-none focus-visible:focus-ring',\n submitSizeMap[ctx.size],\n // Loading state — enabled, pulsing\n loading && ctx.color === 'default' && 'bg-foreground text-background animate-pulse cursor-pointer',\n loading && ctx.color === 'primary' && 'bg-primary text-primary-foreground animate-pulse cursor-pointer',\n // Enabled state\n !loading && !isDisabled && ctx.color === 'default' && [\n 'bg-foreground text-background',\n 'hover:bg-foreground/90 active:bg-foreground/80 active:scale-pressed cursor-pointer',\n ],\n !loading && !isDisabled && ctx.color === 'primary' && [\n 'bg-primary text-primary-foreground',\n 'hover:bg-primary-hover active:scale-pressed cursor-pointer',\n ],\n // Disabled state\n !loading && isDisabled && 'bg-background-muted text-text-subtle pointer-events-none',\n className\n )}\n onClick={handleClick}\n {...props}\n >\n <span\n aria-hidden=\"true\"\n className={cn('flex items-center justify-center', submitIconSizeMap[ctx.size])}\n >\n {children ?? (loading ? <StopIcon /> : <SendIcon />)}\n </span>\n </button>\n </div>\n )\n }\n)\nChatInputSubmit.displayName = 'ChatInputSubmit'\n\n// ============================================================================\n// Built-in SVG icons — no external icon dependency\n// ============================================================================\n\nfunction SendIcon() {\n return (\n <svg\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"w-full h-full\"\n >\n <path d=\"M22 2 11 13\" />\n <path d=\"M22 2 15 22 11 13 2 9l20-7Z\" />\n </svg>\n )\n}\n\nfunction StopIcon() {\n return (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" className=\"w-full h-full\">\n <rect x=\"5\" y=\"5\" width=\"14\" height=\"14\" rx=\"2\" />\n </svg>\n )\n}\n\nexport {\n ChatInput,\n ChatInputField,\n ChatInputSubmit,\n chatInputVariants,\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  ChatInputField,
5
5
  ChatInputSubmit,
6
6
  chatInputVariants
7
- } from "../chunk-MRUVGHGP.mjs";
7
+ } from "../chunk-YZ7HHFKA.mjs";
8
8
  import "../chunk-53MIUPSY.mjs";
9
9
  export {
10
10
  ChatInput,
@@ -4,7 +4,7 @@ import {
4
4
  ChatMessageAvatar,
5
5
  ChatMessageContent,
6
6
  ChatMessageFooter
7
- } from "../chunk-234NAXGV.mjs";
7
+ } from "../chunk-R7FJEO4K.mjs";
8
8
  import "../chunk-S4T4PU7F.mjs";
9
9
  import "../chunk-GD4YE5AE.mjs";
10
10
  import "../chunk-53MIUPSY.mjs";
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  Checkbox,
4
4
  checkboxVariants
5
- } from "../chunk-UWTT5AE6.mjs";
6
- import "../chunk-Z6JWWCNL.mjs";
5
+ } from "../chunk-HS2VRYSX.mjs";
6
+ import "../chunk-T5A4APEL.mjs";
7
7
  import "../chunk-53MIUPSY.mjs";
8
8
  export {
9
9
  Checkbox,
@@ -4,14 +4,16 @@ import {
4
4
  FieldCharCount,
5
5
  FieldError,
6
6
  FieldLabel,
7
- useFieldContext
8
- } from "../chunk-Z6JWWCNL.mjs";
7
+ useFieldContext,
8
+ useFieldControl
9
+ } from "../chunk-T5A4APEL.mjs";
9
10
  import "../chunk-53MIUPSY.mjs";
10
11
  export {
11
12
  Field,
12
13
  FieldCharCount,
13
14
  FieldError,
14
15
  FieldLabel,
15
- useFieldContext
16
+ useFieldContext,
17
+ useFieldControl
16
18
  };
17
19
  //# sourceMappingURL=field.mjs.map
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  Input,
4
4
  inputVariants
5
- } from "../chunk-WWSN5YME.mjs";
6
- import "../chunk-Z6JWWCNL.mjs";
5
+ } from "../chunk-SDDAGZWA.mjs";
6
+ import "../chunk-T5A4APEL.mjs";
7
7
  import "../chunk-53MIUPSY.mjs";
8
8
  export {
9
9
  Input,
@@ -10,7 +10,7 @@ import {
10
10
  NavigationMenuTrigger,
11
11
  NavigationMenuViewport,
12
12
  navigationMenuSizeMap
13
- } from "../chunk-DTLNWOTR.mjs";
13
+ } from "../chunk-C5D3VRNJ.mjs";
14
14
  import "../chunk-53MIUPSY.mjs";
15
15
  export {
16
16
  NavigationMenu,
@@ -13,7 +13,7 @@ import {
13
13
  paginationItemVariants,
14
14
  paginationSizeMap,
15
15
  usePagination
16
- } from "../chunk-T546XBQG.mjs";
16
+ } from "../chunk-EG2GTK65.mjs";
17
17
  import "../chunk-53MIUPSY.mjs";
18
18
  export {
19
19
  Pagination,
@@ -4,8 +4,8 @@ import {
4
4
  RadioGroupItem,
5
5
  radioGroupVariants,
6
6
  radioItemVariants
7
- } from "../chunk-GRCJ35DX.mjs";
8
- import "../chunk-Z6JWWCNL.mjs";
7
+ } from "../chunk-2WIIXHOV.mjs";
8
+ import "../chunk-T5A4APEL.mjs";
9
9
  import "../chunk-53MIUPSY.mjs";
10
10
  export {
11
11
  RadioGroup,
@@ -8,7 +8,8 @@ import {
8
8
  SelectSeparator,
9
9
  SelectTrigger,
10
10
  SelectValue
11
- } from "../chunk-IY3R2VGB.mjs";
11
+ } from "../chunk-L55ABE4H.mjs";
12
+ import "../chunk-T5A4APEL.mjs";
12
13
  import "../chunk-53MIUPSY.mjs";
13
14
  export {
14
15
  Select,
@@ -2,7 +2,8 @@
2
2
  import {
3
3
  Slider,
4
4
  sliderVariants
5
- } from "../chunk-VUPGBB5X.mjs";
5
+ } from "../chunk-IJ2FZ3L5.mjs";
6
+ import "../chunk-T5A4APEL.mjs";
6
7
  import "../chunk-53MIUPSY.mjs";
7
8
  export {
8
9
  Slider,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  Switch,
4
4
  switchVariants
5
- } from "../chunk-DRVHHEAY.mjs";
6
- import "../chunk-Z6JWWCNL.mjs";
5
+ } from "../chunk-ND6TUVP2.mjs";
6
+ import "../chunk-T5A4APEL.mjs";
7
7
  import "../chunk-53MIUPSY.mjs";
8
8
  export {
9
9
  Switch,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  Textarea,
4
4
  textareaVariants
5
- } from "../chunk-N4K2BDGM.mjs";
6
- import "../chunk-Z6JWWCNL.mjs";
5
+ } from "../chunk-IHHI3LIN.mjs";
6
+ import "../chunk-T5A4APEL.mjs";
7
7
  import "../chunk-53MIUPSY.mjs";
8
8
  export {
9
9
  Textarea,
package/dist/index.d.ts CHANGED
@@ -276,9 +276,18 @@ declare const Textarea: React.ForwardRefExoticComponent<TextareaProps & React.Re
276
276
 
277
277
  interface FieldContextValue {
278
278
  id: string;
279
+ /** id of the FieldLabel, for aria-labelledby on grouped controls */
280
+ labelId: string;
279
281
  error?: boolean;
280
282
  disabled?: boolean;
281
- }
283
+ /** A FieldLabel is rendered inside this Field */
284
+ hasLabel: boolean;
285
+ /** The Field holds labelled checkboxes / switches / a radio group and no single input */
286
+ isGroup: boolean;
287
+ registerLabel: () => () => void;
288
+ registerControl: (kind: FieldControlKind) => () => void;
289
+ }
290
+ type FieldControlKind = 'single' | 'group' | 'labelled';
282
291
  declare function useFieldContext(): FieldContextValue | null;
283
292
  declare const fieldVariants: (props?: ({
284
293
  gap?: "default" | "sm" | "lg" | "none" | "xs" | null | undefined;
@@ -423,7 +432,7 @@ declare namespace DropdownMenuShortcut {
423
432
 
424
433
  type SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full';
425
434
  type SelectSize = 'xs' | 'sm' | 'default' | 'lg' | 'xl';
426
- declare const Select: ({ size, radius, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {
435
+ declare const Select: ({ size, radius, disabled, ...props }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {
427
436
  size?: SelectSize;
428
437
  radius?: SelectRadius;
429
438
  }) => React.JSX.Element;