{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "date-picker-styled",
  "title": "Picker-styled date",
  "description": "Styled date: the Picker-styled set. 5 decorative date variations (SimpleDatePicker, RangeDatePicker, GlassDatePicker, InlineDatePicker, IconDatePicker) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2",
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/date-picker-styled.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Calendar, ChevronLeft, ChevronRight } from \"lucide-react\"\nimport { AnimatePresence, motion, useReducedMotion, type Transition } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Date picker family: 5 decorative self-contained date pickers. NO radix, NO native\n   input, NO portal, NO Intl. Each export is a complete picker: a relative\n   inline-flex wrapper + a real trigger (role=\"combobox\", the selected date) + a\n   small month-grid calendar panel (role=\"grid\") absolutely positioned BELOW the\n   trigger. Picking a day updates the value and closes the panel. It closes on an\n   outside click (window pointerdown, with inner clicks ignored via the wrapper ref)\n   and on Escape.\n\n   CRITICAL: to avoid an SSR/hydration mismatch the visible month derives from a\n   FIXED value (the month of the selected date if there is one, otherwise\n   FIXED_MONTH = 2025-01) - NEVER today. The date format is manual (YYYY-MM-DD),\n   with NO locale-dependent Intl -> deterministic. Controlled (value/onChange) +\n   uncontrolled (defaultValue). Color comes ONLY from tokens, via alpha color-mix.\n   Only a fade under reduced motion. */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\n/* Trigger yuksekligi base kontrol olcegiyle hizali (sm h-8, md h-9, lg h-10, xl h-12). */\nconst triggerHeight: Record<StyledSize, string> = {\n  sm: \"h-8 text-sm\",\n  md: \"h-9 text-sm\",\n  lg: \"h-10 text-base\",\n  xl: \"h-12 text-base\",\n}\n\n/* SSR-guvenli sabit gorunen ay. today ASLA kullanilmaz. */\nconst FIXED_MONTH = new Date(2025, 0, 1)\n\nconst MONTH_NAMES = [\n  \"January\",\n  \"February\",\n  \"March\",\n  \"April\",\n  \"May\",\n  \"June\",\n  \"July\",\n  \"August\",\n  \"September\",\n  \"October\",\n  \"November\",\n  \"December\",\n]\n\nconst WEEKDAY_LABELS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"]\n\nfunction pad2(n: number): string {\n  return n < 10 ? `0${n}` : `${n}`\n}\n\n/* Locale bagimsiz, deterministik format. */\nfunction formatDate(d: Date): string {\n  return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`\n}\n\nfunction startOfMonth(d: Date): Date {\n  return new Date(d.getFullYear(), d.getMonth(), 1)\n}\n\nfunction daysInMonth(year: number, month: number): number {\n  return new Date(year, month + 1, 0).getDate()\n}\n\nfunction sameDay(a: Date | undefined, b: Date | undefined): boolean {\n  return (\n    !!a &&\n    !!b &&\n    a.getFullYear() === b.getFullYear() &&\n    a.getMonth() === b.getMonth() &&\n    a.getDate() === b.getDate()\n  )\n}\n\nfunction isBetween(day: Date, start: Date | undefined, end: Date | undefined): boolean {\n  if (!start || !end) return false\n  const t = day.getTime()\n  const lo = Math.min(start.getTime(), end.getTime())\n  const hi = Math.max(start.getTime(), end.getTime())\n  return t > lo && t < hi\n}\n\n/* Controlled/uncontrolled single-value management. */\nfunction useControlledDate(\n  value: Date | undefined,\n  defaultValue: Date | undefined,\n  onChange?: (d: Date) => void\n): [Date | undefined, (d: Date) => void] {\n  const isControlled = value !== undefined\n  const [internal, setInternal] = React.useState<Date | undefined>(defaultValue)\n  const current = isControlled ? value : internal\n  const set = React.useCallback(\n    (d: Date) => {\n      if (!isControlled) setInternal(d)\n      onChange?.(d)\n    },\n    [isControlled, onChange]\n  )\n  return [current, set]\n}\n\n/* Escape + disari tiklama ile kapanma. */\nfunction useDismiss(open: boolean, onClose: () => void, ref: React.RefObject<HTMLDivElement | null>) {\n  React.useEffect(() => {\n    if (!open) return\n    const onKey = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") onClose()\n    }\n    const onPointer = (e: PointerEvent) => {\n      const node = ref.current\n      if (node && e.target instanceof Node && !node.contains(e.target)) {\n        onClose()\n      }\n    }\n    window.addEventListener(\"keydown\", onKey)\n    window.addEventListener(\"pointerdown\", onPointer)\n    return () => {\n      window.removeEventListener(\"keydown\", onKey)\n      window.removeEventListener(\"pointerdown\", onPointer)\n    }\n  }, [open, onClose, ref])\n}\n\nconst springTransition: Transition = { type: \"spring\", stiffness: 340, damping: 26 }\n\nconst panelMotion = {\n  initial: { opacity: 0, scale: 0.96, y: -6 },\n  animate: { opacity: 1, scale: 1, y: 0 },\n  exit: { opacity: 0, scale: 0.96, y: -6 },\n  transition: springTransition,\n}\n\nconst triggerBase =\n  \"inline-flex w-full select-none items-center gap-2 whitespace-nowrap rounded-lg px-3 font-medium outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\n\nconst navBtn =\n  \"inline-flex size-7 items-center justify-center rounded-md text-muted-foreground outline-none transition-colors hover:bg-[color-mix(in_oklab,var(--color-foreground)_6%,transparent)] hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0\"\n\nconst dayBase =\n  \"relative inline-flex size-8 items-center justify-center rounded-md text-sm text-foreground outline-none transition-colors hover:bg-[color-mix(in_oklab,var(--color-foreground)_6%,transparent)] focus-visible:ring-[3px] focus-visible:ring-ring/50\"\n\nconst daySelected =\n  \"bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--color-primary)_90%,transparent)]\"\n\nconst dayRange =\n  \"rounded-none bg-[color-mix(in_oklab,var(--color-primary)_18%,transparent)] text-foreground\"\n\n/* The shared calendar body: a header (the month name + prev/next) + a weekday row +\n   a role=\"grid\" day grid. renderDay returns every real day as a <button>. */\nfunction CalendarBody({\n  month,\n  onMonthChange,\n  renderDay,\n  className,\n}: {\n  month: Date\n  onMonthChange: (d: Date) => void\n  renderDay: (day: Date) => React.ReactNode\n  className?: string\n}) {\n  const year = month.getFullYear()\n  const m = month.getMonth()\n  const leading = new Date(year, m, 1).getDay()\n  const total = daysInMonth(year, m)\n\n  const cells: (Date | null)[] = []\n  for (let i = 0; i < leading; i++) cells.push(null)\n  for (let d = 1; d <= total; d++) cells.push(new Date(year, m, d))\n\n  return (\n    <div data-slot=\"styled-date-picker-calendar\" className={cn(\"flex flex-col gap-2\", className)}>\n      <div className=\"flex items-center justify-between px-1\">\n        <button\n          type=\"button\"\n          aria-label=\"Previous month\"\n          className={navBtn}\n          onClick={() => onMonthChange(new Date(year, m - 1, 1))}\n        >\n          <ChevronLeft />\n        </button>\n        <div className=\"text-sm font-semibold text-foreground\">\n          {MONTH_NAMES[m]} {year}\n        </div>\n        <button\n          type=\"button\"\n          aria-label=\"Next month\"\n          className={navBtn}\n          onClick={() => onMonthChange(new Date(year, m + 1, 1))}\n        >\n          <ChevronRight />\n        </button>\n      </div>\n\n      <div className=\"grid grid-cols-7 gap-0.5\">\n        {WEEKDAY_LABELS.map((w) => (\n          <div\n            key={w}\n            className=\"flex size-8 items-center justify-center text-xs font-medium text-muted-foreground\"\n          >\n            {w}\n          </div>\n        ))}\n      </div>\n\n      <div role=\"grid\" className=\"grid grid-cols-7 gap-0.5\">\n        {cells.map((day, i) =>\n          day === null ? (\n            <span key={`empty-${i}`} className=\"size-8\" aria-hidden=\"true\" />\n          ) : (\n            <React.Fragment key={formatDate(day)}>{renderDay(day)}</React.Fragment>\n          )\n        )}\n      </div>\n    </div>\n  )\n}\n\n/* Ortak popover kabugu: wrapper + trigger + AnimatePresence panel. */\nfunction PickerShell({\n  className,\n  trigger,\n  open,\n  setOpen,\n  panelClassName,\n  children,\n}: {\n  className?: string\n  trigger: (open: boolean) => React.ReactNode\n  open: boolean\n  setOpen: (o: boolean) => void\n  panelClassName?: string\n  children: React.ReactNode\n}) {\n  const reduce = useReducedMotion()\n  const wrapperRef = React.useRef<HTMLDivElement>(null)\n  useDismiss(open, () => setOpen(false), wrapperRef)\n\n  const fade = { initial: { opacity: 0 }, animate: { opacity: 1 }, exit: { opacity: 0 } }\n  const mp = reduce ? fade : panelMotion\n\n  return (\n    <div\n      ref={wrapperRef}\n      data-slot=\"styled-date-picker\"\n      className={cn(\"relative inline-flex w-64 flex-col\", className)}\n    >\n      <span\n        data-slot=\"styled-date-picker-trigger\"\n        className=\"inline-flex\"\n        onClick={() => setOpen(!open)}\n      >\n        {trigger(open)}\n      </span>\n\n      <AnimatePresence>\n        {open ? (\n          <motion.div\n            data-slot=\"styled-date-picker-popover\"\n            className={cn(\n              \"absolute left-0 top-full z-50 mt-2 w-64 origin-top rounded-xl border border-border bg-popover p-3 text-popover-foreground shadow-lg outline-none\",\n              panelClassName\n            )}\n            initial={mp.initial}\n            animate={mp.animate}\n            exit={mp.exit}\n            transition={reduce ? ({ duration: 0.12 } as Transition) : panelMotion.transition}\n          >\n            {children}\n          </motion.div>\n        ) : null}\n      </AnimatePresence>\n    </div>\n  )\n}\n\ninterface DatePickerProps {\n  className?: string\n  size?: StyledSize\n  placeholder?: string\n  value?: Date\n  defaultValue?: Date\n  onChange?: (d: Date) => void\n}\n\n/* SimpleDatePicker: cerceveli trigger + takvim popover. */\nexport function SimpleDatePicker({\n  className,\n  size = \"md\",\n  placeholder = \"Pick a date\",\n  value,\n  defaultValue,\n  onChange,\n}: DatePickerProps) {\n  const [selected, setSelected] = useControlledDate(value, defaultValue, onChange)\n  const [open, setOpen] = React.useState(false)\n  const [month, setMonth] = React.useState(() => startOfMonth(selected ?? FIXED_MONTH))\n\n  const pick = (day: Date) => {\n    setSelected(day)\n    setMonth(startOfMonth(day))\n    setOpen(false)\n  }\n\n  return (\n    <PickerShell\n      className={className}\n      open={open}\n      setOpen={setOpen}\n      trigger={(isOpen) => (\n        <button\n          type=\"button\"\n          role=\"combobox\"\n          aria-expanded={isOpen}\n          aria-haspopup=\"grid\"\n          className={cn(\n            triggerBase,\n            triggerHeight[size],\n            \"justify-between border border-field-border bg-transparent text-foreground hover:bg-[color-mix(in_oklab,var(--color-foreground)_4%,transparent)]\"\n          )}\n        >\n          <span className={cn(!selected && \"text-muted-foreground\")}>\n            {selected ? formatDate(selected) : placeholder}\n          </span>\n          <Calendar className=\"text-muted-foreground\" />\n        </button>\n      )}\n    >\n      <CalendarBody\n        month={month}\n        onMonthChange={setMonth}\n        renderDay={(day) => (\n          <button\n            type=\"button\"\n            role=\"gridcell\"\n            aria-selected={sameDay(day, selected)}\n            className={cn(dayBase, sameDay(day, selected) && daySelected)}\n            onClick={() => pick(day)}\n          >\n            {day.getDate()}\n          </button>\n        )}\n      />\n    </PickerShell>\n  )\n}\n\n/* RangeDatePicker: a start-to-end range trigger plus range selection in the popover. The shared signature (value/defaultValue: Date) seeds the start; the second click sets the end and onChange is called with the end day. */\nexport function RangeDatePicker({\n  className,\n  size = \"md\",\n  placeholder = \"Pick a range\",\n  value,\n  defaultValue,\n  onChange,\n}: DatePickerProps) {\n  const [open, setOpen] = React.useState(false)\n  const [start, setStart] = React.useState<Date | undefined>(value ?? defaultValue)\n  const [end, setEnd] = React.useState<Date | undefined>(undefined)\n  const [month, setMonth] = React.useState(() => startOfMonth(value ?? defaultValue ?? FIXED_MONTH))\n\n  const pick = (day: Date) => {\n    if (!start || (start && end)) {\n      setStart(day)\n      setEnd(undefined)\n      onChange?.(day)\n      return\n    }\n    if (day.getTime() < start.getTime()) {\n      setStart(day)\n      onChange?.(day)\n      return\n    }\n    setEnd(day)\n    onChange?.(day)\n    setOpen(false)\n  }\n\n  const label =\n    start && end\n      ? `${formatDate(start)} - ${formatDate(end)}`\n      : start\n        ? `${formatDate(start)} - ...`\n        : placeholder\n\n  return (\n    <PickerShell\n      className={cn(\"w-72\", className)}\n      panelClassName=\"w-72\"\n      open={open}\n      setOpen={setOpen}\n      trigger={(isOpen) => (\n        <button\n          type=\"button\"\n          role=\"combobox\"\n          aria-expanded={isOpen}\n          aria-haspopup=\"grid\"\n          className={cn(\n            triggerBase,\n            triggerHeight[size],\n            \"justify-between border border-field-border bg-transparent text-foreground hover:bg-[color-mix(in_oklab,var(--color-foreground)_4%,transparent)]\"\n          )}\n        >\n          <span className={cn(!start && \"text-muted-foreground\")}>{label}</span>\n          <Calendar className=\"text-muted-foreground\" />\n        </button>\n      )}\n    >\n      <CalendarBody\n        month={month}\n        onMonthChange={setMonth}\n        renderDay={(day) => {\n          const isEnd = sameDay(day, start) || sameDay(day, end)\n          const inside = isBetween(day, start, end)\n          return (\n            <button\n              type=\"button\"\n              role=\"gridcell\"\n              aria-selected={isEnd}\n              className={cn(dayBase, inside && dayRange, isEnd && daySelected)}\n              onClick={() => pick(day)}\n            >\n              {day.getDate()}\n            </button>\n          )\n        }}\n      />\n    </PickerShell>\n  )\n}\n\n/* GlassDatePicker: buzlu cam trigger + popover. */\nexport function GlassDatePicker({\n  className,\n  size = \"md\",\n  placeholder = \"Pick a date\",\n  value,\n  defaultValue,\n  onChange,\n}: DatePickerProps) {\n  const [selected, setSelected] = useControlledDate(value, defaultValue, onChange)\n  const [open, setOpen] = React.useState(false)\n  const [month, setMonth] = React.useState(() => startOfMonth(selected ?? FIXED_MONTH))\n\n  const pick = (day: Date) => {\n    setSelected(day)\n    setMonth(startOfMonth(day))\n    setOpen(false)\n  }\n\n  const glass =\n    \"border-border bg-[color-mix(in_oklab,var(--color-popover)_75%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-popover)_55%,transparent)] supports-[backdrop-filter]:backdrop-blur-xl shadow-[inset_0_1px_0_color-mix(in_oklab,var(--color-foreground)_12%,transparent)]\"\n\n  return (\n    <PickerShell\n      className={className}\n      panelClassName={glass}\n      open={open}\n      setOpen={setOpen}\n      trigger={(isOpen) => (\n        <button\n          type=\"button\"\n          role=\"combobox\"\n          aria-expanded={isOpen}\n          aria-haspopup=\"grid\"\n          className={cn(\n            triggerBase,\n            triggerHeight[size],\n            \"justify-between border border-border text-foreground\",\n            \"bg-[color-mix(in_oklab,var(--color-surface-2)_70%,transparent)] supports-[backdrop-filter]:bg-[color-mix(in_oklab,var(--color-surface-2)_45%,transparent)] supports-[backdrop-filter]:backdrop-blur-md hover:bg-[color-mix(in_oklab,var(--color-surface-2)_60%,transparent)]\"\n          )}\n        >\n          <span className={cn(!selected && \"text-muted-foreground\")}>\n            {selected ? formatDate(selected) : placeholder}\n          </span>\n          <Calendar className=\"text-muted-foreground\" />\n        </button>\n      )}\n    >\n      <CalendarBody\n        month={month}\n        onMonthChange={setMonth}\n        renderDay={(day) => (\n          <button\n            type=\"button\"\n            role=\"gridcell\"\n            aria-selected={sameDay(day, selected)}\n            className={cn(dayBase, sameDay(day, selected) && daySelected)}\n            onClick={() => pick(day)}\n          >\n            {day.getDate()}\n          </button>\n        )}\n      />\n    </PickerShell>\n  )\n}\n\n/* InlineDatePicker: a calendar embedded under a small label, with NO trigger toggle. */\nexport function InlineDatePicker({\n  className,\n  size = \"md\",\n  placeholder = \"Selected date\",\n  value,\n  defaultValue,\n  onChange,\n}: DatePickerProps) {\n  const [selected, setSelected] = useControlledDate(value, defaultValue, onChange)\n  const [month, setMonth] = React.useState(() => startOfMonth(selected ?? FIXED_MONTH))\n\n  const pick = (day: Date) => {\n    setSelected(day)\n    setMonth(startOfMonth(day))\n  }\n\n  const labelSize = size === \"lg\" || size === \"xl\" ? \"text-sm\" : \"text-xs\"\n\n  return (\n    <div\n      data-slot=\"styled-date-picker\"\n      className={cn(\n        \"inline-flex w-64 flex-col gap-2 rounded-xl border border-border bg-popover p-3 text-popover-foreground shadow-sm\",\n        className\n      )}\n    >\n      <div className={cn(\"px-1 font-medium text-muted-foreground\", labelSize)}>\n        {selected ? formatDate(selected) : placeholder}\n      </div>\n      <CalendarBody\n        month={month}\n        onMonthChange={setMonth}\n        renderDay={(day) => (\n          <button\n            type=\"button\"\n            role=\"gridcell\"\n            aria-selected={sameDay(day, selected)}\n            className={cn(dayBase, sameDay(day, selected) && daySelected)}\n            onClick={() => pick(day)}\n          >\n            {day.getDate()}\n          </button>\n        )}\n      />\n    </div>\n  )\n}\n\n/* IconDatePicker: onde takvim ikonu olan minimal trigger + popover. */\nexport function IconDatePicker({\n  className,\n  size = \"md\",\n  placeholder = \"Pick a date\",\n  value,\n  defaultValue,\n  onChange,\n}: DatePickerProps) {\n  const [selected, setSelected] = useControlledDate(value, defaultValue, onChange)\n  const [open, setOpen] = React.useState(false)\n  const [month, setMonth] = React.useState(() => startOfMonth(selected ?? FIXED_MONTH))\n\n  const pick = (day: Date) => {\n    setSelected(day)\n    setMonth(startOfMonth(day))\n    setOpen(false)\n  }\n\n  return (\n    <PickerShell\n      className={className}\n      open={open}\n      setOpen={setOpen}\n      trigger={(isOpen) => (\n        <button\n          type=\"button\"\n          role=\"combobox\"\n          aria-expanded={isOpen}\n          aria-haspopup=\"grid\"\n          className={cn(\n            triggerBase,\n            triggerHeight[size],\n            \"justify-start border-b border-field-border bg-transparent px-1 text-foreground rounded-none hover:bg-[color-mix(in_oklab,var(--color-foreground)_4%,transparent)]\"\n          )}\n        >\n          <Calendar className=\"text-muted-foreground\" />\n          <span className={cn(!selected && \"text-muted-foreground\")}>\n            {selected ? formatDate(selected) : placeholder}\n          </span>\n        </button>\n      )}\n    >\n      <CalendarBody\n        month={month}\n        onMonthChange={setMonth}\n        renderDay={(day) => (\n          <button\n            type=\"button\"\n            role=\"gridcell\"\n            aria-selected={sameDay(day, selected)}\n            className={cn(dayBase, sameDay(day, selected) && daySelected)}\n            onClick={() => pick(day)}\n          >\n            {day.getDate()}\n          </button>\n        )}\n      />\n    </PickerShell>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/date-picker-styled.tsx"
    }
  ],
  "categories": [
    "styled",
    "date"
  ],
  "type": "registry:component"
}