{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "date-picker",
  "title": "Date picker",
  "description": "A date inside a sentence, like the select. It opens the month on a leader line; choose a day and it is written into the sentence in italic.",
  "registryDependencies": [
    "https://thedirectors.agency/ui/r/0nlytype.json",
    "https://thedirectors.agency/ui/r/calendar.json",
    "https://thedirectors.agency/ui/r/field.json",
    "https://thedirectors.agency/ui/r/popover.json"
  ],
  "files": [
    {
      "path": "registry/0nlytype/ui/date-picker.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Calendar, type CalendarProps } from \"@/components/ui/calendar\"\nimport { useFieldControl } from \"@/components/ui/field\"\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/components/ui/popover\"\n\ntype DatePickerProps = Omit<React.ComponentProps<\"button\">, \"value\" | \"defaultValue\" | \"onChange\" | \"type\"> & {\n  value?: Date\n  defaultValue?: Date\n  onValueChange?: (date: Date | undefined) => void\n  /** The words before the date: \"Deliver the brief by\". Clicking them opens the month. */\n  label?: string\n  /** What the line says before a day is chosen. */\n  placeholder?: string\n  /** Days before today can't be chosen. */\n  disablePast?: boolean\n  locale?: string\n  /** How the month draws time: \"dots\" (the default, the poster), \"ruler\", \"ghost\" or \"parenthesis\". */\n  variant?: CalendarProps[\"variant\"]\n  /** Classes for the sentence around the date. className goes to the button. */\n  rootClassName?: string\n  /** Pins a state for documentation (\"hover\", \"focus\"); set on the button. */\n  \"data-force\"?: string\n}\n\n/** \"Thursday, 1 October\": the date as words. */\nfunction words(date: Date, locale: string) {\n  let previous = \"\"\n  return new Intl.DateTimeFormat(locale, { weekday: \"long\", day: \"numeric\", month: \"long\" })\n    .formatToParts(date)\n    .map((part) => {\n      const out = part.type === \"literal\" && previous === \"weekday\" && !part.value.includes(\",\") ? \", \" : part.value\n      previous = part.type\n      return out\n    })\n    .join(\"\")\n}\n\n/**\n * A date inside a sentence, like the select. It opens the month on a leader line;\n * choose a day and it is written into the sentence in italic. Works alone or inside a Field.\n */\nfunction DatePicker({\n  value: valueProp,\n  defaultValue,\n  onValueChange,\n  label,\n  placeholder = \"choose a day\",\n  disablePast,\n  locale = \"en-GB\",\n  variant,\n  className,\n  rootClassName,\n  ...props\n}: DatePickerProps) {\n  const field = useFieldControl()\n  const [open, setOpen] = React.useState(false)\n  const [own, setOwn] = React.useState(defaultValue)\n  const value = valueProp ?? own\n  const id = props.id ?? field.id\n  const Root = label ? \"label\" : \"span\"\n\n  const pick = (date: Date) => {\n    if (valueProp === undefined) setOwn(date)\n    onValueChange?.(date)\n    setOpen(false)\n  }\n\n  // A Field's label names the button, which hides the button's own words; say the date as a description too.\n  const spoken = field.id && value ? `${field.id}-date` : undefined\n\n  return (\n    <Root data-slot=\"date-picker\" className={cn(\"ot-date-root\", rootClassName)}>\n      {label ? <span>{label}</span> : null}\n      <Popover open={open} onOpenChange={setOpen}>\n        <PopoverTrigger asChild>\n          <button\n            type=\"button\"\n            data-slot=\"date-picker-trigger\"\n            data-set={value ? \"\" : undefined}\n            className={cn(\"ot-date\", className)}\n            {...props}\n            id={id}\n            data-invalid={field[\"aria-invalid\"] ? \"\" : undefined}\n            aria-describedby={[props[\"aria-describedby\"] ?? field[\"aria-describedby\"], spoken].filter(Boolean).join(\" \") || undefined}\n          >\n            {value ? words(value, locale) : placeholder}\n          </button>\n        </PopoverTrigger>\n        <PopoverContent\n          data-slot=\"date-picker-content\"\n          className=\"ot-date-pop\"\n          aria-label={label ?? \"Choose a day\"}\n          // Open on the day (the chosen one, else today), not on the month's first arrow.\n          onOpenAutoFocus={(e) => {\n            const day = (e.currentTarget as HTMLElement).querySelector<HTMLElement>('[data-slot=\"calendar-day\"][tabindex=\"0\"]')\n            if (!day) return\n            e.preventDefault()\n            day.focus()\n          }}\n        >\n          <Calendar value={value} disablePast={disablePast} locale={locale} variant={variant} onValueChange={pick} />\n        </PopoverContent>\n      </Popover>\n      {spoken ? (\n        <span id={spoken} className=\"ot-sr\">\n          {words(value!, locale)}\n        </span>\n      ) : null}\n    </Root>\n  )\n}\n\nexport { DatePicker, type DatePickerProps }\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/0nlytype/styles/date-picker.css",
      "content": "@layer components {\n  /* ── ot-date ── a date inside a sentence, like the select. The month hangs from it\n     on a leader line (a ot-pop holding a Calendar); the chosen day is written in italic. */\n  .ot-date-root { display: inline-flex; flex-wrap: wrap; align-items: baseline; column-gap: 0.25em; font-size: var(--ot-mp); line-height: var(--ot-mp-lh); color: var(--ot-graphite); }\n  .ot-field > .ot-date-root { grid-column: 1 / -1; justify-self: start; }\n  .ot-date {\n    appearance: none; border: 0; border-radius: 0; margin: 0; padding: 0 0 0.1em; cursor: pointer;\n    background: linear-gradient(var(--ot-rule-strong), var(--ot-rule-strong)) no-repeat 0 100% / 100% var(--ot-hairline);\n    color: var(--ot-pencil); font: inherit; line-height: 1.2;\n    transition: background-color var(--ot-allegro);\n  }\n  :is(.ot-date:hover, .ot-date[data-force~=\"hover\"]) { background-image: linear-gradient(var(--ot-ink), var(--ot-ink)); }\n  .ot-date[data-set] { color: var(--ot-ink); font-family: var(--ot-expression); font-style: italic; font-size: calc(var(--ot-expression-scale) * 1em); }\n  .ot-date[data-invalid] { background-image: linear-gradient(var(--ot-signal), var(--ot-signal)); }\n  .ot-date:disabled { color: var(--ot-pencil); cursor: not-allowed; background-image: none; }\n  /* The month at popover size: the same poster, its numeral a step down. */\n  .ot-date-pop > .ot-month { --big: var(--ot-ff); width: min(21rem, 78vw); gap: var(--ot-space-5); }\n}\n",
      "type": "registry:file",
      "target": "styles/0nlytype/date-picker.css"
    }
  ],
  "css": {
    "@import \"../styles/0nlytype/date-picker.css\"": {}
  },
  "meta": {
    "movement": "VI",
    "underneath": "radix",
    "contract": "ot-date"
  },
  "type": "registry:ui"
}
