{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "scope",
  "title": "Scope",
  "description": "The org ▸ project scope contract shared by the scoped-shell blocks: OrgRef/ProjectRef display snapshots, the Scope type and the onOrgChange/onProjectChange/onProjectClear callback vocabulary.",
  "files": [
    {
      "path": "components/blocks/scope.tsx",
      "content": "/**\n * scope — the org ▸ project scope contract shared by the scoped-shell blocks\n * (ScopeBreadcrumbs, ScopedNav, AppSwitcher and the AppShell top bar).\n *\n * The Nexus app family scopes every screen to an ORGANISATION (the auth\n * boundary — switching org changes what the user is allowed to see) and,\n * optionally, to one CONSTRUCTION PROJECT inside it. Blocks receive the scope\n * as plain display snapshots and report changes through callbacks; they hold\n * NO persistence and NO auth. The consumer owns the source of truth — in the\n * nx app the org lives on the user profile and the project is derived from\n * the URL (`/app/projects/[slug]/…`) — and re-renders the blocks with the new\n * scope. See `docs/scoped-shell.md` for the full architecture note.\n *\n * This file is deliberately type-only (plus one tiny helper): it exists so\n * every scoped block agrees on one vocabulary without importing each other.\n */\n\n/** Display snapshot of an organisation — the auth scope. */\nexport type OrgRef = {\n  id: string\n  name: string\n  /** Square logo/avatar; falls back to initials derived from the name. */\n  logoUrl?: string\n  /** Secondary line in switcher menus (e.g. the viewer's role, or a plan). */\n  meta?: string\n}\n\n/** Display snapshot of a construction project within the scoped org. */\nexport type ProjectRef = {\n  id: string\n  name: string\n  /** Human reference (e.g. \"RQ-014\") shown alongside the client in menus. */\n  reference?: string\n  /** Client / employer name shown in switcher menus. */\n  client?: string\n}\n\n/**\n * The active scope: always an organisation, optionally a project within it.\n * `project: null` means the user is at workspace level (cross-project\n * dashboard, projects picker…); a non-null project means every nav entry and\n * breadcrumb tail is project-scoped.\n */\nexport type Scope = {\n  org: OrgRef\n  project: ProjectRef | null\n}\n\n/**\n * Change callbacks a scope-aware control reports through. All optional at the\n * usage site — blocks accept the subset they can trigger:\n *\n * - `onOrgChange`   — the user picked another organisation. Consumers must\n *   treat this as an auth-scope change: clear any project selection that\n *   belongs to the old org and re-resolve permissions/data.\n * - `onProjectChange` — the user picked a project (entering project scope, or\n *   jumping between projects while already scoped). Consumers should land on\n *   the project's overview — never carry a sub-path from the previous\n *   project across (a stale record from project A must not render under\n *   project B).\n * - `onProjectClear` — the user left project scope (\"All projects\" in the\n *   breadcrumb menu, or the nav's back row). Consumers typically return to\n *   the projects picker.\n */\nexport type ScopeChangeHandlers = {\n  onOrgChange?: (orgId: string) => void\n  onProjectChange?: (projectId: string) => void\n  onProjectClear?: () => void\n}\n\n/** Initials for an org/project avatar fallback (first letters of two words). */\nexport function scopeInitials(name: string): string {\n  return name\n    .split(/\\s+/)\n    .filter(Boolean)\n    .slice(0, 2)\n    .map((word) => word[0]?.toUpperCase() ?? \"\")\n    .join(\"\")\n}\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}