{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "form-layouts",
  "title": "Form Layouts",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/form-layouts/FormLayouts.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport { Globe, Link2, Lock } from 'lucide-vue-next'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Label } from '@/components/ui/label'\nimport { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'\nimport { SectionCard } from '@/components/ui/section-card'\nimport { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'\nimport { Switch } from '@/components/ui/switch'\nimport { Textarea } from '@/components/ui/textarea'\n\nconst props = withDefaults(\n  defineProps<{\n    class?: HTMLAttributes['class']\n  }>(),\n  {},\n)\n\nconst DESCRIPTION_LIMIT = 280\n\nconst name = ref('')\nconst description = ref('')\nconst visibility = ref('internal')\nconst startDate = ref('')\nconst budget = ref('')\nconst access = ref<'link' | 'restricted'>('link')\nconst notifications = ref(true)\nconst comments = ref(true)\nconst submitted = ref(false)\n\nconst slug = computed(() => {\n  const cleaned = name.value\n    .trim()\n    .toLowerCase()\n    .replace(/[^a-z0-9]+/g, '-')\n    .replace(/^-+|-+$/g, '')\n  return cleaned || 'your-project'\n})\n\nconst showNameError = computed(() => submitted.value && name.value.trim() === '')\n\nfunction handleSubmit() {\n  submitted.value = true\n  if (name.value.trim() === '') return\n}\n</script>\n\n<template>\n  <div data-slot=\"form-layouts\" :class=\"['max-w-2xl', props.class]\">\n    <form class=\"space-y-6\" novalidate @submit.prevent=\"handleSubmit\">\n      <SectionCard title=\"Project details\" description=\"Name your project and describe what it covers.\">\n        <div class=\"space-y-4\">\n          <div class=\"space-y-2\">\n            <Label for=\"fl-name\">Name</Label>\n            <Input\n              id=\"fl-name\"\n              v-model=\"name\"\n              placeholder=\"Q3 launch site\"\n              autocomplete=\"off\"\n              :aria-invalid=\"showNameError || undefined\"\n            />\n            <p v-if=\"showNameError\" role=\"alert\" class=\"text-destructive text-xs\">Project name is required.</p>\n          </div>\n          <div class=\"border-border bg-muted/40 flex items-center gap-2 rounded-md border px-3 py-2\">\n            <Globe class=\"text-muted-foreground size-4 shrink-0\" aria-hidden=\"true\" />\n            <p class=\"min-w-0 truncate text-xs\">\n              <span class=\"text-muted-foreground\">acme.uipkge.app/</span>\n              <span class=\"text-foreground font-medium\">{{ slug }}</span>\n            </p>\n          </div>\n          <div class=\"space-y-2\">\n            <Label for=\"fl-description\">Description</Label>\n            <Textarea id=\"fl-description\" v-model=\"description\" :rows=\"3\" placeholder=\"What is this project about?\" />\n            <p\n              class=\"text-right text-xs\"\n              :class=\"description.length > DESCRIPTION_LIMIT ? 'text-destructive' : 'text-muted-foreground'\"\n            >\n              {{ description.length }}/{{ DESCRIPTION_LIMIT }}\n            </p>\n          </div>\n        </div>\n      </SectionCard>\n\n      <SectionCard title=\"Configuration\" description=\"Visibility, schedule and budget for the project.\">\n        <div class=\"grid gap-4 sm:grid-cols-3\">\n          <div class=\"space-y-2\">\n            <Label for=\"fl-visibility\">Visibility</Label>\n            <Select v-model=\"visibility\">\n              <SelectTrigger id=\"fl-visibility\" class=\"w-full\">\n                <SelectValue />\n              </SelectTrigger>\n              <SelectContent>\n                <SelectItem value=\"public\">Public</SelectItem>\n                <SelectItem value=\"internal\">Internal</SelectItem>\n                <SelectItem value=\"private\">Private</SelectItem>\n              </SelectContent>\n            </Select>\n          </div>\n          <div class=\"space-y-2\">\n            <Label for=\"fl-start-date\">Start date</Label>\n            <Input id=\"fl-start-date\" v-model=\"startDate\" type=\"date\" />\n          </div>\n          <div class=\"space-y-2\">\n            <Label for=\"fl-budget\">Budget</Label>\n            <Input id=\"fl-budget\" v-model=\"budget\" type=\"number\" :min=\"0\" :step=\"500\" class=\"text-left\" />\n          </div>\n        </div>\n      </SectionCard>\n\n      <SectionCard title=\"Access\" description=\"Decide who can open the project and what they can do.\">\n        <div class=\"space-y-5\">\n          <RadioGroup v-model=\"access\" class=\"gap-3\">\n            <div\n              class=\"hover:bg-accent/50 has-data-[state=checked]:border-primary flex items-start gap-3 rounded-lg border p-3 transition-colors\"\n            >\n              <RadioGroupItem id=\"fl-access-link\" value=\"link\" class=\"mt-0.5\" />\n              <label for=\"fl-access-link\" class=\"cursor-pointer select-none\">\n                <span class=\"flex items-center gap-1.5 text-sm font-medium\">\n                  <Link2 class=\"size-4\" aria-hidden=\"true\" />\n                  Anyone with the link\n                </span>\n                <span class=\"text-muted-foreground mt-0.5 block text-xs\"> Guests can view without signing in. </span>\n              </label>\n            </div>\n            <div\n              class=\"hover:bg-accent/50 has-data-[state=checked]:border-primary flex items-start gap-3 rounded-lg border p-3 transition-colors\"\n            >\n              <RadioGroupItem id=\"fl-access-restricted\" value=\"restricted\" class=\"mt-0.5\" />\n              <label for=\"fl-access-restricted\" class=\"cursor-pointer select-none\">\n                <span class=\"flex items-center gap-1.5 text-sm font-medium\">\n                  <Lock class=\"size-4\" aria-hidden=\"true\" />\n                  Restricted\n                </span>\n                <span class=\"text-muted-foreground mt-0.5 block text-xs\">\n                  Only invited members can open the project.\n                </span>\n              </label>\n            </div>\n          </RadioGroup>\n\n          <div class=\"divide-y rounded-lg border\">\n            <div class=\"flex items-center justify-between gap-4 p-4\">\n              <div class=\"min-w-0\">\n                <p class=\"text-sm font-medium\">Notifications</p>\n                <p class=\"text-muted-foreground mt-0.5 text-xs\">Email the team on status changes and mentions.</p>\n              </div>\n              <Switch v-model=\"notifications\" aria-label=\"Toggle notifications\" />\n            </div>\n            <div class=\"flex items-center justify-between gap-4 p-4\">\n              <div class=\"min-w-0\">\n                <p class=\"text-sm font-medium\">Comments</p>\n                <p class=\"text-muted-foreground mt-0.5 text-xs\">Let viewers comment on tasks and updates.</p>\n              </div>\n              <Switch v-model=\"comments\" aria-label=\"Toggle comments\" />\n            </div>\n          </div>\n        </div>\n      </SectionCard>\n\n      <div\n        class=\"bg-background/80 border-border sticky bottom-0 -mx-1 flex items-center justify-end gap-2 rounded-b-xl border-t px-1 py-4 backdrop-blur\"\n      >\n        <Button type=\"button\" variant=\"ghost\" size=\"sm\">Cancel</Button>\n        <Button type=\"submit\" size=\"sm\" :disabled=\"name.trim() === ''\">Create project</Button>\n      </div>\n    </form>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/FormLayouts.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/label.json",
    "https://uipkge.dev/r/vue/radio-group.json",
    "https://uipkge.dev/r/vue/section-card.json",
    "https://uipkge.dev/r/vue/select.json",
    "https://uipkge.dev/r/vue/switch.json",
    "https://uipkge.dev/r/vue/textarea.json"
  ],
  "description": "Structured create/edit entity form (\"New project\"): stacked SectionCards for project details (name with live slug preview, description with char counter), configuration (visibility Select, start date, budget), and access (link vs restricted RadioGroup, notification/comment Switch rows) with a sticky-feel footer bar. Create stays disabled until the name is filled; validation hints appear under empty required fields after the first submit attempt.",
  "categories": [
    "layout",
    "app",
    "forms"
  ]
}