{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "oods-date-picker",
  "type": "registry:component",
  "title": "OODS Foundry DatePicker",
  "description": "React adapter for OODS DatePicker on shadcn/ui's Radix and Base UI bases. Keeps the native date input and adds the team calendar/popover, including min, max, step, disabled and readOnly. pickerClassName/pickerStyle apply to the native input; density is metadata only.",
  "dependencies": [
    "@oods/components-react@0.11.2"
  ],
  "registryDependencies": [
    "input",
    "label",
    "calendar",
    "popover",
    "button"
  ],
  "files": [
    {
      "path": "components/oods/date-picker.tsx",
      "target": "components/oods/date-picker.tsx",
      "type": "registry:component",
      "content": "import * as React from 'react';\nimport type { DatePickerProps } from '@oods/components-react';\nimport { Input } from '@/registry/new-york-v4/ui/input';\nimport { Label } from '@/registry/new-york-v4/ui/label';\nimport { Button } from '@/registry/new-york-v4/ui/button';\nimport { Calendar } from '@/registry/new-york-v4/ui/calendar';\nimport { Popover, PopoverTrigger, PopoverContent } from '@/registry/new-york-v4/ui/popover';\n\nconst dateValue = (date: Date) => `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;\nconst parseDate = (value: unknown) => {\n  if (typeof value !== 'string' || !/^\\d{4}-\\d{2}-\\d{2}$/.test(value)) return undefined;\n  const date = new Date(`${value}T12:00:00`);\n  return Number.isFinite(date.getTime()) && dateValue(date) === value ? date : undefined;\n};\n\nexport const OodsDatePicker = React.forwardRef<HTMLInputElement, DatePickerProps>(function OodsDatePicker(\n  { id, label, help, description, validation, density = 'comfortable', requiredIndicator, className, style,\n    inputClassName, inputStyle, pickerClassName, pickerStyle, onChange, onValueChange, onUpdate, required,\n    value, defaultValue, disabled, readOnly, min, max, step, 'aria-describedby': describedBy, ...props }, ref,\n) {\n  const native = React.useRef<HTMLInputElement>(null);\n  React.useImperativeHandle(ref, () => native.current!);\n  const [local, setLocal] = React.useState(String(defaultValue ?? ''));\n  const [open, setOpen] = React.useState(false);\n  const selected = value === undefined ? local : String(value);\n  const details = help ?? description;\n  const validationId = validation?.id ?? `${id}-validation`;\n  const descriptions = [describedBy, details ? `${id}-description` : '', validation?.message ? validationId : ''].filter(Boolean).join(' ') || undefined;\n  const disallowed = (date: Date) => {\n    const next = dateValue(date);\n    if ((parseDate(min) && next < String(min)) || (parseDate(max) && next > String(max))) return true;\n    const interval = step === 'any' ? 1 : Number(step ?? 1);\n    const base = parseDate(min) ?? parseDate(String(value ?? defaultValue ?? '')) ?? new Date('1970-01-01T12:00:00');\n    return interval > 0 && Math.round((Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()) - Date.UTC(base.getFullYear(), base.getMonth(), base.getDate())) / 86400000) % interval !== 0;\n  };\n  const choose = (next: string) => {\n    if (!native.current || disabled || readOnly) return;\n    // Bypass React's value tracker so the existing native onChange contract sees the calendar edit.\n    Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')!.set!.call(native.current, next);\n    native.current.dispatchEvent(new Event('input', { bubbles: true }));\n    setOpen(false);\n    native.current.focus();\n  };\n  return <div className={className} style={style} data-density={density} data-validation-state={validation?.state} data-oods-component={undefined} data-oods-adapter=\"DatePicker\">\n    <Label htmlFor={id}>{label}{required && requiredIndicator !== null ? requiredIndicator ?? <span aria-hidden=\"true\"> *</span> : null}</Label>\n    <div className=\"flex items-center gap-2\">\n      <Input {...props} ref={native} id={id} type=\"date\" value={value} defaultValue={defaultValue} disabled={disabled} readOnly={readOnly} required={required} min={min} max={max} step={step}\n        className={[inputClassName, pickerClassName].filter(Boolean).join(' ')} style={{ ...inputStyle, ...pickerStyle }} data-oods-component={undefined}\n        aria-describedby={descriptions} aria-invalid={props['aria-invalid'] ?? (validation?.state === 'error' || undefined)}\n        onChange={event => { onChange?.(event); const next = event.currentTarget.value; if (value === undefined) setLocal(next); if (!event.defaultPrevented) { onValueChange?.(next); onUpdate?.(next); } }} />\n      <Popover open={open} onOpenChange={next => { if (next && value === undefined) setLocal(native.current?.value ?? ''); setOpen(next); }}>\n        <PopoverTrigger disabled={disabled || readOnly} aria-label={`Open calendar for ${typeof label === 'string' ? label : id}`} className=\"inline-flex h-9 items-center rounded-md border bg-background px-3 text-sm text-foreground\">Calendar</PopoverTrigger>\n        <PopoverContent className=\"w-auto p-2\">\n          <Calendar mode=\"single\" selected={parseDate(selected)} defaultMonth={parseDate(selected)} disabled={disallowed} onSelect={date => { if (date) choose(dateValue(date)); }} />\n          <Button type=\"button\" variant=\"ghost\" onClick={() => choose('')}>Clear date</Button>\n        </PopoverContent>\n      </Popover>\n    </div>\n    {details ? <p id={`${id}-description`} className=\"text-sm text-muted-foreground\">{details}</p> : null}\n    {validation?.message ? <p id={validationId} role={validation.state === 'error' ? 'alert' : 'status'} aria-live={validation.state === 'error' ? 'assertive' : 'polite'}>{validation.message}</p> : null}\n  </div>;\n});\n"
    }
  ]
}
