{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "date-picker-story",
  "title": "Date Picker Story",
  "author": "Lloyd Richards <lloyd.d.richards@gmail.com>",
  "description": "Interactive Storybook stories demonstrating date picker component usage and variants",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "calendar",
    "label",
    "input",
    "popover"
  ],
  "files": [
    {
      "path": "registry/ui/date-picker-story/date-picker-base.stories.tsx",
      "content": "import { expect, userEvent, waitFor, within } from \"storybook/test\";\n// Replace nextjs-vite with the name of your framework\nimport type { Meta, StoryObj } from \"@storybook/nextjs-vite\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { Calendar } from \"@/components/ui/calendar\";\nimport { Input } from \"@/components/ui/input\";\nimport { Label } from \"@/components/ui/label\";\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\";\nimport { CalendarIcon, ChevronDownIcon } from \"lucide-react\";\nimport { useState } from \"react\";\nimport { action } from \"storybook/actions\";\n\n/**\n * A window overlaid on either the primary window or another dialog window,\n * rendering the content underneath inert.\n */\nconst meta = {\n  title: \"ui/base/DatePicker\",\n  component: Calendar,\n  tags: [\"autodocs\"],\n  argTypes: {},\n  parameters: {\n    layout: \"centered\",\n  },\n} satisfies Meta<typeof Calendar>;\n\nexport default meta;\n\ntype Story = StoryObj<typeof meta>;\n\n/**\n * Combination of the calendar and a button that opens a popover.\n */\nexport const WithPopover: Story = {\n  args: {\n    captionLayout: \"dropdown\",\n  },\n\n  render: (args) => {\n    const [open, setOpen] = useState(false);\n    const [date, setDate] = useState<Date | undefined>(undefined);\n    return (\n      <div className=\"flex flex-col gap-3\">\n        <Label htmlFor=\"date\" className=\"px-1\">\n          Date of birth\n        </Label>\n        <Popover open={open} onOpenChange={setOpen}>\n          <PopoverTrigger\n            render={\n              <Button\n                variant=\"outline\"\n                id=\"date\"\n                className=\"w-48 justify-between font-normal\"\n              />\n            }\n          >\n            {date ? date.toLocaleDateString() : \"Select date\"}\n            <ChevronDownIcon />\n          </PopoverTrigger>\n          <PopoverContent className=\"w-auto overflow-hidden p-0\" align=\"start\">\n            <Calendar\n              {...args}\n              mode=\"single\"\n              selected={date}\n              onSelect={(date) => {\n                setDate(date);\n                setOpen(false);\n                action(\"date selected\")(date);\n              }}\n            />\n          </PopoverContent>\n        </Popover>\n      </div>\n    );\n  },\n};\n\nexport const ShouldOpenPopover: Story = {\n  ...WithPopover,\n  name: \"when clicking the button, should open the popover to select a date\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement.ownerDocument.body);\n    await step(\"Open the popover\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: \"Date of birth\" }),\n      );\n      await waitFor(() =>\n        expect(\n          canvasElement.ownerDocument.body.querySelector(\".rdp-root\"),\n        ).toBeVisible(),\n      );\n    });\n    await step(\"Select a date\", async () => {\n      const dateButtons = await canvas.findAllByRole(\"button\", {\n        name: /1st/i,\n      });\n      await userEvent.click(dateButtons[0]);\n    });\n  },\n};\n\nconst formatDate = (date: Date | undefined) => {\n  return date\n    ? date.toLocaleDateString(\"en-US\", {\n        day: \"2-digit\",\n        month: \"long\",\n        year: \"numeric\",\n      })\n    : \"\";\n};\n\nconst isValidDate = (date: Date | undefined) =>\n  date ? !isNaN(date.getTime()) : false;\n\n/**\n * Combination of the calendar and an input field that allows typing a date.\n */\nexport const WithInput: Story = {\n  args: {\n    captionLayout: \"dropdown\",\n  },\n\n  render: (args) => {\n    const [open, setOpen] = useState(false);\n    const [date, setDate] = useState<Date | undefined>(new Date(\"2025-06-01\"));\n    const [month, setMonth] = useState<Date | undefined>(date);\n    const [value, setValue] = useState(formatDate(date));\n\n    return (\n      <div className=\"flex flex-col gap-3\">\n        <Label htmlFor=\"date\" className=\"px-1\">\n          Subscription Date\n        </Label>\n        <div className=\"relative flex gap-2\">\n          <Input\n            id=\"date\"\n            value={value}\n            placeholder=\"June 01, 2025\"\n            className=\"bg-background pr-10\"\n            onChange={(e) => {\n              const date = new Date(e.target.value);\n              setValue(e.target.value);\n              if (isValidDate(date)) {\n                setDate(date);\n                setMonth(date);\n                action(\"date input changed\")(date);\n              }\n            }}\n            onKeyDown={(e) => {\n              if (e.key === \"ArrowDown\") {\n                e.preventDefault();\n                setOpen(true);\n              }\n            }}\n          />\n          <Popover open={open} onOpenChange={setOpen}>\n            <PopoverTrigger\n              render={\n                <Button\n                  id=\"date-picker\"\n                  variant=\"ghost\"\n                  className=\"absolute top-1/2 right-2 size-6 -translate-y-1/2\"\n                />\n              }\n            >\n              <CalendarIcon className=\"size-3.5\" />\n              <span className=\"sr-only\">Select date</span>\n            </PopoverTrigger>\n            <PopoverContent\n              className=\"w-auto overflow-hidden p-0\"\n              align=\"end\"\n              alignOffset={-8}\n              sideOffset={10}\n            >\n              <Calendar\n                {...args}\n                mode=\"single\"\n                selected={date}\n                month={month}\n                onMonthChange={setMonth}\n                onSelect={(date) => {\n                  setDate(date);\n                  setValue(formatDate(date));\n                  setOpen(false);\n                  action(\"date selected\")(date);\n                }}\n              />\n            </PopoverContent>\n          </Popover>\n        </div>\n      </div>\n    );\n  },\n};\n\nexport const ShouldEnterTextDate: Story = {\n  ...WithInput,\n  name: \"when typing a valid date, should update the input and close the calendar\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement.ownerDocument.body);\n    const input = await canvas.findByRole(\"textbox\", {\n      name: \"Subscription Date\",\n    });\n    await step(\"type a date\", async () => {\n      await userEvent.click(input);\n      await userEvent.clear(input);\n      await userEvent.type(input, \"July 21, 1999\");\n      await userEvent.keyboard(\"{enter}\");\n      expect(input).toHaveValue(\"July 21, 1999\");\n    });\n\n    await step(\"check the calendar\", async () => {\n      await userEvent.click(\n        await canvas.findByRole(\"button\", { name: \"Select date\" }),\n      );\n      await waitFor(() =>\n        expect(\n          canvas.queryByRole(\"button\", {\n            name: \"Wednesday, July 21st, 1999, selected\",\n          }),\n        ).toBeVisible(),\n      );\n    });\n  },\n};\n\n/**\n * Combination of the calendar and an input field that allows changing the time.\n */\nexport const WithDateTime: Story = {\n  args: {\n    captionLayout: \"dropdown\",\n  },\n\n  render: (args) => {\n    const [open, setOpen] = useState(false);\n    const [date, setDate] = useState<Date | undefined>(undefined);\n    return (\n      <div className=\"flex gap-4\">\n        <div className=\"flex flex-col gap-3\">\n          <Label htmlFor=\"date-picker\" className=\"px-1\">\n            Date\n          </Label>\n          <Popover open={open} onOpenChange={setOpen}>\n            <PopoverTrigger\n              render={\n                <Button\n                  variant=\"outline\"\n                  id=\"date-picker\"\n                  className=\"w-32 justify-between font-normal\"\n                />\n              }\n            >\n              {date ? date.toLocaleDateString() : \"Select date\"}\n              <ChevronDownIcon />\n            </PopoverTrigger>\n            <PopoverContent\n              className=\"w-auto overflow-hidden p-0\"\n              align=\"start\"\n            >\n              <Calendar\n                {...args}\n                mode=\"single\"\n                selected={date}\n                onSelect={(date) => {\n                  setDate(date);\n                  setOpen(false);\n                  action(\"date selected\")(date);\n                }}\n              />\n            </PopoverContent>\n          </Popover>\n        </div>\n        <div className=\"flex flex-col gap-3\">\n          <Label htmlFor=\"time-picker\" className=\"px-1\">\n            Time\n          </Label>\n          <Input\n            type=\"time\"\n            id=\"time-picker\"\n            step=\"1\"\n            disabled={!date}\n            defaultValue=\"10:30:00\"\n            onChange={(e) => {\n              if (!date) {\n                return;\n              }\n              const [hours, minutes, seconds] = e.target.value\n                .split(\":\")\n                .map(Number);\n              date.setHours(hours, minutes, seconds);\n              setDate(date);\n              action(\"time selected\")(date);\n            }}\n            className=\"bg-background appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none\"\n          />\n        </div>\n      </div>\n    );\n  },\n};\n\nexport const ShouldOpenCalendar: Story = {\n  ...WithDateTime,\n  name: \"when clicking the date button, should open the calendar to select a date\",\n  tags: [\"!dev\", \"!autodocs\"],\n  play: async ({ canvasElement, step }) => {\n    const canvas = within(canvasElement.ownerDocument.body);\n\n    await step(\"Open the date popover\", async () => {\n      const dateInput = await canvas.findByLabelText(\"Date\");\n      await userEvent.click(dateInput);\n      await waitFor(() =>\n        expect(\n          canvas.queryAllByRole(\"button\", { name: /1st/i }).at(0),\n        ).toBeVisible(),\n      );\n    });\n\n    const dateButtons = await canvas.findAllByRole(\"button\", { name: /1st/i });\n    await userEvent.click(dateButtons[0]);\n\n    await step(\"type a time\", async () => {\n      const timeInput = await canvas.findByLabelText(\"Time\");\n      await userEvent.click(timeInput);\n      await userEvent.type(timeInput, \"1\");\n    });\n  },\n};\n",
      "type": "registry:component"
    }
  ],
  "categories": [
    "ui",
    "storybook",
    "date-picker",
    "form"
  ],
  "type": "registry:component"
}