{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "form-layouts",
  "title": "Form Layouts",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-angular/blocks/form-layouts/form-layouts.component.ts",
      "content": "// Structured create/edit entity form (\"New project\"): stacked SectionCards for project\n// details (name with live slug preview, description with char counter), configuration\n// (visibility Select, start date, budget), and access (link vs restricted RadioGroup,\n// notification/comment Switch rows) with a sticky-feel footer bar. Port of the React block 1:1.\nimport { ChangeDetectionStrategy, Component, Input, computed, signal } from '@angular/core'\nimport { Globe, Link2, Lock, LucideAngularModule } from 'lucide-angular'\nimport { cn } from '@/lib/utils'\nimport { UiButtonComponent } from '@/ui/button/button.component'\nimport { UiInputComponent } from '@/ui/input/input.component'\nimport { UiLabelComponent } from '@/ui/label/label.component'\nimport { UiRadioGroupComponent, UiRadioGroupItemComponent } from '@/ui/radio-group/radio-group.component'\nimport { UiSectionCardComponent } from '@/ui/section-card/section-card.component'\nimport {\n  UiSelectComponent,\n  UiSelectContentComponent,\n  UiSelectItemComponent,\n  UiSelectTriggerComponent,\n  UiSelectValueComponent,\n} from '@/ui/select/select.component'\nimport { UiSwitchComponent } from '@/ui/switch/switch.component'\nimport { UiTextareaComponent } from '@/ui/textarea/textarea.component'\n\nconst DESCRIPTION_LIMIT = 280\n\nexport type FormLayoutsAccess = 'link' | 'restricted'\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-form-layouts, [ui-form-layouts]',\n  standalone: true,\n  // React renders the root <div> itself: the host stays out of layout and `class` goes to the root.\n  host: { '[attr.class]': '\"contents\"' },\n  imports: [\n    LucideAngularModule,\n    UiButtonComponent,\n    UiInputComponent,\n    UiLabelComponent,\n    UiRadioGroupComponent,\n    UiRadioGroupItemComponent,\n    UiSectionCardComponent,\n    UiSelectComponent,\n    UiSelectContentComponent,\n    UiSelectItemComponent,\n    UiSelectTriggerComponent,\n    UiSelectValueComponent,\n    UiSwitchComponent,\n    UiTextareaComponent,\n  ],\n  template: `\n    <div data-slot=\"form-layouts\" [class]=\"rootClass\">\n      <form class=\"space-y-6\" novalidate (submit)=\"handleSubmit($event)\">\n        <div ui-section-card 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 ui-label for=\"fl-name\">Name</label>\n              <ui-input\n                id=\"fl-name\"\n                [value]=\"name()\"\n                (valueChange)=\"name.set($event)\"\n                placeholder=\"Q3 launch site\"\n                autoComplete=\"off\"\n                [aria-invalid]=\"showNameError() || undefined\"\n              />\n              @if (showNameError()) {\n                <p role=\"alert\" class=\"text-destructive text-xs\">Project name is required.</p>\n              }\n            </div>\n            <div class=\"border-border bg-muted/40 flex items-center gap-2 rounded-md border px-3 py-2\">\n              <lucide-icon [img]=\"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 ui-label for=\"fl-description\">Description</label>\n              <ui-textarea\n                id=\"fl-description\"\n                [value]=\"description()\"\n                (valueChange)=\"description.set($event)\"\n                [rows]=\"3\"\n                placeholder=\"What is this project about?\"\n              />\n              <p\n                class=\"text-right text-xs\"\n                [class]=\"description().length > limit ? 'text-destructive' : 'text-muted-foreground'\"\n              >\n                {{ description().length }}/{{ limit }}\n              </p>\n            </div>\n          </div>\n        </div>\n\n        <div ui-section-card 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 ui-label for=\"fl-visibility\">Visibility</label>\n              <ui-select [value]=\"visibility()\" (valueChange)=\"visibility.set($event)\">\n                <button ui-select-trigger id=\"fl-visibility\" class=\"w-full\">\n                  <ui-select-value />\n                </button>\n                <ui-select-content>\n                  <ui-select-item value=\"public\">Public</ui-select-item>\n                  <ui-select-item value=\"internal\">Internal</ui-select-item>\n                  <ui-select-item value=\"private\">Private</ui-select-item>\n                </ui-select-content>\n              </ui-select>\n            </div>\n            <div class=\"space-y-2\">\n              <label ui-label for=\"fl-start-date\">Start date</label>\n              <ui-input id=\"fl-start-date\" type=\"date\" [value]=\"startDate()\" (valueChange)=\"startDate.set($event)\" />\n            </div>\n            <div class=\"space-y-2\">\n              <label ui-label for=\"fl-budget\">Budget</label>\n              <ui-input\n                id=\"fl-budget\"\n                type=\"number\"\n                [min]=\"0\"\n                [step]=\"500\"\n                class=\"text-left\"\n                [value]=\"budget()\"\n                (valueChange)=\"budget.set($event)\"\n              />\n            </div>\n          </div>\n        </div>\n\n        <div ui-section-card title=\"Access\" description=\"Decide who can open the project and what they can do.\">\n          <div class=\"space-y-5\">\n            <ui-radio-group [value]=\"access()\" (valueChange)=\"setAccess($event)\" 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                <ui-radio-group-item 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                    <lucide-icon [img]=\"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                <ui-radio-group-item 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                    <lucide-icon [img]=\"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            </ui-radio-group>\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                <ui-switch\n                  [checked]=\"notifications()\"\n                  (checkedChange)=\"notifications.set($event)\"\n                  aria-label=\"Toggle notifications\"\n                />\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                <ui-switch [checked]=\"comments()\" (checkedChange)=\"comments.set($event)\" aria-label=\"Toggle comments\" />\n              </div>\n            </div>\n          </div>\n        </div>\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 ui-button type=\"button\" variant=\"ghost\" size=\"sm\">Cancel</button>\n          <button ui-button type=\"submit\" size=\"sm\" [disabled]=\"name().trim() === ''\">Create project</button>\n        </div>\n      </form>\n    </div>\n  `,\n})\nexport class UiFormLayoutsComponent {\n  protected readonly Globe = Globe\n  protected readonly Link2 = Link2\n  protected readonly Lock = Lock\n\n  protected readonly limit = DESCRIPTION_LIMIT\n\n  readonly name = signal('')\n  readonly description = signal('')\n  readonly visibility = signal('internal')\n  readonly startDate = signal('')\n  readonly budget = signal('')\n  readonly access = signal<FormLayoutsAccess>('link')\n  readonly notifications = signal(true)\n  readonly comments = signal(true)\n  readonly submitted = signal(false)\n\n  @Input('class') className?: string\n\n  readonly slug = computed(() => {\n    const cleaned = this.name()\n      .trim()\n      .toLowerCase()\n      .replace(/[^a-z0-9]+/g, '-')\n      .replace(/^-+|-+$/g, '')\n    return cleaned || 'your-project'\n  })\n\n  readonly showNameError = computed(() => this.submitted() && this.name().trim() === '')\n\n  get rootClass(): string {\n    return cn('max-w-2xl', this.className)\n  }\n\n  setAccess(value: string): void {\n    this.access.set(value as FormLayoutsAccess)\n  }\n\n  handleSubmit(event?: Event): void {\n    event?.preventDefault()\n    this.submitted.set(true)\n    if (this.name().trim() === '') return\n  }\n}\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/form-layouts/form-layouts.component.ts"
    },
    {
      "path": "packages/registry-angular/blocks/form-layouts/index.ts",
      "content": "export { UiFormLayoutsComponent, type FormLayoutsAccess } from './form-layouts.component'\n",
      "type": "registry:block",
      "target": "~/src/app/components/blocks/form-layouts/index.ts"
    }
  ],
  "dependencies": [
    "lucide-angular"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/button.json",
    "https://uipkge.dev/r/angular/input.json",
    "https://uipkge.dev/r/angular/label.json",
    "https://uipkge.dev/r/angular/radio-group.json",
    "https://uipkge.dev/r/angular/section-card.json",
    "https://uipkge.dev/r/angular/select.json",
    "https://uipkge.dev/r/angular/switch.json",
    "https://uipkge.dev/r/angular/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"
  ]
}