{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "contact-form",
  "version": "1.2.9",
  "category": "form",
  "meta": {
    "preview": "https://ui.manifest.build/previews/contact-form.png",
    "version": "1.2.9",
    "changelog": {
      "1.0.0": "Initial release with name, phone, email, message and file attachment fields",
      "1.1.0": "Made phone, email, and message fields optional with defaults",
      "1.2.0": "Added initialValues prop to pre-fill form fields",
      "1.2.1": "Added aria-label to file removal button for screen reader accessibility",
      "1.2.3": "Added comprehensive JSDoc documentation",
      "1.2.4": "Updated Props interface with decorative header and sub-parameter JSDoc documentation",
      "1.2.5": "Fixed defensive property access to handle empty objects and null values",
      "1.2.6": "Removed default content data - component only renders explicitly provided data",
      "1.2.7": "Fixed missing popover dependency for shadcn CLI installation",
      "1.2.8": "Extracted country data to separate countries.ts file",
      "1.2.9": "Show demo data when rendered without props"
    }
  },
  "changelog": {
    "1.0.0": "Initial release with name, phone, email, message and file attachment fields",
    "1.1.0": "Made phone, email, and message fields optional with defaults",
    "1.2.0": "Added initialValues prop to pre-fill form fields",
    "1.2.1": "Added aria-label to file removal button for screen reader accessibility",
    "1.2.3": "Added comprehensive JSDoc documentation",
    "1.2.4": "Updated Props interface with decorative header and sub-parameter JSDoc documentation",
    "1.2.5": "Fixed defensive property access to handle empty objects and null values",
    "1.2.6": "Removed default content data - component only renders explicitly provided data",
    "1.2.7": "Fixed missing popover dependency for shadcn CLI installation",
    "1.2.8": "Extracted country data to separate countries.ts file",
    "1.2.9": "Show demo data when rendered without props"
  },
  "title": "Contact Form",
  "author": "MNFST, Inc",
  "description": "A complete contact form with name fields, phone with country selector, email, message textarea, and file attachment.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "input",
    "label",
    "popover"
  ],
  "files": [
    {
      "path": "registry/form/contact-form.tsx",
      "content": "'use client';\n\nimport { Button } from '@/components/ui/button';\nimport { Input } from '@/components/ui/input';\nimport { Label } from '@/components/ui/label';\nimport { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';\nimport { cn } from '@/lib/utils';\nimport { ChevronDown, Paperclip, Search, Send, X } from 'lucide-react';\nimport { useEffect, useRef, useState } from 'react';\nimport { countries } from './countries';\nimport { demoContactFormData } from './demo/form';\n\n/**\n * Data structure representing the contact form submission.\n * @interface ContactFormData\n * @property {string} firstName - The user's first name (required)\n * @property {string} lastName - The user's last name (required)\n * @property {string} [countryId] - The selected country identifier (e.g., 'us', 'fr')\n * @property {string} [countryCode] - The phone country code (e.g., '+1', '+33')\n * @property {string} [phoneNumber] - The user's phone number without country code\n * @property {string} [email] - The user's email address\n * @property {string} [message] - The message or project description\n * @property {File | null} [attachment] - An optional file attachment\n */\nexport interface ContactFormData {\n  firstName?: string;\n  lastName?: string;\n  countryId?: string;\n  countryCode?: string;\n  phoneNumber?: string;\n  email?: string;\n  message?: string;\n  attachment?: File | null;\n}\n\n/**\n * ═══════════════════════════════════════════════════════════════════════════\n * ContactFormProps\n * ═══════════════════════════════════════════════════════════════════════════\n *\n * Props for the ContactForm component with name fields, phone number with\n * country selector, email input, message textarea, and file attachment support.\n */\nexport interface ContactFormProps {\n  data?: {\n    /** The form title displayed at the top. */\n    title?: string;\n    /** Descriptive text below the title. */\n    subtitle?: string;\n    /** Custom label for the submit button. */\n    submitLabel?: string;\n    /** Pre-filled form values. */\n    initialValues?: Partial<ContactFormData>;\n  };\n  actions?: {\n    /** Called when the form is submitted with form data. */\n    onSubmit?: (data: ContactFormData) => void;\n  };\n  appearance?: {\n    /**\n     * Whether to display the title section.\n     * @default true\n     */\n    showTitle?: boolean;\n  };\n  control?: {\n    /**\n     * Shows loading state on submit button.\n     * @default false\n     */\n    isLoading?: boolean;\n  };\n}\n\n\n/**\n * A complete contact form component with name fields, phone number with country selector,\n * email input, message textarea, and file attachment support.\n *\n * Features:\n * - First and last name fields\n * - Phone number with searchable country code dropdown\n * - Email input with validation\n * - Message textarea for project descriptions\n * - File attachment with preview and removal\n * - Loading state support\n * - Customizable title and submit button text\n *\n * @component\n * @example\n * ```tsx\n * <ContactForm\n *   data={{\n *     title: \"Get in Touch\",\n *     subtitle: \"We'd love to hear from you\",\n *     submitLabel: \"Send\"\n *   }}\n *   actions={{\n *     onSubmit: (data) => console.log(\"Form submitted:\", data)\n *   }}\n *   appearance={{ showTitle: true }}\n *   control={{ isLoading: false }}\n * />\n * ```\n */\nexport function ContactForm({ data, actions, appearance, control }: ContactFormProps) {\n  const resolved: NonNullable<ContactFormProps['data']> = data ?? demoContactFormData\n  const title = resolved.title\n  const subtitle = resolved.subtitle\n  const submitLabel = resolved.submitLabel ?? 'Submit'\n  const initialValues = resolved.initialValues\n  const { onSubmit } = actions ?? {};\n  const { showTitle = true } = appearance ?? {};\n  const { isLoading = false } = control ?? {};\n\n  const fileInputRef = useRef<HTMLInputElement>(null);\n  const searchInputRef = useRef<HTMLInputElement>(null);\n  const [formData, setFormData] = useState<ContactFormData>({\n    firstName: initialValues?.firstName ?? '',\n    lastName: initialValues?.lastName ?? '',\n    countryId: initialValues?.countryId ?? 'us',\n    countryCode: initialValues?.countryCode ?? '+1',\n    phoneNumber: initialValues?.phoneNumber ?? '',\n    email: initialValues?.email ?? '',\n    message: initialValues?.message ?? '',\n    attachment: initialValues?.attachment ?? null,\n  });\n  const [countrySearch, setCountrySearch] = useState('');\n  const [countryDropdownOpen, setCountryDropdownOpen] = useState(false);\n\n  const selectedCountry = countries.find((c) => c.id === formData.countryId);\n\n  const filteredCountries = countries.filter(\n    (country) =>\n      country.name.toLowerCase().includes(countrySearch.toLowerCase()) ||\n      country.code.includes(countrySearch)\n  );\n\n  useEffect(() => {\n    if (countryDropdownOpen && searchInputRef.current) {\n      searchInputRef.current.focus();\n    }\n  }, [countryDropdownOpen]);\n\n  const handleCountrySelect = (country: (typeof countries)[0]) => {\n    setFormData((prev) => ({\n      ...prev,\n      countryId: country.id,\n      countryCode: country.code,\n    }));\n    setCountryDropdownOpen(false);\n    setCountrySearch('');\n  };\n\n  const handleChange = (field: keyof ContactFormData, value: string | File | null) => {\n    setFormData((prev) => ({ ...prev, [field]: value }));\n  };\n\n  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const file = e.target.files?.[0] || null;\n    handleChange('attachment', file);\n  };\n\n  const handleRemoveFile = () => {\n    handleChange('attachment', null);\n    if (fileInputRef.current) {\n      fileInputRef.current.value = '';\n    }\n  };\n\n  const handleSubmit = (e: React.FormEvent) => {\n    e.preventDefault();\n    onSubmit?.(formData);\n  };\n\n  return (\n    <div className=\"w-full bg-card rounded-xl p-6\">\n      {showTitle && (title || subtitle) && (\n        <div className=\"mb-6\">\n          {title && <h2 className=\"text-xl font-semibold text-foreground\">{title}</h2>}\n          {subtitle && <p className=\"text-sm text-muted-foreground mt-1\">{subtitle}</p>}\n        </div>\n      )}\n\n      <form onSubmit={handleSubmit} className=\"space-y-4\">\n        {/* First Name & Last Name */}\n        <div className=\"grid grid-cols-2 gap-4\">\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"firstName\">First Name</Label>\n            <Input\n              id=\"firstName\"\n              placeholder=\"John\"\n              value={formData.firstName}\n              onChange={(e) => handleChange('firstName', e.target.value)}\n              required\n            />\n          </div>\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"lastName\">Last Name</Label>\n            <Input\n              id=\"lastName\"\n              placeholder=\"Doe\"\n              value={formData.lastName}\n              onChange={(e) => handleChange('lastName', e.target.value)}\n              required\n            />\n          </div>\n        </div>\n\n        {/* Phone Number & Email */}\n        <div className=\"grid grid-cols-1 md:grid-cols-2 gap-4\">\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"phone\">Phone Number</Label>\n            <div className=\"flex gap-2\">\n              <Popover open={countryDropdownOpen} onOpenChange={setCountryDropdownOpen}>\n                <PopoverTrigger asChild>\n                  <button\n                    type=\"button\"\n                    className={cn(\n                      'flex items-center gap-1.5 h-9 px-3 rounded-lg border border-input bg-transparent text-sm transition-colors',\n                      'hover:bg-muted focus-visible:border-foreground focus-visible:outline-none'\n                    )}\n                  >\n                    {selectedCountry && (\n                      <>\n                        <span>{selectedCountry.flag}</span>\n                        <span>{selectedCountry.code}</span>\n                      </>\n                    )}\n                    <ChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n                  </button>\n                </PopoverTrigger>\n                <PopoverContent className=\"w-[280px] p-0\" align=\"start\">\n                  <div className=\"p-2 border-b border-border\">\n                    <div className=\"relative\">\n                      <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground\" />\n                      <input\n                        ref={searchInputRef}\n                        type=\"text\"\n                        placeholder=\"Search country...\"\n                        value={countrySearch}\n                        onChange={(e) => setCountrySearch(e.target.value)}\n                        className=\"w-full h-9 pl-9 pr-3 rounded-md border border-input bg-transparent text-sm placeholder:text-muted-foreground focus-visible:border-foreground focus-visible:outline-none\"\n                      />\n                    </div>\n                  </div>\n                  <div className=\"max-h-[240px] overflow-y-auto p-1\">\n                    {filteredCountries.length === 0 ? (\n                      <p className=\"text-sm text-muted-foreground text-center py-4\">\n                        No country found\n                      </p>\n                    ) : (\n                      filteredCountries.map((country) => (\n                        <button\n                          key={country.id}\n                          type=\"button\"\n                          onClick={() => handleCountrySelect(country)}\n                          className={cn(\n                            'w-full flex items-center gap-2 px-2 py-1.5 rounded-md text-sm transition-colors text-left',\n                            'hover:bg-muted',\n                            formData.countryId === country.id && 'bg-muted'\n                          )}\n                        >\n                          <span>{country.flag}</span>\n                          <span className=\"flex-1\">{country.name}</span>\n                          <span className=\"text-muted-foreground\">{country.code}</span>\n                        </button>\n                      ))\n                    )}\n                  </div>\n                </PopoverContent>\n              </Popover>\n              <Input\n                id=\"phone\"\n                type=\"tel\"\n                placeholder=\"(555) 123-4567\"\n                value={formData.phoneNumber}\n                onChange={(e) => handleChange('phoneNumber', e.target.value)}\n                className=\"flex-1\"\n              />\n            </div>\n          </div>\n\n          <div className=\"space-y-2\">\n            <Label htmlFor=\"email\">Email</Label>\n            <Input\n              id=\"email\"\n              type=\"email\"\n              placeholder=\"john@example.com\"\n              value={formData.email}\n              onChange={(e) => handleChange('email', e.target.value)}\n              required\n            />\n          </div>\n        </div>\n\n        {/* Message */}\n        <div className=\"space-y-2\">\n          <Label htmlFor=\"message\">Tell us about your project</Label>\n          <textarea\n            id=\"message\"\n            placeholder=\"Describe your project, goals, and timeline...\"\n            value={formData.message}\n            onChange={(e) => handleChange('message', e.target.value)}\n            rows={4}\n            required\n            className={cn(\n              'border-input placeholder:text-muted-foreground flex w-full rounded-lg border bg-transparent px-3 py-2 text-base transition-colors outline-none md:text-sm resize-none',\n              'focus-visible:border-foreground'\n            )}\n          />\n        </div>\n\n        {/* Actions */}\n        <div className=\"flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2\">\n          <input\n            ref={fileInputRef}\n            type=\"file\"\n            onChange={handleFileChange}\n            className=\"hidden\"\n            accept=\".pdf,.doc,.docx,.txt,.png,.jpg,.jpeg\"\n          />\n\n          {formData.attachment ? (\n            <div className=\"flex items-center justify-center gap-2 px-3 py-2 bg-muted rounded-lg w-full sm:w-auto\">\n              <Paperclip className=\"h-4 w-4 text-muted-foreground flex-shrink-0\" />\n              <span className=\"text-sm text-foreground truncate max-w-[150px]\">\n                {formData.attachment.name}\n              </span>\n              <button\n                type=\"button\"\n                onClick={handleRemoveFile}\n                aria-label=\"Remove attachment\"\n                className=\"p-1 hover:bg-background rounded transition-colors\"\n              >\n                <X className=\"h-4 w-4 text-muted-foreground\" />\n              </button>\n            </div>\n          ) : (\n            <Button\n              type=\"button\"\n              variant=\"outline\"\n              size=\"sm\"\n              onClick={() => fileInputRef.current?.click()}\n              className=\"w-full sm:w-auto\"\n            >\n              <Paperclip className=\"h-4 w-4 mr-2\" />\n              Attach a file\n            </Button>\n          )}\n\n          <Button type=\"submit\" size=\"sm\" disabled={isLoading} className=\"w-full sm:w-auto\">\n            {isLoading ? (\n              'Sending...'\n            ) : (\n              <>\n                <Send className=\"h-4 w-4 mr-2\" />\n                {submitLabel}\n              </>\n            )}\n          </Button>\n        </div>\n      </form>\n    </div>\n  );\n}\n",
      "type": "registry:block",
      "target": "components/ui/contact-form.tsx"
    },
    {
      "path": "registry/form/countries.ts",
      "content": "export interface Country {\n  id: string\n  code: string\n  name: string\n  flag: string\n}\n\nexport const countries: Country[] = [\n  { id: 'af', code: '+93', name: 'Afghanistan', flag: '\\u{1F1E6}\\u{1F1EB}' },\n  { id: 'al', code: '+355', name: 'Albania', flag: '\\u{1F1E6}\\u{1F1F1}' },\n  { id: 'dz', code: '+213', name: 'Algeria', flag: '\\u{1F1E9}\\u{1F1FF}' },\n  { id: 'ar', code: '+54', name: 'Argentina', flag: '\\u{1F1E6}\\u{1F1F7}' },\n  { id: 'am', code: '+374', name: 'Armenia', flag: '\\u{1F1E6}\\u{1F1F2}' },\n  { id: 'au', code: '+61', name: 'Australia', flag: '\\u{1F1E6}\\u{1F1FA}' },\n  { id: 'at', code: '+43', name: 'Austria', flag: '\\u{1F1E6}\\u{1F1F9}' },\n  { id: 'az', code: '+994', name: 'Azerbaijan', flag: '\\u{1F1E6}\\u{1F1FF}' },\n  { id: 'bh', code: '+973', name: 'Bahrain', flag: '\\u{1F1E7}\\u{1F1ED}' },\n  { id: 'bd', code: '+880', name: 'Bangladesh', flag: '\\u{1F1E7}\\u{1F1E9}' },\n  { id: 'by', code: '+375', name: 'Belarus', flag: '\\u{1F1E7}\\u{1F1FE}' },\n  { id: 'be', code: '+32', name: 'Belgium', flag: '\\u{1F1E7}\\u{1F1EA}' },\n  { id: 'bo', code: '+591', name: 'Bolivia', flag: '\\u{1F1E7}\\u{1F1F4}' },\n  { id: 'ba', code: '+387', name: 'Bosnia', flag: '\\u{1F1E7}\\u{1F1E6}' },\n  { id: 'br', code: '+55', name: 'Brazil', flag: '\\u{1F1E7}\\u{1F1F7}' },\n  { id: 'bg', code: '+359', name: 'Bulgaria', flag: '\\u{1F1E7}\\u{1F1EC}' },\n  { id: 'kh', code: '+855', name: 'Cambodia', flag: '\\u{1F1F0}\\u{1F1ED}' },\n  { id: 'cm', code: '+237', name: 'Cameroon', flag: '\\u{1F1E8}\\u{1F1F2}' },\n  { id: 'ca', code: '+1', name: 'Canada', flag: '\\u{1F1E8}\\u{1F1E6}' },\n  { id: 'cl', code: '+56', name: 'Chile', flag: '\\u{1F1E8}\\u{1F1F1}' },\n  { id: 'cn', code: '+86', name: 'China', flag: '\\u{1F1E8}\\u{1F1F3}' },\n  { id: 'co', code: '+57', name: 'Colombia', flag: '\\u{1F1E8}\\u{1F1F4}' },\n  { id: 'cr', code: '+506', name: 'Costa Rica', flag: '\\u{1F1E8}\\u{1F1F7}' },\n  { id: 'hr', code: '+385', name: 'Croatia', flag: '\\u{1F1ED}\\u{1F1F7}' },\n  { id: 'cu', code: '+53', name: 'Cuba', flag: '\\u{1F1E8}\\u{1F1FA}' },\n  { id: 'cy', code: '+357', name: 'Cyprus', flag: '\\u{1F1E8}\\u{1F1FE}' },\n  { id: 'cz', code: '+420', name: 'Czech Republic', flag: '\\u{1F1E8}\\u{1F1FF}' },\n  { id: 'dk', code: '+45', name: 'Denmark', flag: '\\u{1F1E9}\\u{1F1F0}' },\n  { id: 'do', code: '+1', name: 'Dominican Republic', flag: '\\u{1F1E9}\\u{1F1F4}' },\n  { id: 'ec', code: '+593', name: 'Ecuador', flag: '\\u{1F1EA}\\u{1F1E8}' },\n  { id: 'eg', code: '+20', name: 'Egypt', flag: '\\u{1F1EA}\\u{1F1EC}' },\n  { id: 'sv', code: '+503', name: 'El Salvador', flag: '\\u{1F1F8}\\u{1F1FB}' },\n  { id: 'ee', code: '+372', name: 'Estonia', flag: '\\u{1F1EA}\\u{1F1EA}' },\n  { id: 'et', code: '+251', name: 'Ethiopia', flag: '\\u{1F1EA}\\u{1F1F9}' },\n  { id: 'fi', code: '+358', name: 'Finland', flag: '\\u{1F1EB}\\u{1F1EE}' },\n  { id: 'fr', code: '+33', name: 'France', flag: '\\u{1F1EB}\\u{1F1F7}' },\n  { id: 'ge', code: '+995', name: 'Georgia', flag: '\\u{1F1EC}\\u{1F1EA}' },\n  { id: 'de', code: '+49', name: 'Germany', flag: '\\u{1F1E9}\\u{1F1EA}' },\n  { id: 'gh', code: '+233', name: 'Ghana', flag: '\\u{1F1EC}\\u{1F1ED}' },\n  { id: 'gr', code: '+30', name: 'Greece', flag: '\\u{1F1EC}\\u{1F1F7}' },\n  { id: 'gt', code: '+502', name: 'Guatemala', flag: '\\u{1F1EC}\\u{1F1F9}' },\n  { id: 'hn', code: '+504', name: 'Honduras', flag: '\\u{1F1ED}\\u{1F1F3}' },\n  { id: 'hk', code: '+852', name: 'Hong Kong', flag: '\\u{1F1ED}\\u{1F1F0}' },\n  { id: 'hu', code: '+36', name: 'Hungary', flag: '\\u{1F1ED}\\u{1F1FA}' },\n  { id: 'is', code: '+354', name: 'Iceland', flag: '\\u{1F1EE}\\u{1F1F8}' },\n  { id: 'in', code: '+91', name: 'India', flag: '\\u{1F1EE}\\u{1F1F3}' },\n  { id: 'id', code: '+62', name: 'Indonesia', flag: '\\u{1F1EE}\\u{1F1E9}' },\n  { id: 'ir', code: '+98', name: 'Iran', flag: '\\u{1F1EE}\\u{1F1F7}' },\n  { id: 'iq', code: '+964', name: 'Iraq', flag: '\\u{1F1EE}\\u{1F1F6}' },\n  { id: 'ie', code: '+353', name: 'Ireland', flag: '\\u{1F1EE}\\u{1F1EA}' },\n  { id: 'il', code: '+972', name: 'Israel', flag: '\\u{1F1EE}\\u{1F1F1}' },\n  { id: 'it', code: '+39', name: 'Italy', flag: '\\u{1F1EE}\\u{1F1F9}' },\n  { id: 'jm', code: '+1', name: 'Jamaica', flag: '\\u{1F1EF}\\u{1F1F2}' },\n  { id: 'jp', code: '+81', name: 'Japan', flag: '\\u{1F1EF}\\u{1F1F5}' },\n  { id: 'jo', code: '+962', name: 'Jordan', flag: '\\u{1F1EF}\\u{1F1F4}' },\n  { id: 'kz', code: '+7', name: 'Kazakhstan', flag: '\\u{1F1F0}\\u{1F1FF}' },\n  { id: 'ke', code: '+254', name: 'Kenya', flag: '\\u{1F1F0}\\u{1F1EA}' },\n  { id: 'kw', code: '+965', name: 'Kuwait', flag: '\\u{1F1F0}\\u{1F1FC}' },\n  { id: 'lv', code: '+371', name: 'Latvia', flag: '\\u{1F1F1}\\u{1F1FB}' },\n  { id: 'lb', code: '+961', name: 'Lebanon', flag: '\\u{1F1F1}\\u{1F1E7}' },\n  { id: 'lt', code: '+370', name: 'Lithuania', flag: '\\u{1F1F1}\\u{1F1F9}' },\n  { id: 'lu', code: '+352', name: 'Luxembourg', flag: '\\u{1F1F1}\\u{1F1FA}' },\n  { id: 'my', code: '+60', name: 'Malaysia', flag: '\\u{1F1F2}\\u{1F1FE}' },\n  { id: 'mx', code: '+52', name: 'Mexico', flag: '\\u{1F1F2}\\u{1F1FD}' },\n  { id: 'ma', code: '+212', name: 'Morocco', flag: '\\u{1F1F2}\\u{1F1E6}' },\n  { id: 'mm', code: '+95', name: 'Myanmar', flag: '\\u{1F1F2}\\u{1F1F2}' },\n  { id: 'np', code: '+977', name: 'Nepal', flag: '\\u{1F1F3}\\u{1F1F5}' },\n  { id: 'nl', code: '+31', name: 'Netherlands', flag: '\\u{1F1F3}\\u{1F1F1}' },\n  { id: 'nz', code: '+64', name: 'New Zealand', flag: '\\u{1F1F3}\\u{1F1FF}' },\n  { id: 'ng', code: '+234', name: 'Nigeria', flag: '\\u{1F1F3}\\u{1F1EC}' },\n  { id: 'no', code: '+47', name: 'Norway', flag: '\\u{1F1F3}\\u{1F1F4}' },\n  { id: 'om', code: '+968', name: 'Oman', flag: '\\u{1F1F4}\\u{1F1F2}' },\n  { id: 'pk', code: '+92', name: 'Pakistan', flag: '\\u{1F1F5}\\u{1F1F0}' },\n  { id: 'pa', code: '+507', name: 'Panama', flag: '\\u{1F1F5}\\u{1F1E6}' },\n  { id: 'py', code: '+595', name: 'Paraguay', flag: '\\u{1F1F5}\\u{1F1FE}' },\n  { id: 'pe', code: '+51', name: 'Peru', flag: '\\u{1F1F5}\\u{1F1EA}' },\n  { id: 'ph', code: '+63', name: 'Philippines', flag: '\\u{1F1F5}\\u{1F1ED}' },\n  { id: 'pl', code: '+48', name: 'Poland', flag: '\\u{1F1F5}\\u{1F1F1}' },\n  { id: 'pt', code: '+351', name: 'Portugal', flag: '\\u{1F1F5}\\u{1F1F9}' },\n  { id: 'pr', code: '+1', name: 'Puerto Rico', flag: '\\u{1F1F5}\\u{1F1F7}' },\n  { id: 'qa', code: '+974', name: 'Qatar', flag: '\\u{1F1F6}\\u{1F1E6}' },\n  { id: 'ro', code: '+40', name: 'Romania', flag: '\\u{1F1F7}\\u{1F1F4}' },\n  { id: 'ru', code: '+7', name: 'Russia', flag: '\\u{1F1F7}\\u{1F1FA}' },\n  { id: 'sa', code: '+966', name: 'Saudi Arabia', flag: '\\u{1F1F8}\\u{1F1E6}' },\n  { id: 'sn', code: '+221', name: 'Senegal', flag: '\\u{1F1F8}\\u{1F1F3}' },\n  { id: 'rs', code: '+381', name: 'Serbia', flag: '\\u{1F1F7}\\u{1F1F8}' },\n  { id: 'sg', code: '+65', name: 'Singapore', flag: '\\u{1F1F8}\\u{1F1EC}' },\n  { id: 'sk', code: '+421', name: 'Slovakia', flag: '\\u{1F1F8}\\u{1F1F0}' },\n  { id: 'si', code: '+386', name: 'Slovenia', flag: '\\u{1F1F8}\\u{1F1EE}' },\n  { id: 'za', code: '+27', name: 'South Africa', flag: '\\u{1F1FF}\\u{1F1E6}' },\n  { id: 'kr', code: '+82', name: 'South Korea', flag: '\\u{1F1F0}\\u{1F1F7}' },\n  { id: 'es', code: '+34', name: 'Spain', flag: '\\u{1F1EA}\\u{1F1F8}' },\n  { id: 'lk', code: '+94', name: 'Sri Lanka', flag: '\\u{1F1F1}\\u{1F1F0}' },\n  { id: 'se', code: '+46', name: 'Sweden', flag: '\\u{1F1F8}\\u{1F1EA}' },\n  { id: 'ch', code: '+41', name: 'Switzerland', flag: '\\u{1F1E8}\\u{1F1ED}' },\n  { id: 'tw', code: '+886', name: 'Taiwan', flag: '\\u{1F1F9}\\u{1F1FC}' },\n  { id: 'th', code: '+66', name: 'Thailand', flag: '\\u{1F1F9}\\u{1F1ED}' },\n  { id: 'tn', code: '+216', name: 'Tunisia', flag: '\\u{1F1F9}\\u{1F1F3}' },\n  { id: 'tr', code: '+90', name: 'Turkey', flag: '\\u{1F1F9}\\u{1F1F7}' },\n  { id: 'ua', code: '+380', name: 'Ukraine', flag: '\\u{1F1FA}\\u{1F1E6}' },\n  { id: 'ae', code: '+971', name: 'United Arab Emirates', flag: '\\u{1F1E6}\\u{1F1EA}' },\n  { id: 'gb', code: '+44', name: 'United Kingdom', flag: '\\u{1F1EC}\\u{1F1E7}' },\n  { id: 'us', code: '+1', name: 'United States', flag: '\\u{1F1FA}\\u{1F1F8}' },\n  { id: 'uy', code: '+598', name: 'Uruguay', flag: '\\u{1F1FA}\\u{1F1FE}' },\n  { id: 'uz', code: '+998', name: 'Uzbekistan', flag: '\\u{1F1FA}\\u{1F1FF}' },\n  { id: 've', code: '+58', name: 'Venezuela', flag: '\\u{1F1FB}\\u{1F1EA}' },\n  { id: 'vn', code: '+84', name: 'Vietnam', flag: '\\u{1F1FB}\\u{1F1F3}' },\n  { id: 'ye', code: '+967', name: 'Yemen', flag: '\\u{1F1FE}\\u{1F1EA}' },\n  { id: 'zm', code: '+260', name: 'Zambia', flag: '\\u{1F1FF}\\u{1F1F2}' },\n  { id: 'zw', code: '+263', name: 'Zimbabwe', flag: '\\u{1F1FF}\\u{1F1FC}' },\n]\n",
      "type": "registry:lib",
      "target": "components/ui/countries.ts"
    },
    {
      "path": "registry/form/demo/form.ts",
      "content": "// Demo data for Form category components\n// This file contains sample data used for component previews and documentation\n\n/**\n * Generate available dates dynamically so the DateTimePicker preview\n * always has clickable dates regardless of when it is viewed.\n */\nfunction generateAvailableDates(): Date[] {\n  const dates: Date[] = [];\n  const now = new Date();\n  // Walk through current and next month, only keeping weekdays (Mon-Fri)\n  for (let m = 0; m <= 1; m++) {\n    for (let d = 1; d <= 28; d += 2) {\n      const date = new Date(now.getFullYear(), now.getMonth() + m, d);\n      const day = date.getDay();\n      if (day !== 0 && day !== 6) {\n        dates.push(date);\n      }\n    }\n  }\n  return dates;\n}\n\nexport const demoContactFormData = {\n  title: 'Get in Touch',\n  subtitle: \"We'd love to hear from you. Fill out the form below.\",\n  submitLabel: 'Send Message',\n}\n\nexport const demoIssueReportFormData = {\n  title: 'Report an Issue',\n  teams: ['Engineering', 'Product', 'Design', 'Marketing', 'Operations'],\n  locations: ['New York - HQ', 'San Francisco', 'London', 'Remote'],\n  categories: {\n    Software: ['Business App', 'Email', 'VPN', 'Browser', 'OS'],\n    Hardware: ['Computer', 'Monitor', 'Keyboard', 'Mouse', 'Printer'],\n    Network: ['Wi-Fi', 'Ethernet', 'VPN Access'],\n    Access: ['Account', 'Permissions', 'Password Reset'],\n  } as Record<string, string[]>,\n  impacts: [\n    { value: 'critical', label: 'Critical - Work stopped' },\n    { value: 'high', label: 'High - Major feature broken' },\n    { value: 'medium', label: 'Medium - Workaround available' },\n    { value: 'low', label: 'Low - Minor inconvenience' },\n  ],\n  urgencies: [\n    { value: 'immediate', label: 'Immediate' },\n    { value: 'today', label: 'Today' },\n    { value: 'this-week', label: 'This week' },\n    { value: 'no-rush', label: 'No rush' },\n  ],\n  frequencies: [\n    { value: 'constant', label: 'Constant' },\n    { value: 'frequent', label: 'Frequent' },\n    { value: 'occasional', label: 'Occasional' },\n    { value: 'once', label: 'Happened once' },\n  ],\n  attemptedActions: [\n    'Restarted the application',\n    'Cleared browser cache',\n    'Restarted computer',\n    'Checked internet connection',\n    'Contacted a colleague',\n  ],\n}\n\nexport const demoDateTimePickerData = {\n  title: 'Select a Date & Time',\n  availableDates: generateAvailableDates(),\n  availableTimeSlots: [\n    '9:00am',\n    '10:00am',\n    '11:30am',\n    '1:00pm',\n    '2:30pm',\n    '4:00pm',\n  ],\n  timezone: 'Eastern Time - US & Canada',\n};\n",
      "type": "registry:lib",
      "target": "components/ui/demo/form.ts"
    }
  ],
  "categories": [
    "form"
  ],
  "type": "registry:block"
}