{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "scope-picker",
  "title": "Scope Picker",
  "description": "The nx-ui Scope Picker block.",
  "dependencies": [
    "@untitledui/icons@^0.0.23"
  ],
  "registryDependencies": [
    "@nx-ui/input",
    "@nx-ui/popover",
    "@nx-ui/utils"
  ],
  "files": [
    {
      "path": "components/blocks/scope-picker.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n  AlertCircle,\n  Building01,\n  Check,\n  ChevronDown,\n  ChevronRight,\n  LayersTwo01,\n  RefreshCcw01,\n  SearchLg,\n} from \"@untitledui/icons\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Input } from \"@/components/ui/input\"\nimport {\n  Popover,\n  PopoverContent,\n  PopoverTrigger,\n} from \"@/components/ui/popover\"\n\n/** The app-local view selector. It never changes the identity session. */\nexport type ViewScope =\n  | { type: \"all-accessible\" }\n  | { type: \"organisation\"; orgId: string; extent: ScopeExtent }\n\nexport type ScopeExtent = \"self\" | \"subtree\"\n\n/** A short, consumer-supplied summary of access to a node. */\nexport type ScopeAccessSummary = {\n  /** Copy such as \"Your accessible divisions\" or \"Group view\". */\n  label: string\n  /** Optional disclosed count. The picker never derives this value. */\n  count?: number\n  /** Optional disclosed denominator. The picker never derives this value. */\n  total?: number\n}\n\n/**\n * Display metadata for an organisation in the hierarchy. The consumer owns\n * the directory and supplies only nodes that the current actor may discover.\n */\nexport type OrganisationScopeNode = {\n  id: string\n  parentOrganizationId: string | null\n  name: string\n  shortName?: string\n  kind: \"group\" | \"standard\"\n  unitLabel?: string\n  selectableExtents: readonly ScopeExtent[]\n  /** True when children exist but have not been loaded into this node. */\n  hasChildren?: boolean\n  /** A supplied access/count summary; no values are inferred here. */\n  accessSummary?: ScopeAccessSummary\n  /** Full ancestry to disambiguate duplicate names in search results. */\n  path?: readonly ScopePathSegment[]\n}\n\n/** Minimal path metadata for remote search results. */\nexport type ScopePathSegment = Pick<\n  OrganisationScopeNode,\n  \"id\" | \"name\" | \"shortName\" | \"kind\" | \"unitLabel\"\n>\n\n/** One page returned by either asynchronous directory callback. */\nexport type ScopeNodePage = {\n  nodes: readonly OrganisationScopeNode[]\n  nextCursor?: string | null\n}\n\nexport type ScopeLoadOptions = {\n  signal: AbortSignal\n  cursor?: string | null\n}\n\n/** Load direct children for a parent. Pass null to load the root page. */\nexport type ScopeChildrenLoader = (\n  parentOrganizationId: string | null,\n  options: ScopeLoadOptions\n) => Promise<ScopeNodePage>\n\n/** Search the consumer's already-authorised directory. */\nexport type ScopeSearch = (\n  query: string,\n  options: ScopeLoadOptions\n) => Promise<ScopeNodePage>\n\nexport type ScopeRequestStamp = {\n  requestId: number\n  generation?: number\n}\n\nexport type ScopePickerProps = Omit<\n  React.ComponentProps<\"div\">,\n  \"children\" | \"onChange\"\n> & {\n  value: ViewScope\n  onChange: (scope: ViewScope) => void\n  /** Show the synthetic all-accessible root only when the product permits it. */\n  allowAllAccessible?: boolean\n  /** Small directory mode. These nodes are never fetched by nx-ui. */\n  nodes?: readonly OrganisationScopeNode[]\n  /** Remote search mode. Search results must include path metadata where needed. */\n  search?: ScopeSearch\n  /** Remote children mode. Pagination and retries are managed by the picker. */\n  loadChildren?: ScopeChildrenLoader\n  /** Display data for a selected value that is not present in the current page. */\n  selectedNode?: OrganisationScopeNode | null\n  /** Adds an externally known error to the rendered picker state. */\n  error?: React.ReactNode\n  /** Adds an externally known loading state to the rendered picker state. */\n  loading?: boolean\n  /** Called when an externally managed error's retry affordance is used. */\n  onRetry?: () => void\n  allAccessibleLabel?: string\n  searchPlaceholder?: string\n  emptyLabel?: string\n  loadingLabel?: string\n  errorLabel?: string\n  unavailableLabel?: string\n  selectSelfLabel?: string\n  selectSubtreeLabel?: string\n  ariaLabel?: string\n}\n\ntype PageState = {\n  nodes: OrganisationScopeNode[]\n  nextCursor: string | null\n  loading: boolean\n  loaded: boolean\n  error: unknown\n  requestId: number\n}\n\nconst EMPTY_PAGE_STATE: PageState = { nodes: [], nextCursor: null, loading: false, loaded: false, error: null, requestId: 0 }\n\ntype SearchState = PageState & { query: string }\n\nconst ROOT_KEY = \"__scope-root__\"\nconst EMPTY_NODES: readonly OrganisationScopeNode[] = []\n\nfunction pageKey(parentOrganizationId: string | null): string {\n  return parentOrganizationId ?? ROOT_KEY\n}\n\nfunction isAbortError(error: unknown): boolean {\n  return error instanceof DOMException && error.name === \"AbortError\"\n}\n\nfunction mergeNodes(\n  first: readonly OrganisationScopeNode[],\n  second: readonly OrganisationScopeNode[]\n): OrganisationScopeNode[] {\n  const result = new Map<string, OrganisationScopeNode>()\n  for (const node of [...first, ...second]) result.set(node.id, node)\n  return [...result.values()]\n}\n\n/** Find every cached node made unavailable by a refreshed directory page. */\nexport function removedScopeSubtreeIds(\n  nodes: readonly OrganisationScopeNode[],\n  parentOrganizationId: string | null,\n  refreshedPage: readonly OrganisationScopeNode[]\n): ReadonlySet<string> {\n  const refreshedIds = new Set(refreshedPage.map((node) => node.id))\n  const removedIds = new Set(\n    nodes\n      .filter(\n        (node) =>\n          node.parentOrganizationId === parentOrganizationId &&\n          !refreshedIds.has(node.id)\n      )\n      .map((node) => node.id)\n  )\n  const childrenByParent = new Map<string, string[]>()\n  for (const node of nodes) {\n    if (!node.parentOrganizationId) continue\n    const children = childrenByParent.get(node.parentOrganizationId) ?? []\n    children.push(node.id)\n    childrenByParent.set(node.parentOrganizationId, children)\n  }\n  const pending = [...removedIds]\n  while (pending.length > 0) {\n    const parentId = pending.pop()!\n    for (const childId of childrenByParent.get(parentId) ?? []) {\n      if (!removedIds.has(childId)) {\n        removedIds.add(childId)\n        pending.push(childId)\n      }\n    }\n  }\n  return removedIds\n}\n\n/** Remove state that would otherwise make a reappearing node look already loaded. */\nexport function clearScopeSubtreeState<T>(\n  state: Readonly<Record<string, T>>,\n  removedIds: ReadonlySet<string>\n): Record<string, T> {\n  return Object.fromEntries(\n    Object.entries(state).filter(([key]) => !removedIds.has(key))\n  ) as Record<string, T>\n}\n\n/** Remove revoked rows from the expanded tree so their stale child state cannot render. */\nexport function clearScopeSubtreeExpansion(\n  expanded: ReadonlySet<string>,\n  removedIds: ReadonlySet<string>\n): ReadonlySet<string> {\n  return new Set([...expanded].filter((id) => !removedIds.has(id)))\n}\n\n/** Abort and retire descendant requests before an old response can refill the cache. */\nexport function invalidateScopeSubtreeRequests(\n  removedIds: ReadonlySet<string>,\n  controllers: ReadonlyMap<AbortController, string>,\n  requestIds: Map<string, number>\n): void {\n  for (const [controller, key] of controllers) {\n    if (!removedIds.has(key)) continue\n    requestIds.delete(key)\n    controller.abort()\n  }\n}\n\n/** Replace a refreshed directory page so revoked nodes cannot remain selectable. */\nexport function replaceScopePageNodes(\n  nodes: readonly OrganisationScopeNode[],\n  parentOrganizationId: string | null,\n  refreshedPage: readonly OrganisationScopeNode[]\n): OrganisationScopeNode[] {\n  const removedIds = removedScopeSubtreeIds(nodes, parentOrganizationId, refreshedPage)\n\n  return mergeNodes(\n    nodes.filter((node) => !removedIds.has(node.id)),\n    refreshedPage\n  )\n}\n\n/** Choose the default extent without guessing any access policy. */\nexport function defaultScopeExtent(\n  node: OrganisationScopeNode\n): ScopeExtent | null {\n  if (node.selectableExtents.includes(\"subtree\") && node.kind === \"group\") {\n    return \"subtree\"\n  }\n  if (node.selectableExtents.includes(\"self\")) return \"self\"\n  if (node.selectableExtents.includes(\"subtree\")) return \"subtree\"\n  return null\n}\n\n/** Convert a display node into the scope emitted by the controlled picker. */\nexport function scopeForNode(\n  node: OrganisationScopeNode,\n  extent = defaultScopeExtent(node)\n): ViewScope | null {\n  if (!extent || !node.selectableExtents.includes(extent)) return null\n  return { type: \"organisation\", orgId: node.id, extent }\n}\n\n/** Keep an empty page's cursor visible so consumers can continue pagination. */\nexport function scopePageHasMore(\n  page: Pick<ScopeNodePage, \"nextCursor\"> | null | undefined\n): boolean {\n  return Boolean(page?.nextCursor)\n}\n\n/** Ignore an async response after a newer request, refresh, or abort. */\nexport function scopeRequestIsCurrent(\n  stamp: ScopeRequestStamp,\n  currentRequestId: number | undefined,\n  signal: AbortSignal,\n  currentGeneration?: number\n): boolean {\n  return (\n    !signal.aborted &&\n    stamp.requestId === currentRequestId &&\n    (stamp.generation === undefined ||\n      currentGeneration === undefined ||\n      stamp.generation === currentGeneration)\n  )\n}\n\n/**\n * Return the path shown beneath a search result. Supplied path metadata wins;\n * the small directory mode derives a path only from the supplied nodes.\n */\nexport function scopeNodePath(\n  node: OrganisationScopeNode,\n  nodes: readonly OrganisationScopeNode[]\n): ScopePathSegment[] {\n  if (node.path && node.path.length > 0) return [...node.path]\n\n  const byId = new Map(nodes.map((entry) => [entry.id, entry]))\n  const path: ScopePathSegment[] = []\n  const seen = new Set<string>()\n  let current: OrganisationScopeNode | undefined = node\n  while (current && !seen.has(current.id)) {\n    seen.add(current.id)\n    path.unshift(current)\n    current = current.parentOrganizationId\n      ? byId.get(current.parentOrganizationId)\n      : undefined\n  }\n  return path\n}\n\n/** Case-insensitive local directory search, including ancestry. */\nexport function searchScopeNodes(\n  nodes: readonly OrganisationScopeNode[],\n  query: string\n): OrganisationScopeNode[] {\n  const needle = query.trim().toLocaleLowerCase()\n  if (!needle) return [...nodes]\n  return nodes.filter((node) => {\n    const pathText = scopeNodePath(node, nodes)\n      .map((segment) => `${segment.name} ${segment.shortName ?? \"\"}`)\n      .join(\" \")\n    return `${node.name} ${node.shortName ?? \"\"} ${node.unitLabel ?? \"\"} ${pathText}`\n      .toLocaleLowerCase()\n      .includes(needle)\n  })\n}\n\n/**\n * Roots visible to the current directory. A partial customer directory may\n * omit an inaccessible parent, so its permitted node becomes a local root.\n */\nexport function visibleScopeRoots(\n  nodes: readonly OrganisationScopeNode[]\n): OrganisationScopeNode[] {\n  return nodes.filter(\n    (node) =>\n      node.parentOrganizationId === null ||\n      !nodes.some((entry) => entry.id === node.parentOrganizationId)\n  )\n}\n\nfunction summaryText(summary?: ScopeAccessSummary): string | null {\n  if (!summary) return null\n  if (summary.count === undefined) return summary.label\n  const denominator = summary.total === undefined ? \"\" : `/${summary.total}`\n  return `${summary.label} · ${summary.count}${denominator}`\n}\n\nfunction nodeLabel(node: OrganisationScopeNode): string {\n  return node.shortName || node.name\n}\n\nfunction selectedExtent(\n  value: ViewScope,\n  node: OrganisationScopeNode | undefined\n): ScopeExtent | null {\n  return value.type === \"organisation\" &&\n    node?.id === value.orgId &&\n    node.selectableExtents.includes(value.extent)\n    ? value.extent\n    : null\n}\n\nfunction NodeIcon({ node }: { node: OrganisationScopeNode }) {\n  return node.kind === \"group\" ? (\n    <LayersTwo01 className=\"size-4 shrink-0 text-fg-brand-secondary\" aria-hidden=\"true\" />\n  ) : (\n    <Building01 className=\"size-4 shrink-0 text-fg-quaternary\" aria-hidden=\"true\" />\n  )\n}\n\nfunction LoadingRows() {\n  return (\n    <div className=\"flex flex-col gap-2 px-2 py-2\" aria-hidden=\"true\">\n      {[\"w-4/5\", \"w-3/5\", \"w-2/3\"].map((width) => (\n        <div key={width} className=\"flex items-center gap-2 py-2\">\n          <div className=\"size-4 animate-pulse rounded bg-muted\" />\n          <div className={cn(\"h-3 animate-pulse rounded bg-muted\", width)} />\n        </div>\n      ))}\n    </div>\n  )\n}\n\nfunction ErrorState({\n  label,\n  onRetry,\n}: {\n  label: React.ReactNode\n  onRetry?: () => void\n}) {\n  return (\n    <div className=\"flex flex-col items-center gap-2 px-4 py-7 text-center\" role=\"alert\">\n      <AlertCircle className=\"size-5 text-fg-error-primary\" aria-hidden=\"true\" />\n      <p className=\"text-sm text-muted-foreground\">{label}</p>\n      {onRetry ? (\n        <button\n          type=\"button\"\n          className=\"inline-flex cursor-pointer items-center gap-1.5 rounded-md px-2 py-1 text-sm font-semibold text-text-brand-secondary outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring/25\"\n          onClick={onRetry}\n        >\n          <RefreshCcw01 className=\"size-3.5\" aria-hidden=\"true\" />\n          Try again\n        </button>\n      ) : null}\n    </div>\n  )\n}\n\nfunction ScopeNodeRow({\n  node,\n  depth,\n  nodes,\n  expanded,\n  onToggle,\n  onSelect,\n  onSelectExtent,\n  selected,\n  selectedExtentValue,\n  loading,\n  error,\n  onRetry,\n  nextCursor,\n  onLoadMore,\n  children,\n  selectSelfLabel,\n  selectSubtreeLabel,\n}: {\n  node: OrganisationScopeNode\n  depth: number\n  nodes: readonly OrganisationScopeNode[]\n  expanded: boolean\n  onToggle: () => void\n  onSelect: () => void\n  onSelectExtent: (extent: ScopeExtent) => void\n  selected: boolean\n  selectedExtentValue: ScopeExtent | null\n  loading: boolean\n  error: unknown\n  onRetry: () => void\n  nextCursor: string | null\n  onLoadMore: (cursor: string) => void\n  children: React.ReactNode\n  selectSelfLabel: string\n  selectSubtreeLabel: string\n}) {\n  const hasChildren =\n    node.hasChildren ?? nodes.some((entry) => entry.parentOrganizationId === node.id)\n  const isSelectable = node.selectableExtents.length > 0\n  const summary = summaryText(node.accessSummary)\n  const path = scopeNodePath(node, nodes)\n  const showExtentChoices = node.selectableExtents.length > 1\n\n  return (\n    <div data-scope-node-id={node.id}>\n      <div\n        className=\"flex min-w-0 items-start gap-1 rounded-lg px-1 py-1 hover:bg-muted/60\"\n        style={{ paddingInlineStart: `${depth * 1.25 + 0.25}rem` }}\n      >\n        {hasChildren ? (\n          <button\n            type=\"button\"\n            className=\"mt-1 inline-flex size-7 shrink-0 cursor-pointer items-center justify-center rounded-md text-fg-quaternary outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/25\"\n            aria-label={`${expanded ? \"Collapse\" : \"Expand\"} ${nodeLabel(node)}`}\n            aria-expanded={expanded}\n            onClick={onToggle}\n          >\n            {expanded ? (\n              <ChevronDown className=\"size-4\" aria-hidden=\"true\" />\n            ) : (\n              <ChevronRight className=\"size-4\" aria-hidden=\"true\" />\n            )}\n          </button>\n        ) : (\n          <span className=\"inline-flex size-7 shrink-0\" aria-hidden=\"true\" />\n        )}\n\n        <button\n          type=\"button\"\n          className={cn(\n            \"flex min-w-0 flex-1 cursor-pointer items-start gap-2 rounded-md px-2 py-1.5 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring/25\",\n            \"disabled:cursor-default disabled:opacity-60\",\n            selected && \"bg-muted\"\n          )}\n          aria-disabled={!isSelectable}\n          aria-pressed={selected}\n          onClick={isSelectable ? onSelect : undefined}\n        >\n          <NodeIcon node={node} />\n          <span className=\"flex min-w-0 flex-1 flex-col\">\n            <span className=\"flex min-w-0 items-center gap-2\">\n              <span className=\"truncate text-sm font-semibold text-secondary-foreground\">\n                {nodeLabel(node)}\n              </span>\n              {node.unitLabel ? (\n                <span className=\"shrink-0 text-xs text-muted-foreground\">\n                  {node.unitLabel}\n                </span>\n              ) : null}\n            </span>\n            <span className=\"truncate text-xs text-muted-foreground\">\n              {summary ?? (isSelectable ? node.name : \"No view available\")}\n            </span>\n            {path.length > 1 ? (\n              <span className=\"truncate text-xs text-fg-quaternary\">\n                {path.map((segment) => segment.name).join(\" › \")}\n              </span>\n            ) : null}\n          </span>\n          {selected ? (\n            <Check className=\"mt-0.5 size-4 shrink-0 text-fg-brand-primary\" aria-hidden=\"true\" />\n          ) : null}\n        </button>\n      </div>\n\n      {showExtentChoices ? (\n        <div\n          className=\"flex flex-wrap gap-1 pb-1.5\"\n          style={{ paddingInlineStart: `${(depth + 1) * 1.25 + 2.5}rem` }}\n          aria-label={`Choose view for ${nodeLabel(node)}`}\n        >\n          {node.selectableExtents.includes(\"self\") ? (\n            <button\n              type=\"button\"\n              className={cn(\n                \"cursor-pointer rounded-full border border-border px-2 py-0.5 text-xs font-semibold text-muted-foreground outline-none hover:border-ring hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/25\",\n                selectedExtentValue === \"self\" && \"border-ring bg-muted text-foreground\"\n              )}\n              aria-pressed={selectedExtentValue === \"self\"}\n              onClick={() => onSelectExtent(\"self\")}\n            >\n              {selectSelfLabel}\n            </button>\n          ) : null}\n          {node.selectableExtents.includes(\"subtree\") ? (\n            <button\n              type=\"button\"\n              className={cn(\n                \"cursor-pointer rounded-full border border-border px-2 py-0.5 text-xs font-semibold text-muted-foreground outline-none hover:border-ring hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/25\",\n                selectedExtentValue === \"subtree\" && \"border-ring bg-muted text-foreground\"\n              )}\n              aria-pressed={selectedExtentValue === \"subtree\"}\n              onClick={() => onSelectExtent(\"subtree\")}\n            >\n              {selectSubtreeLabel}\n            </button>\n          ) : null}\n        </div>\n      ) : null}\n\n      {expanded ? (\n        <div role=\"group\" aria-label={`${nodeLabel(node)} children`}>\n          {loading ? <LoadingRows /> : null}\n          {error ? (\n            <ErrorState label=\"Children could not be loaded.\" onRetry={onRetry} />\n          ) : null}\n          {!loading && !error && children}\n          {!loading && !error && scopePageHasMore({ nextCursor }) ? (\n            <button\n              type=\"button\"\n              className=\"ml-10 cursor-pointer rounded-md px-2 py-1.5 text-sm font-semibold text-text-brand-secondary outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring/25\"\n              onClick={() => {\n                if (nextCursor) onLoadMore(nextCursor)\n              }}\n            >\n              Load more children\n            </button>\n          ) : null}\n        </div>\n      ) : null}\n    </div>\n  )\n}\n\nfunction ScopeNodeTree({\n  nodes,\n  allNodes,\n  depth = 0,\n  expanded,\n  onToggle,\n  onSelect,\n  onSelectExtent,\n  value,\n  selectedNode,\n  pageStates,\n  loadChildrenFor,\n  loadChildrenPage,\n  selectSelfLabel,\n  selectSubtreeLabel,\n}: {\n  nodes: readonly OrganisationScopeNode[]\n  allNodes: readonly OrganisationScopeNode[]\n  depth?: number\n  expanded: ReadonlySet<string>\n  onToggle: (node: OrganisationScopeNode) => void\n  onSelect: (node: OrganisationScopeNode, extent?: ScopeExtent) => void\n  onSelectExtent: (node: OrganisationScopeNode, extent: ScopeExtent) => void\n  value: ViewScope\n  selectedNode?: OrganisationScopeNode | null\n  pageStates: Readonly<Record<string, PageState>>\n  loadChildrenFor: (parentOrganizationId: string | null, force?: boolean) => void\n  loadChildrenPage: (parentOrganizationId: string | null, cursor: string) => void\n  selectSelfLabel: string\n  selectSubtreeLabel: string\n}) {\n  return (\n    <>\n      {nodes.map((node) => {\n        const children = allNodes.filter(\n          (entry) => entry.parentOrganizationId === node.id\n        )\n        const key = pageKey(node.id)\n        const state = pageStates[key]\n        const currentNode =\n          allNodes.find((entry) => entry.id === node.id) ??\n          (selectedNode?.id === node.id ? selectedNode : undefined)\n        const rowSelected =\n          value.type === \"organisation\" &&\n          value.orgId === node.id &&\n          selectedExtent(value, currentNode) !== null\n        return (\n          <ScopeNodeRow\n            key={node.id}\n            node={node}\n            depth={depth}\n            nodes={allNodes}\n            expanded={expanded.has(node.id)}\n            onToggle={() => onToggle(node)}\n            onSelect={() => onSelect(node)}\n            onSelectExtent={(extent) => onSelectExtent(node, extent)}\n            selected={rowSelected}\n            selectedExtentValue={selectedExtent(value, currentNode)}\n            loading={Boolean(state?.loading)}\n            error={state?.error}\n            onRetry={() => loadChildrenFor(node.id, true)}\n            nextCursor={state?.nextCursor ?? null}\n            onLoadMore={(cursor) => loadChildrenPage(node.id, cursor)}\n            selectSelfLabel={selectSelfLabel}\n            selectSubtreeLabel={selectSubtreeLabel}\n          >\n            {expanded.has(node.id) && children.length > 0 ? (\n              <ScopeNodeTree\n                nodes={children}\n                allNodes={allNodes}\n                depth={depth + 1}\n                expanded={expanded}\n                onToggle={onToggle}\n                onSelect={onSelect}\n                onSelectExtent={onSelectExtent}\n                value={value}\n                selectedNode={selectedNode}\n                pageStates={pageStates}\n                loadChildrenFor={loadChildrenFor}\n                loadChildrenPage={loadChildrenPage}\n                selectSelfLabel={selectSelfLabel}\n                selectSubtreeLabel={selectSubtreeLabel}\n              />\n            ) : null}\n          </ScopeNodeRow>\n        )\n      })}\n    </>\n  )\n}\n\nfunction formatSearchPath(\n  node: OrganisationScopeNode,\n  nodes: readonly OrganisationScopeNode[]\n): string | null {\n  const path = scopeNodePath(node, nodes)\n  return path.length > 1 ? path.map((segment) => segment.name).join(\" › \") : null\n}\n\nfunction ScopeSearchResults({\n  nodes,\n  allNodes,\n  value,\n  selectedNode,\n  onSelect,\n  onSelectExtent,\n  nextCursor,\n  loading,\n  onLoadMore,\n  selectSelfLabel,\n    selectSubtreeLabel,\n}: {\n  nodes: readonly OrganisationScopeNode[]\n  allNodes: readonly OrganisationScopeNode[]\n  value: ViewScope\n  selectedNode?: OrganisationScopeNode | null\n  onSelect: (node: OrganisationScopeNode, extent?: ScopeExtent) => void\n  onSelectExtent: (node: OrganisationScopeNode, extent: ScopeExtent) => void\n  nextCursor: string | null\n  loading: boolean\n  onLoadMore: () => void\n  selectSelfLabel: string\n  selectSubtreeLabel: string\n}) {\n  return (\n    <div className=\"flex flex-col gap-1 p-2\">\n      {nodes.map((node) => {\n        const currentNode =\n          allNodes.find((entry) => entry.id === node.id) ??\n          (selectedNode?.id === node.id ? selectedNode : undefined)\n        const rowSelected =\n          value.type === \"organisation\" &&\n          value.orgId === node.id &&\n          selectedExtent(value, currentNode) !== null\n        const path = formatSearchPath(node, allNodes)\n        const summary = summaryText(node.accessSummary)\n        const isSelectable = node.selectableExtents.length > 0\n        return (\n          <div key={node.id} data-scope-search-result-id={node.id}>\n            <div className=\"flex min-w-0 items-start gap-1 rounded-lg p-1 hover:bg-muted/60\">\n              <button\n                type=\"button\"\n                className=\"flex min-w-0 flex-1 cursor-pointer items-start gap-2 rounded-md px-2 py-1.5 text-left outline-none focus-visible:ring-2 focus-visible:ring-ring/25 disabled:cursor-default disabled:opacity-60\"\n                aria-disabled={!isSelectable}\n                aria-pressed={rowSelected}\n                onClick={isSelectable ? () => onSelect(node) : undefined}\n              >\n                <NodeIcon node={node} />\n                <span className=\"flex min-w-0 flex-1 flex-col\">\n                  <span className=\"truncate text-sm font-semibold text-secondary-foreground\">\n                    {nodeLabel(node)}\n                  </span>\n                  <span className=\"truncate text-xs text-muted-foreground\">\n                    {summary ?? (isSelectable ? node.name : \"No view available\")}\n                  </span>\n                  {path ? (\n                    <span className=\"truncate text-xs text-fg-quaternary\">{path}</span>\n                  ) : null}\n                </span>\n                {rowSelected ? (\n                  <Check className=\"mt-0.5 size-4 shrink-0 text-fg-brand-primary\" aria-hidden=\"true\" />\n                ) : null}\n              </button>\n            </div>\n            {node.selectableExtents.length > 1 ? (\n              <div className=\"flex flex-wrap gap-1 pb-1.5 pl-9\">\n                {node.selectableExtents.includes(\"self\") ? (\n                  <button\n                    type=\"button\"\n                    className={cn(\n                      \"cursor-pointer rounded-full border border-border px-2 py-0.5 text-xs font-semibold text-muted-foreground outline-none hover:border-ring hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/25\",\n                      selectedExtent(value, currentNode) === \"self\" && \"border-ring bg-muted text-foreground\"\n                    )}\n                    aria-pressed={selectedExtent(value, currentNode) === \"self\"}\n                    onClick={() => onSelectExtent(node, \"self\")}\n                  >\n                    {selectSelfLabel}\n                  </button>\n                ) : null}\n                {node.selectableExtents.includes(\"subtree\") ? (\n                  <button\n                    type=\"button\"\n                    className={cn(\n                      \"cursor-pointer rounded-full border border-border px-2 py-0.5 text-xs font-semibold text-muted-foreground outline-none hover:border-ring hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/25\",\n                      selectedExtent(value, currentNode) === \"subtree\" && \"border-ring bg-muted text-foreground\"\n                    )}\n                    aria-pressed={selectedExtent(value, currentNode) === \"subtree\"}\n                    onClick={() => onSelectExtent(node, \"subtree\")}\n                  >\n                    {selectSubtreeLabel}\n                  </button>\n                ) : null}\n              </div>\n            ) : null}\n          </div>\n        )\n      })}\n      {loading ? <LoadingRows /> : null}\n      {scopePageHasMore({ nextCursor }) ? (\n        <button\n          type=\"button\"\n          className=\"mx-1 cursor-pointer rounded-md px-2 py-1.5 text-sm font-semibold text-text-brand-secondary outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring/25 disabled:cursor-default disabled:opacity-60\"\n          disabled={loading}\n          onClick={onLoadMore}\n        >\n          {loading ? \"Loading…\" : \"Load more results\"}\n        </button>\n      ) : null}\n    </div>\n  )\n}\n\n/**\n * A controlled hierarchy scope picker. It renders a small local directory by\n * default and can switch to consumer-owned asynchronous search/children\n * callbacks. It owns only transient popup, search and expansion state.\n */\nfunction ScopePicker({\n  value,\n  onChange,\n  nodes = EMPTY_NODES,\n  allowAllAccessible = false,\n  search,\n  loadChildren,\n  selectedNode,\n  error,\n  loading = false,\n  onRetry,\n  allAccessibleLabel = \"All clients\",\n  searchPlaceholder = \"Search organisations…\",\n  emptyLabel = \"No organisations found.\",\n  loadingLabel = \"Loading organisations…\",\n  errorLabel = \"Organisations could not be loaded.\",\n  unavailableLabel = \"Organisation scope unavailable\",\n  selectSelfLabel = \"Organisation only\",\n  selectSubtreeLabel = \"Group view\",\n  ariaLabel = \"Choose organisation scope\",\n  className,\n  ...props\n}: ScopePickerProps) {\n  const [open, setOpen] = React.useState(false)\n  const [query, setQuery] = React.useState(\"\")\n  const [expanded, setExpanded] = React.useState<ReadonlySet<string>>(new Set())\n  const [loadedNodes, setLoadedNodes] = React.useState<OrganisationScopeNode[]>([])\n  const [pageStates, setPageStates] = React.useState<Record<string, PageState>>({})\n  const [searchState, setSearchState] = React.useState<SearchState | null>(null)\n  const triggerRef = React.useRef<HTMLButtonElement>(null)\n  const requestCounter = React.useRef(0)\n  const searchRequestId = React.useRef<number | undefined>(undefined)\n  const searchController = React.useRef<AbortController | null>(null)\n  const childControllers = React.useRef(new Set<AbortController>())\n  const childControllerKeys = React.useRef(new Map<AbortController, string>())\n  const childRequestIds = React.useRef(new Map<string, number>())\n  const loadedNodesRef = React.useRef<OrganisationScopeNode[]>(loadedNodes)\n  const directoryGeneration = React.useRef(0)\n  const nodesRef = React.useRef(nodes)\n  const searchRef = React.useRef(search)\n  const loadChildrenRef = React.useRef(loadChildren)\n\n  searchRef.current = search\n  loadChildrenRef.current = loadChildren\n\n  React.useEffect(() => {\n    if (nodesRef.current === nodes) return\n    nodesRef.current = nodes\n    directoryGeneration.current += 1\n    searchController.current?.abort()\n    searchController.current = null\n    for (const controller of childControllers.current) controller.abort()\n    childControllers.current.clear()\n    childControllerKeys.current.clear()\n    childRequestIds.current.clear()\n    loadedNodesRef.current = []\n    setLoadedNodes([])\n    setPageStates({})\n    setSearchState(null)\n  }, [nodes])\n\n  React.useEffect(\n    () => () => {\n      searchController.current?.abort()\n      for (const controller of childControllers.current) controller.abort()\n    },\n    []\n  )\n\n  const invalidateRemovedScopeSubtree = React.useCallback(\n    (removedIds: ReadonlySet<string>) => {\n      if (removedIds.size === 0) return\n      invalidateScopeSubtreeRequests(\n        removedIds,\n        childControllerKeys.current,\n        childRequestIds.current\n      )\n      setExpanded((previous) => clearScopeSubtreeExpansion(previous, removedIds))\n      setPageStates((previous) => clearScopeSubtreeState(previous, removedIds))\n    },\n    []\n  )\n\n  const allNodes = React.useMemo(\n    () => mergeNodes(nodes, loadedNodes),\n    [loadedNodes, nodes]\n  )\n  const rootNodes = React.useMemo(() => visibleScopeRoots(allNodes), [allNodes])\n  const resolvedSelectedNode =\n    selectedNode ??\n    (value.type === \"organisation\"\n      ? allNodes.find((node) => node.id === value.orgId)\n      : undefined)\n  const selectedScopeAvailable =\n    value.type === \"all-accessible\"\n      ? allowAllAccessible\n      : selectedExtent(value, resolvedSelectedNode) !== null\n  const selectedLabel =\n    value.type === \"all-accessible\" && allowAllAccessible\n      ? allAccessibleLabel\n      : value.type === \"organisation\" && !selectedScopeAvailable\n        ? resolvedSelectedNode\n          ? `${nodeLabel(resolvedSelectedNode)} · ${unavailableLabel}`\n          : unavailableLabel\n      : resolvedSelectedNode\n        ? nodeLabel(resolvedSelectedNode)\n        : unavailableLabel\n  const selectedSummary =\n    value.type === \"organisation\" && selectedScopeAvailable && resolvedSelectedNode\n      ? summaryText(resolvedSelectedNode.accessSummary)\n      : null\n\n  const closeAndRestoreFocus = React.useCallback(() => {\n    setOpen(false)\n    window.requestAnimationFrame(() => triggerRef.current?.focus())\n  }, [])\n\n  const commit = React.useCallback(\n    (node: OrganisationScopeNode, extent?: ScopeExtent) => {\n      const next = scopeForNode(node, extent)\n      if (!next) return\n      onChange(next)\n      closeAndRestoreFocus()\n    },\n    [closeAndRestoreFocus, onChange]\n  )\n\n  const loadChildrenFor = React.useCallback(\n    async (parentOrganizationId: string | null, force = false) => {\n      const loader = loadChildrenRef.current\n      if (!loader) return\n      const key = pageKey(parentOrganizationId)\n      const existing = pageStates[key]\n      if (existing?.loading || (existing?.loaded && !force)) return\n      const requestId = ++requestCounter.current\n      const stamp = { requestId }\n      const controller = new AbortController()\n      childControllers.current.add(controller)\n      childControllerKeys.current.set(controller, key)\n      childRequestIds.current.set(key, requestId)\n      setPageStates((previous) => ({\n        ...previous,\n        [key]: {\n          nodes: force ? [] : previous[key]?.nodes ?? [],\n          nextCursor: force ? null : previous[key]?.nextCursor ?? null,\n          loading: true,\n          loaded: Boolean(previous[key]?.loaded && !force),\n          error: null,\n          requestId,\n        },\n      }))\n      try {\n        const page = await loader(parentOrganizationId, {\n          signal: controller.signal,\n        })\n        if (!scopeRequestIsCurrent(stamp, childRequestIds.current.get(key), controller.signal)) {\n          return\n        }\n        const previousLoadedNodes = loadedNodesRef.current\n        if (force) {\n          invalidateRemovedScopeSubtree(\n            removedScopeSubtreeIds(previousLoadedNodes, parentOrganizationId, page.nodes)\n          )\n        }\n        const nextLoadedNodes = force\n          ? replaceScopePageNodes(previousLoadedNodes, parentOrganizationId, page.nodes)\n          : mergeNodes(previousLoadedNodes, page.nodes)\n        loadedNodesRef.current = nextLoadedNodes\n        setLoadedNodes(nextLoadedNodes)\n        setPageStates((previous) => ({\n          ...previous,\n          [key]: {\n            nodes: [...page.nodes],\n            nextCursor: page.nextCursor ?? null,\n            loading: false,\n            loaded: true,\n            error: null,\n            requestId,\n          },\n        }))\n      } catch (loadError) {\n        if (\n          !scopeRequestIsCurrent(stamp, childRequestIds.current.get(key), controller.signal) ||\n          isAbortError(loadError)\n        ) {\n          return\n        }\n        setPageStates((previous) => ({\n          ...previous,\n          [key]: {\n            nodes: previous[key]?.nodes ?? [],\n            nextCursor: previous[key]?.nextCursor ?? null,\n            loading: false,\n            loaded: false,\n            error: loadError,\n            requestId,\n          },\n        }))\n      } finally {\n        childControllers.current.delete(controller)\n        childControllerKeys.current.delete(controller)\n        if (childRequestIds.current.get(key) === requestId) {\n          childRequestIds.current.delete(key)\n        }\n      }\n    },\n    [invalidateRemovedScopeSubtree, pageStates]\n  )\n\n  const loadChildrenPage = React.useCallback(\n    async (parentOrganizationId: string | null, cursor: string) => {\n      const loader = loadChildrenRef.current\n      if (!loader) return\n      const key = pageKey(parentOrganizationId)\n      const requestId = ++requestCounter.current\n      const stamp = { requestId }\n      const controller = new AbortController()\n      childControllers.current.add(controller)\n      childControllerKeys.current.set(controller, key)\n      childRequestIds.current.set(key, requestId)\n      setPageStates((previous) => ({\n        ...previous,\n        [key]: { ...(previous[key] ?? EMPTY_PAGE_STATE), loading: true, error: null, requestId },\n      }))\n      try {\n        const page = await loader(parentOrganizationId, { signal: controller.signal, cursor })\n        if (!scopeRequestIsCurrent(stamp, childRequestIds.current.get(key), controller.signal)) {\n          return\n        }\n        const nextLoadedNodes = mergeNodes(loadedNodesRef.current, page.nodes)\n        loadedNodesRef.current = nextLoadedNodes\n        setLoadedNodes(nextLoadedNodes)\n        setPageStates((previous) => ({\n          ...previous,\n          [key]: {\n            nodes: mergeNodes(previous[key]?.nodes ?? [], page.nodes),\n            nextCursor: page.nextCursor ?? null,\n            loading: false,\n            loaded: true,\n            error: null,\n            requestId,\n          },\n        }))\n      } catch (loadError) {\n        if (\n          !scopeRequestIsCurrent(stamp, childRequestIds.current.get(key), controller.signal) ||\n          isAbortError(loadError)\n        ) {\n          return\n        }\n        setPageStates((previous) => ({\n          ...previous,\n          [key]: { ...(previous[key] ?? EMPTY_PAGE_STATE), loading: false, error: loadError, requestId },\n        }))\n      } finally {\n        childControllers.current.delete(controller)\n        childControllerKeys.current.delete(controller)\n        if (childRequestIds.current.get(key) === requestId) {\n          childRequestIds.current.delete(key)\n        }\n      }\n    },\n    []\n  )\n\n  const toggleNode = React.useCallback(\n    (node: OrganisationScopeNode) => {\n      setExpanded((previous) => {\n        const next = new Set(previous)\n        if (next.has(node.id)) next.delete(node.id)\n        else next.add(node.id)\n        return next\n      })\n      const hasLoadedChildren = allNodes.some(\n        (entry) => entry.parentOrganizationId === node.id\n      )\n      if (!hasLoadedChildren && node.hasChildren === true) {\n        void loadChildrenFor(node.id)\n      }\n    },\n    [allNodes, loadChildrenFor]\n  )\n\n  const runSearch = React.useCallback(\n    async (searchQuery: string, cursor?: string | null) => {\n      const searcher = searchRef.current\n      if (!searcher) return\n      if (!cursor) {\n        searchController.current?.abort()\n        searchController.current = new AbortController()\n      }\n      const controller = searchController.current ?? new AbortController()\n      searchController.current = controller\n      const generation = directoryGeneration.current\n      const requestId = ++requestCounter.current\n      const stamp = { requestId, generation }\n      searchRequestId.current = requestId\n      setSearchState((previous) => ({\n        query: searchQuery,\n        nodes: cursor ? previous?.nodes ?? [] : [],\n        nextCursor: cursor ?? null,\n        loading: true,\n        loaded: false,\n        error: null,\n        requestId,\n      }))\n      try {\n        const page = await searcher(searchQuery, {\n          signal: controller.signal,\n          cursor,\n        })\n        if (\n          !scopeRequestIsCurrent(\n            stamp,\n            searchRequestId.current,\n            controller.signal,\n            directoryGeneration.current\n          ) ||\n          searchController.current !== controller\n        ) {\n          return\n        }\n        setSearchState((previous) => ({\n          query: searchQuery,\n          nodes: cursor ? mergeNodes(previous?.nodes ?? [], page.nodes) : [...page.nodes],\n          nextCursor: page.nextCursor ?? null,\n          loading: false,\n          loaded: true,\n          error: null,\n          requestId,\n        }))\n      } catch (searchError) {\n        if (\n          !scopeRequestIsCurrent(\n            stamp,\n            searchRequestId.current,\n            controller.signal,\n            directoryGeneration.current\n          ) ||\n          searchController.current !== controller ||\n          isAbortError(searchError)\n        ) {\n          return\n        }\n        setSearchState((previous) => ({\n          query: searchQuery,\n          nodes: previous?.nodes ?? [],\n          nextCursor: previous?.nextCursor ?? null,\n          loading: false,\n          loaded: false,\n          error: searchError,\n          requestId,\n        }))\n      }\n    },\n    []\n  )\n\n  React.useEffect(() => {\n    const searchQuery = query.trim()\n    if (!open || !searchQuery || !searchRef.current) {\n      searchController.current?.abort()\n      setSearchState(null)\n      return\n    }\n    void runSearch(searchQuery)\n  }, [open, query, runSearch, nodes, search])\n\n  const rootState = pageStates[ROOT_KEY]\n  const hasRemoteRoot = Boolean(loadChildrenRef.current)\n  React.useEffect(() => {\n    if (!open || query.trim() || loading || !hasRemoteRoot || rootNodes.length > 0) return\n    if (!rootState?.loaded && !rootState?.loading) void loadChildrenFor(null)\n  }, [hasRemoteRoot, loadChildrenFor, loading, open, query, rootNodes.length, rootState])\n\n  const searchResults = query.trim()\n    ? search\n      ? searchState?.nodes ?? []\n      : searchScopeNodes(allNodes, query)\n    : []\n  const searchLoading = Boolean(search && (!searchState || searchState.loading))\n  const searchError = searchState?.error\n  const showingSearch = query.trim().length > 0\n  const isEmpty = showingSearch\n    ? !searchLoading &&\n      !searchError &&\n      searchResults.length === 0 &&\n      !scopePageHasMore(searchState)\n    : !loading &&\n      !rootState?.loading &&\n      !error &&\n      rootNodes.length === 0 &&\n      !scopePageHasMore(rootState)\n\n  return (\n    <Popover\n      open={open}\n      onOpenChange={(next) => {\n        setOpen(next)\n        if (!next) {\n          searchController.current?.abort()\n          window.requestAnimationFrame(() => triggerRef.current?.focus())\n        }\n      }}\n    >\n      <PopoverTrigger\n        ref={triggerRef}\n        className={cn(\n          \"flex min-w-0 max-w-full cursor-pointer items-center gap-2 rounded-lg border border-input bg-background px-3 py-2 text-left text-sm shadow-xs outline-none transition-colors hover:bg-muted focus-visible:border-ring focus-visible:ring-4 focus-visible:ring-ring/25\",\n          value.type === \"organisation\" && !resolvedSelectedNode && \"border-warning/50\",\n          className\n        )}\n        aria-label={ariaLabel}\n      >\n        <span className=\"flex min-w-0 flex-1 flex-col\">\n          <span className=\"flex min-w-0 items-center gap-2\">\n            <span className=\"truncate font-semibold text-secondary-foreground\">\n              {selectedLabel}\n            </span>\n            {value.type === \"organisation\" ? (\n              <span className=\"hidden shrink-0 text-xs text-muted-foreground sm:inline\">\n                {value.extent === \"subtree\" ? selectSubtreeLabel : selectSelfLabel}\n              </span>\n            ) : null}\n          </span>\n          {selectedSummary ? (\n            <span className=\"truncate text-xs text-muted-foreground\">{selectedSummary}</span>\n          ) : null}\n        </span>\n        <ChevronDown className=\"size-4 shrink-0 text-fg-quaternary\" aria-hidden=\"true\" />\n      </PopoverTrigger>\n\n      <PopoverContent\n        align=\"start\"\n        sideOffset={8}\n        className=\"w-[min(32rem,calc(100vw-1rem))] max-w-[calc(100vw-1rem)] gap-0 overflow-hidden p-0\"\n        {...props}\n      >\n        <div role=\"dialog\" aria-label={ariaLabel} aria-busy={loading || searchLoading}>\n          <div className=\"border-b border-border p-3\">\n            <div className=\"relative\">\n              <SearchLg\n                className=\"pointer-events-none absolute top-1/2 left-3 size-4 -translate-y-1/2 text-fg-quaternary\"\n                aria-hidden=\"true\"\n              />\n              <Input\n                autoFocus\n                value={query}\n                onChange={(event) => setQuery(event.currentTarget.value)}\n                onKeyDown={(event) => {\n                  if (event.key === \"Escape\") {\n                    event.preventDefault()\n                    closeAndRestoreFocus()\n                  }\n                }}\n                placeholder={searchPlaceholder}\n                aria-label=\"Search organisations\"\n                className=\"h-10 pl-9 shadow-none\"\n              />\n            </div>\n          </div>\n\n          <div className=\"max-h-[min(30rem,calc(100vh-10rem))] overflow-y-auto p-2\">\n            {allowAllAccessible ? (\n              <>\n                <button\n                  type=\"button\"\n                  className={cn(\n                    \"flex w-full cursor-pointer items-center gap-2 rounded-lg px-3 py-2.5 text-left outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring/25\",\n                    value.type === \"all-accessible\" && \"bg-muted\"\n                  )}\n                  aria-current={value.type === \"all-accessible\" ? \"true\" : undefined}\n                  aria-pressed={value.type === \"all-accessible\"}\n                  onClick={() => {\n                    onChange({ type: \"all-accessible\" })\n                    closeAndRestoreFocus()\n                  }}\n                >\n                  <LayersTwo01 className=\"size-4 text-fg-brand-secondary\" aria-hidden=\"true\" />\n                  <span className=\"flex min-w-0 flex-1 flex-col\">\n                    <span className=\"text-sm font-semibold text-secondary-foreground\">\n                      {allAccessibleLabel}\n                    </span>\n                    <span className=\"text-xs text-muted-foreground\">\n                      Every organisation available to you in this product\n                    </span>\n                  </span>\n                  {value.type === \"all-accessible\" ? (\n                    <Check className=\"size-4 text-fg-brand-primary\" aria-hidden=\"true\" />\n                  ) : null}\n                </button>\n\n                <div className=\"my-1 border-t border-border\" />\n              </>\n            ) : null}\n\n            {showingSearch ? (\n              searchError ? (\n                <ErrorState label={errorLabel} onRetry={() => void runSearch(query.trim())} />\n              ) : searchLoading && searchResults.length === 0 ? (\n                <>\n                  <LoadingRows />\n                  <span className=\"sr-only\">Searching organisations…</span>\n                </>\n              ) : isEmpty ? (\n                <div className=\"px-4 py-7 text-center text-sm text-muted-foreground\">\n                  {emptyLabel}\n                </div>\n              ) : (\n                <ScopeSearchResults\n                  nodes={searchResults}\n                  allNodes={allNodes}\n                  value={value}\n                  selectedNode={resolvedSelectedNode}\n                  onSelect={commit}\n                  onSelectExtent={commit}\n                  nextCursor={searchState?.nextCursor ?? null}\n                  loading={searchLoading}\n                  onLoadMore={() => {\n                    if (searchState?.nextCursor) {\n                      void runSearch(query.trim(), searchState.nextCursor)\n                    }\n                  }}\n                  selectSelfLabel={selectSelfLabel}\n                  selectSubtreeLabel={selectSubtreeLabel}\n                />\n              )\n            ) : loading || rootState?.loading ? (\n              <>\n                <LoadingRows />\n                <span className=\"sr-only\">{loadingLabel}</span>\n              </>\n            ) : error || rootState?.error ? (\n              <ErrorState\n                label={error ?? errorLabel}\n                onRetry={\n                  onRetry ??\n                  (loadChildren\n                    ? () => void loadChildrenFor(null, true)\n                    : undefined)\n                }\n              />\n            ) : isEmpty ? (\n              <div className=\"px-4 py-7 text-center text-sm text-muted-foreground\">\n                {emptyLabel}\n              </div>\n            ) : (\n              <>\n                <ScopeNodeTree\n                  nodes={rootNodes}\n                  allNodes={allNodes}\n                  expanded={expanded}\n                  onToggle={toggleNode}\n                  onSelect={commit}\n                  onSelectExtent={commit}\n                  value={value}\n                  selectedNode={resolvedSelectedNode}\n                  pageStates={pageStates}\n                  loadChildrenFor={(parent, force) => void loadChildrenFor(parent, force)}\n                  loadChildrenPage={(parent, cursor) => void loadChildrenPage(parent, cursor)}\n                  selectSelfLabel={selectSelfLabel}\n                  selectSubtreeLabel={selectSubtreeLabel}\n                />\n                {scopePageHasMore(rootState) ? (\n                  <button\n                    type=\"button\"\n                    className=\"mx-2 cursor-pointer rounded-md px-2 py-1.5 text-sm font-semibold text-text-brand-secondary outline-none hover:bg-muted focus-visible:ring-2 focus-visible:ring-ring/25\"\n                    onClick={() => {\n                      const cursor = rootState?.nextCursor\n                      if (cursor) {\n                        void loadChildrenPage(null, cursor)\n                      }\n                    }}\n                  >\n                    Load more organisations\n                  </button>\n                ) : null}\n              </>\n            )}\n          </div>\n        </div>\n      </PopoverContent>\n    </Popover>\n  )\n}\n\nexport { ScopePicker }\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}