7onic 0.1.18 → 0.1.20

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 (2) hide show
  1. package/dist/index.js +183 -47
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -12302,6 +12302,13 @@ const ChatInput = React.forwardRef<HTMLDivElement, ChatInputRootProps>(
12302
12302
  )
12303
12303
  ChatInput.displayName = 'ChatInput'
12304
12304
 
12305
+ // Writes a node into a callback or object ref. Kept outside the component: React
12306
+ // Compiler rules flag assigning \`.current\` on refs that come from props or context.
12307
+ function assignRef<T>(ref: React.Ref<T> | undefined, value: T | null) {
12308
+ if (typeof ref === 'function') ref(value)
12309
+ else if (ref) (ref as React.MutableRefObject<T | null>).current = value
12310
+ }
12311
+
12305
12312
  // ============================================================================
12306
12313
  // ChatInputField \u2014 Auto-resizing textarea
12307
12314
  // ============================================================================
@@ -12336,12 +12343,8 @@ const ChatInputField = React.forwardRef<HTMLTextAreaElement, ChatInputFieldProps
12336
12343
  const setRef = React.useCallback(
12337
12344
  (el: HTMLTextAreaElement | null) => {
12338
12345
  internalRef.current = el
12339
- ctx._fieldRef.current = el
12340
- if (typeof forwardedRef === 'function') {
12341
- forwardedRef(el)
12342
- } else if (forwardedRef) {
12343
- (forwardedRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = el
12344
- }
12346
+ assignRef(ctx._fieldRef, el)
12347
+ assignRef(forwardedRef, el)
12345
12348
  },
12346
12349
  // eslint-disable-next-line react-hooks/exhaustive-deps
12347
12350
  [forwardedRef]
@@ -12749,7 +12752,6 @@ export interface ChatMessageAvatarProps {
12749
12752
  className?: string
12750
12753
  }
12751
12754
 
12752
- // eslint-disable-next-line @typescript-eslint/no-empty-object-type
12753
12755
  export interface ChatMessageContentProps extends React.HTMLAttributes<HTMLDivElement> {}
12754
12756
 
12755
12757
  export interface ChatMessageFooterProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -12986,7 +12988,7 @@ import * as React from 'react'
12986
12988
  import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
12987
12989
  import { cva, type VariantProps } from 'class-variance-authority'
12988
12990
  import { cn } from '@/lib/utils'
12989
- import { useFieldContext } from './field'
12991
+ import { useFieldContext, useFieldControl } from './field'
12990
12992
 
12991
12993
  // Color maps for checked/indeterminate state
12992
12994
  const checkboxColorMap = {
@@ -13068,7 +13070,11 @@ const Checkbox = React.forwardRef<
13068
13070
  const resolvedSize = size || 'default'
13069
13071
  const resolvedDisabled = disabled ?? fieldContext?.disabled
13070
13072
  const generatedId = React.useId()
13071
- const checkboxId = id ?? fieldContext?.id ?? generatedId
13073
+ // With its own label the checkbox is one item of a group: keep a unique id. Only a
13074
+ // bare checkbox labelled by FieldLabel takes the Field id.
13075
+ const hasOwnLabel = Boolean(label)
13076
+ const checkboxId = id ?? (hasOwnLabel ? generatedId : fieldContext?.id ?? generatedId)
13077
+ useFieldControl(hasOwnLabel ? 'group' : 'single', Boolean(fieldContext) && (hasOwnLabel || !id))
13072
13078
 
13073
13079
  const checkbox = (
13074
13080
  <CheckboxPrimitive.Root
@@ -13934,16 +13940,42 @@ import { cn } from '@/lib/utils'
13934
13940
  // Field Context for sharing state between components
13935
13941
  interface FieldContextValue {
13936
13942
  id: string
13943
+ /** id of the FieldLabel, for aria-labelledby on grouped controls */
13944
+ labelId: string
13937
13945
  error?: boolean
13938
13946
  disabled?: boolean
13947
+ /** A FieldLabel is rendered inside this Field */
13948
+ hasLabel: boolean
13949
+ /** The Field holds labelled checkboxes / switches / a radio group and no single input */
13950
+ isGroup: boolean
13951
+ registerLabel: () => () => void
13952
+ registerControl: (kind: FieldControlKind) => () => void
13939
13953
  }
13940
13954
 
13955
+ type FieldControlKind = 'single' | 'group' | 'labelled'
13956
+
13941
13957
  const FieldContext = React.createContext<FieldContextValue | null>(null)
13942
13958
 
13943
13959
  function useFieldContext() {
13944
13960
  return React.useContext(FieldContext)
13945
13961
  }
13946
13962
 
13963
+ // Controls tell their Field what they are, so FieldLabel can point at the right thing.
13964
+ // 'single': one input that takes the Field id (Input, Textarea, a bare Checkbox / Switch);
13965
+ // FieldLabel targets it with htmlFor.
13966
+ // 'group': a Checkbox / Switch with its own label keeps a unique id; the Field becomes
13967
+ // role="group" named by FieldLabel instead of every item sharing one id.
13968
+ // 'labelled': a RadioGroup names itself from FieldLabel (aria-labelledby).
13969
+ // A single input wins: with one present, FieldLabel keeps pointing at it.
13970
+ function useFieldControl(kind: FieldControlKind, enabled: boolean) {
13971
+ const context = useFieldContext()
13972
+ const register = context?.registerControl
13973
+ React.useEffect(() => {
13974
+ if (!enabled || !register) return
13975
+ return register(kind)
13976
+ }, [enabled, register, kind])
13977
+ }
13978
+
13947
13979
  // Field wrapper
13948
13980
  const fieldVariants = cva('flex flex-col', {
13949
13981
  variants: {
@@ -13970,11 +14002,33 @@ export interface FieldProps
13970
14002
  const Field = React.forwardRef<HTMLDivElement, FieldProps>(
13971
14003
  ({ className, gap, error, disabled, children, ...props }, ref) => {
13972
14004
  const id = React.useId()
14005
+ const labelId = \`\${id}-label\`
14006
+ const [labelCount, setLabelCount] = React.useState(0)
14007
+ const [counts, setCounts] = React.useState({ single: 0, group: 0, labelled: 0 })
14008
+
14009
+ const registerLabel = React.useCallback(() => {
14010
+ setLabelCount((n) => n + 1)
14011
+ return () => setLabelCount((n) => n - 1)
14012
+ }, [])
14013
+ const registerControl = React.useCallback((kind: FieldControlKind) => {
14014
+ setCounts((c) => ({ ...c, [kind]: c[kind] + 1 }))
14015
+ return () => setCounts((c) => ({ ...c, [kind]: c[kind] - 1 }))
14016
+ }, [])
14017
+
14018
+ const hasLabel = labelCount > 0
14019
+ const isGroup = counts.single === 0 && (counts.group > 0 || counts.labelled > 0)
14020
+ const asGroup = counts.single === 0 && counts.group > 0
14021
+ const contextValue = React.useMemo(
14022
+ () => ({ id, labelId, error, disabled, hasLabel, isGroup, registerLabel, registerControl }),
14023
+ [id, labelId, error, disabled, hasLabel, isGroup, registerLabel, registerControl]
14024
+ )
13973
14025
 
13974
14026
  return (
13975
- <FieldContext.Provider value={{ id, error, disabled }}>
14027
+ <FieldContext.Provider value={contextValue}>
13976
14028
  <div
13977
14029
  ref={ref}
14030
+ role={asGroup ? 'group' : undefined}
14031
+ aria-labelledby={asGroup && hasLabel ? labelId : undefined}
13978
14032
  className={cn(fieldVariants({ gap }), className)}
13979
14033
  data-error={error || undefined}
13980
14034
  data-disabled={disabled || undefined}
@@ -13996,11 +14050,15 @@ export interface FieldLabelProps extends React.LabelHTMLAttributes<HTMLLabelElem
13996
14050
  const FieldLabel = React.forwardRef<HTMLLabelElement, FieldLabelProps>(
13997
14051
  ({ className, required, children, ...props }, ref) => {
13998
14052
  const context = useFieldContext()
14053
+ const registerLabel = context?.registerLabel
14054
+ React.useEffect(() => registerLabel?.(), [registerLabel])
13999
14055
 
14000
14056
  return (
14001
14057
  <label
14002
14058
  ref={ref}
14003
- htmlFor={context?.id}
14059
+ id={context?.labelId}
14060
+ // Grouped controls have their own labels; the group title targets no input
14061
+ htmlFor={context && !context.isGroup ? context.id : undefined}
14004
14062
  className={cn(
14005
14063
  'text-md font-semibold text-foreground', // 14px - primary field identifier
14006
14064
  context?.disabled && 'opacity-50 cursor-not-allowed',
@@ -14061,7 +14119,7 @@ const FieldCharCount = React.forwardRef<
14061
14119
  })
14062
14120
  FieldCharCount.displayName = 'FieldCharCount'
14063
14121
 
14064
- export { Field, FieldLabel, FieldError, FieldCharCount, useFieldContext }
14122
+ export { Field, FieldLabel, FieldError, FieldCharCount, useFieldContext, useFieldControl }
14065
14123
  `,
14066
14124
  type: "ui"
14067
14125
  }]
@@ -14211,7 +14269,7 @@ export { IconButton, iconButtonVariants }
14211
14269
  import * as React from 'react'
14212
14270
  import { cva, type VariantProps } from 'class-variance-authority'
14213
14271
  import { cn } from '@/lib/utils'
14214
- import { useFieldContext } from './field'
14272
+ import { useFieldContext, useFieldControl } from './field'
14215
14273
 
14216
14274
  const inputVariants = cva(
14217
14275
  [
@@ -14320,6 +14378,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
14320
14378
  const resolvedError = error ?? fieldContext?.error
14321
14379
  const resolvedState = resolvedError ? 'error' : state
14322
14380
  const inputId = id ?? fieldContext?.id
14381
+ useFieldControl('single', Boolean(fieldContext) && !id)
14323
14382
  const isDisabled = props.disabled ?? fieldContext?.disabled
14324
14383
 
14325
14384
  // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)
@@ -15444,10 +15503,13 @@ const NavigationMenuItem = React.forwardRef<HTMLLIElement, NavigationMenuItemPro
15444
15503
  const { orientation, collapsed } = useNavigationMenuContext()
15445
15504
  const [open, setOpen] = React.useState(defaultOpen)
15446
15505
 
15447
- // Auto-close sub-menus when collapsed
15448
- React.useEffect(() => {
15506
+ // Auto-close sub-menus when collapsed. Adjusted during render (React's pattern for
15507
+ // state that follows a prop) instead of in an effect, which re-rendered once more.
15508
+ const [prevCollapsed, setPrevCollapsed] = React.useState(collapsed)
15509
+ if (collapsed !== prevCollapsed) {
15510
+ setPrevCollapsed(collapsed)
15449
15511
  if (collapsed) setOpen(false)
15450
- }, [collapsed])
15512
+ }
15451
15513
 
15452
15514
  if (orientation === 'horizontal') {
15453
15515
  return (
@@ -15765,20 +15827,37 @@ const NavigationMenuGroup = React.forwardRef<HTMLDivElement, NavigationMenuGroup
15765
15827
  const { size, collapsed } = useNavigationMenuContext()
15766
15828
  const s = navigationMenuSizeMap[size]
15767
15829
 
15830
+ const labelId = React.useId()
15831
+ const showLabel = Boolean(label) && !collapsed
15832
+
15833
+ // Groups sit inside NavigationMenuList's <ul>, so the group is wrapped in an <li> to
15834
+ // keep the list structure valid. The spacing class stays on that <li>: it relies on
15835
+ // :first-child among the list's children.
15768
15836
  return (
15769
- <div ref={ref} role="group" className={cn(label && !collapsed && s.groupMargin, className)} {...props}>
15770
- {label && !collapsed && (
15771
- <div className={cn(
15772
- 'font-semibold text-text-subtle uppercase tracking-wider select-none',
15773
- s.groupLabel,
15774
- )}>
15775
- {label}
15776
- </div>
15777
- )}
15778
- <ul className="flex flex-col gap-0.5">
15779
- {children}
15780
- </ul>
15781
- </div>
15837
+ <li className={cn(showLabel && s.groupMargin)}>
15838
+ <div
15839
+ ref={ref}
15840
+ role="group"
15841
+ aria-labelledby={showLabel && !props['aria-label'] ? labelId : undefined}
15842
+ className={className}
15843
+ {...props}
15844
+ >
15845
+ {showLabel && (
15846
+ <div
15847
+ id={labelId}
15848
+ className={cn(
15849
+ 'font-semibold text-text-subtle uppercase tracking-wider select-none',
15850
+ s.groupLabel,
15851
+ )}
15852
+ >
15853
+ {label}
15854
+ </div>
15855
+ )}
15856
+ <ul className="flex flex-col gap-0.5">
15857
+ {children}
15858
+ </ul>
15859
+ </div>
15860
+ </li>
15782
15861
  )
15783
15862
  }
15784
15863
  )
@@ -16474,11 +16553,15 @@ PaginationEllipsis.displayName = 'PaginationEllipsis'
16474
16553
 
16475
16554
  // \u2500\u2500\u2500 PaginationItems (Convenience) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
16476
16555
 
16556
+ // Renders the <li> items straight into PaginationContent's <ul>: a wrapper element
16557
+ // between them breaks the list structure for assistive technology (a \`display:
16558
+ // contents\` div used to sit here). The div props and ref stay in the signature for
16559
+ // compatibility but have no element to attach to.
16477
16560
  const PaginationItems = React.forwardRef<HTMLDivElement, React.ComponentPropsWithoutRef<'div'>>(
16478
- ({ className, ...props }, ref) => {
16561
+ (_props, _ref) => {
16479
16562
  const ctx = usePaginationContext()
16480
16563
  return (
16481
- <div ref={ref} className={cn('contents', className)} {...props}>
16564
+ <>
16482
16565
  {ctx.paginationRange.map((item, index) => (
16483
16566
  <PaginationItem key={\`\${item}-\${index}\`}>
16484
16567
  {item === 'dots' ? (
@@ -16488,7 +16571,7 @@ const PaginationItems = React.forwardRef<HTMLDivElement, React.ComponentPropsWit
16488
16571
  )}
16489
16572
  </PaginationItem>
16490
16573
  ))}
16491
- </div>
16574
+ </>
16492
16575
  )
16493
16576
  }
16494
16577
  )
@@ -17205,7 +17288,7 @@ import * as React from 'react'
17205
17288
  import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'
17206
17289
  import { cva } from 'class-variance-authority'
17207
17290
  import { cn } from '@/lib/utils'
17208
- import { useFieldContext } from './field'
17291
+ import { useFieldContext, useFieldControl } from './field'
17209
17292
 
17210
17293
  // Color maps for checked state
17211
17294
  const radioColorMap = {
@@ -17257,6 +17340,9 @@ const RadioGroup = React.forwardRef<
17257
17340
  >(({ className, orientation, size = 'default', weight = 'bold', color = 'default', disabled, ...props }, ref) => {
17258
17341
  const fieldContext = useFieldContext()
17259
17342
  const resolvedDisabled = disabled ?? fieldContext?.disabled
17343
+ // Inside a Field the FieldLabel names the radio group (items keep their own labels)
17344
+ useFieldControl('labelled', Boolean(fieldContext))
17345
+ const labelledBy = fieldContext?.hasLabel && !props['aria-label'] ? fieldContext.labelId : undefined
17260
17346
 
17261
17347
  return (
17262
17348
  <RadioGroupContext.Provider value={{ size, weight, color, disabled: resolvedDisabled }}>
@@ -17265,6 +17351,7 @@ const RadioGroup = React.forwardRef<
17265
17351
  className={cn(radioGroupVariants({ orientation }), className)}
17266
17352
  orientation={orientation || undefined}
17267
17353
  disabled={resolvedDisabled}
17354
+ aria-labelledby={labelledBy}
17268
17355
  {...props}
17269
17356
  />
17270
17357
  </RadioGroupContext.Provider>
@@ -17605,7 +17692,7 @@ export { Segmented, SegmentedItem, segmentedVariants, segmentedItemVariants }
17605
17692
  "select": {
17606
17693
  name: "select",
17607
17694
  dependencies: ["@radix-ui/react-select"],
17608
- registryDependencies: [],
17695
+ registryDependencies: ["field"],
17609
17696
  reverseDependencies: [],
17610
17697
  namespace: false,
17611
17698
  description: "",
@@ -17616,6 +17703,7 @@ export { Segmented, SegmentedItem, segmentedVariants, segmentedItemVariants }
17616
17703
  import * as React from 'react'
17617
17704
  import * as SelectPrimitive from '@radix-ui/react-select'
17618
17705
  import { cn } from '@/lib/utils'
17706
+ import { useFieldContext, useFieldControl } from './field'
17619
17707
 
17620
17708
  // Radius (matches Input \u2014 set at Root, propagates to Trigger and Content)
17621
17709
  type SelectRadius = 'none' | 'sm' | 'base' | 'default' | 'lg' | 'xl' | '2xl' | '3xl' | 'full'
@@ -17744,19 +17832,24 @@ const SelectStyleContext = React.createContext<{
17744
17832
  flush: boolean
17745
17833
  }>({ contentRadius: 'xl', itemSize: 'md', flush: false })
17746
17834
 
17747
- // Root \u2014 state management + size/radius context
17835
+ // Root \u2014 state management + size/radius context. Inside a Field it inherits the
17836
+ // Field's disabled state, like Input and Textarea.
17748
17837
  const Select = ({
17749
17838
  size = 'default',
17750
17839
  radius = 'default',
17840
+ disabled,
17751
17841
  ...props
17752
17842
  }: React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root> & {
17753
17843
  size?: SelectSize
17754
17844
  radius?: SelectRadius
17755
- }) => (
17756
- <SelectRootContext.Provider value={{ size, radius }}>
17757
- <SelectPrimitive.Root {...props} />
17758
- </SelectRootContext.Provider>
17759
- )
17845
+ }) => {
17846
+ const fieldContext = useFieldContext()
17847
+ return (
17848
+ <SelectRootContext.Provider value={{ size, radius }}>
17849
+ <SelectPrimitive.Root disabled={disabled ?? fieldContext?.disabled} {...props} />
17850
+ </SelectRootContext.Provider>
17851
+ )
17852
+ }
17760
17853
 
17761
17854
  // Value \u2014 displays selected value or placeholder
17762
17855
  const SelectValue = SelectPrimitive.Value
@@ -17768,11 +17861,15 @@ const SelectGroup = SelectPrimitive.Group
17768
17861
  const SelectTrigger = React.forwardRef<
17769
17862
  React.ElementRef<typeof SelectPrimitive.Trigger>,
17770
17863
  React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
17771
- >(({ className, children, ...props }, ref) => {
17864
+ >(({ className, children, id, ...props }, ref) => {
17772
17865
  const { size, radius } = React.useContext(SelectRootContext)
17866
+ // Inside a Field the trigger takes the Field id, so FieldLabel names it
17867
+ const fieldContext = useFieldContext()
17868
+ useFieldControl('single', Boolean(fieldContext) && !id)
17773
17869
  return (
17774
17870
  <SelectPrimitive.Trigger
17775
17871
  ref={ref}
17872
+ id={id ?? fieldContext?.id}
17776
17873
  className={cn(
17777
17874
  'flex w-full items-center justify-between bg-background text-foreground hover:bg-background-muted',
17778
17875
  'border border-border',
@@ -18154,7 +18251,7 @@ export { Skeleton, skeletonVariants }
18154
18251
  "slider": {
18155
18252
  name: "slider",
18156
18253
  dependencies: ["@radix-ui/react-slider"],
18157
- registryDependencies: [],
18254
+ registryDependencies: ["field"],
18158
18255
  reverseDependencies: [],
18159
18256
  namespace: false,
18160
18257
  description: "",
@@ -18166,6 +18263,7 @@ import * as React from 'react'
18166
18263
  import * as SliderPrimitive from '@radix-ui/react-slider'
18167
18264
  import { cva, type VariantProps } from 'class-variance-authority'
18168
18265
  import { cn } from '@/lib/utils'
18266
+ import { useFieldContext, useFieldControl } from './field'
18169
18267
 
18170
18268
  // Slider root variants
18171
18269
  const sliderVariants = cva(
@@ -18241,8 +18339,13 @@ export interface SliderProps
18241
18339
  const Slider = React.forwardRef<
18242
18340
  React.ElementRef<typeof SliderPrimitive.Root>,
18243
18341
  SliderProps
18244
- >(({ className, size, color = 'default', value, defaultValue, onValueChange, showTooltip = 'never', formatLabel, startContent, endContent, orientation, ...props }, ref) => {
18342
+ >(({ className, size, color = 'default', value, defaultValue, onValueChange, showTooltip = 'never', formatLabel, startContent, endContent, orientation, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }, ref) => {
18245
18343
  const resolvedSize = size || 'default'
18344
+ // The thumbs carry role="slider", so the accessible name goes on them, not on the
18345
+ // Root. Inside a Field the FieldLabel names the slider unless a name is given.
18346
+ const fieldContext = useFieldContext()
18347
+ useFieldControl('labelled', Boolean(fieldContext))
18348
+ const thumbLabelledBy = ariaLabelledBy ?? (!ariaLabel && fieldContext?.hasLabel ? fieldContext.labelId : undefined)
18246
18349
  const thumbCount = value?.length ?? defaultValue?.length ?? 1
18247
18350
  const hasTooltip = showTooltip !== 'never'
18248
18351
  const hasWrapper = !!(startContent || endContent)
@@ -18295,6 +18398,8 @@ const Slider = React.forwardRef<
18295
18398
  {Array.from({ length: thumbCount }).map((_, i) => (
18296
18399
  <SliderPrimitive.Thumb
18297
18400
  key={i}
18401
+ aria-label={ariaLabel}
18402
+ aria-labelledby={thumbLabelledBy}
18298
18403
  className={cn(
18299
18404
  'group/thumb block rounded-full border-2 shadow-sm', sliderColorMap[color].thumb,
18300
18405
  isVertical
@@ -18988,7 +19093,7 @@ import * as React from 'react'
18988
19093
  import * as SwitchPrimitive from '@radix-ui/react-switch'
18989
19094
  import { cva, type VariantProps } from 'class-variance-authority'
18990
19095
  import { cn } from '@/lib/utils'
18991
- import { useFieldContext } from './field'
19096
+ import { useFieldContext, useFieldControl } from './field'
18992
19097
 
18993
19098
  // Switch track variants
18994
19099
  const switchVariants = cva(
@@ -19089,7 +19194,11 @@ const Switch = React.forwardRef<
19089
19194
  const resolvedSize = size || 'default'
19090
19195
  const resolvedDisabled = disabled ?? fieldContext?.disabled
19091
19196
  const generatedId = React.useId()
19092
- const switchId = id ?? fieldContext?.id ?? generatedId
19197
+ // With its own label the switch is one item of a group: keep a unique id. Only a
19198
+ // bare switch labelled by FieldLabel takes the Field id.
19199
+ const hasOwnLabel = Boolean(label || startLabel || endLabel)
19200
+ const switchId = id ?? (hasOwnLabel ? generatedId : fieldContext?.id ?? generatedId)
19201
+ useFieldControl(hasOwnLabel ? 'group' : 'single', Boolean(fieldContext) && (hasOwnLabel || !id))
19093
19202
 
19094
19203
  const switchEl = (
19095
19204
  <SwitchPrimitive.Root
@@ -19801,7 +19910,7 @@ export {
19801
19910
  import * as React from 'react'
19802
19911
  import { cva, type VariantProps } from 'class-variance-authority'
19803
19912
  import { cn } from '@/lib/utils'
19804
- import { useFieldContext } from './field'
19913
+ import { useFieldContext, useFieldControl } from './field'
19805
19914
 
19806
19915
  const textareaVariants = cva(
19807
19916
  [
@@ -19882,6 +19991,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
19882
19991
  const resolvedError = error ?? fieldContext?.error
19883
19992
  const resolvedState = resolvedError ? 'error' : state
19884
19993
  const textareaId = id ?? fieldContext?.id
19994
+ useFieldControl('single', Boolean(fieldContext) && !id)
19885
19995
  const isDisabled = props.disabled ?? fieldContext?.disabled
19886
19996
 
19887
19997
  // Keyboard focus detection (when focusRing: false, auto-show ring on Tab navigation)
@@ -21631,8 +21741,34 @@ function findSimilar(input, candidates) {
21631
21741
  best = name;
21632
21742
  }
21633
21743
  }
21744
+ if (best) return best;
21745
+ let bestDistance = Infinity;
21746
+ for (const name of candidates) {
21747
+ const distance = editDistance(input.toLowerCase(), name.toLowerCase());
21748
+ const limit = Math.min(2, Math.floor(name.length / 3));
21749
+ if (distance <= limit && distance < bestDistance) {
21750
+ bestDistance = distance;
21751
+ best = name;
21752
+ }
21753
+ }
21634
21754
  return best;
21635
21755
  }
21756
+ function editDistance(a, b) {
21757
+ const d3 = Array.from(
21758
+ { length: a.length + 1 },
21759
+ (_2, i) => Array.from({ length: b.length + 1 }, (_3, j2) => i === 0 ? j2 : j2 === 0 ? i : 0)
21760
+ );
21761
+ for (let i = 1; i <= a.length; i++) {
21762
+ for (let j2 = 1; j2 <= b.length; j2++) {
21763
+ const cost = a[i - 1] === b[j2 - 1] ? 0 : 1;
21764
+ d3[i][j2] = Math.min(d3[i - 1][j2] + 1, d3[i][j2 - 1] + 1, d3[i - 1][j2 - 1] + cost);
21765
+ if (i > 1 && j2 > 1 && a[i - 1] === b[j2 - 2] && a[i - 2] === b[j2 - 1]) {
21766
+ d3[i][j2] = Math.min(d3[i][j2], d3[i - 2][j2 - 2] + 1);
21767
+ }
21768
+ }
21769
+ }
21770
+ return d3[a.length][b.length];
21771
+ }
21636
21772
  function similarity(a, b) {
21637
21773
  if (a === b) return 1;
21638
21774
  if (a.length < 2 || b.length < 2) return 0;
@@ -21701,7 +21837,7 @@ function showCompanionHints(names) {
21701
21837
 
21702
21838
  // cli/src/index.ts
21703
21839
  var import_picocolors4 = __toESM(require_picocolors());
21704
- var VERSION = "0.1.18";
21840
+ var VERSION = "0.1.20";
21705
21841
  var HELP = `
21706
21842
  ${import_picocolors4.default.bold("7onic")} \u2014 Add 7onic design system components to your project
21707
21843
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "7onic",
3
- "version": "0.1.18",
3
+ "version": "0.1.20",
4
4
  "description": "CLI for adding 7onic design system components to your project",
5
5
  "bin": {
6
6
  "7onic": "./dist/index.js"