{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "nested-layer",
  "title": "Nested Layer",
  "description": "Helper used by the Get IT Done components.",
  "dependencies": [],
  "registryDependencies": [
    "https://zero-design.itdone.de/r/theme.json"
  ],
  "files": [
    {
      "path": "registry/lib/nested-layer.ts",
      "content": "'use client';\n\nimport * as React from 'react';\n\n// A popup layer inside a dialog or sheet (select list, menu, popover, combobox list) owns the first Escape.\n// The Radix Select trigger keeps focus while its list is open and reports it as aria-expanded.\nconst NESTED_LAYER = '[data-radix-popper-content-wrapper],[role=\"listbox\"],[role=\"menu\"],button[role=\"combobox\"][aria-expanded=\"true\"]';\n\n// Set by the overlay content while one Escape press is handled, read by the overlay root before it closes.\nexport type EscapeGuard = React.MutableRefObject<boolean>;\n\nexport const EscapeGuardContext = React.createContext<EscapeGuard | null>(null);\n\nexport function escapeBelongsToNestedLayer(event: KeyboardEvent): boolean {\n  const target = event.target;\n  if (!(target instanceof Element)) return false;\n  if (target.closest(NESTED_LAYER) !== null) return true;\n  // SingleSelect and MultiSelect keep focus in their search field while the list is open; the list only holds items then.\n  return target.closest('.command')?.querySelector('[cmdk-item]') != null;\n}\n\n// Safety net. With aligned Radix versions every layer shares one dismissable-layer stack and only the innermost layer sees Escape, so the guard stays idle for Radix layers. It still covers a consumer that pins an older copy (separate stacks) and nested popups that are not Radix layers: the content marks such a press and the root skips the close. Radix marks the event as handled once the overlay has seen it, which would stop the nested layer from closing, so the flag is reported as unset for the layers that follow.\nexport function guardNestedEscape(guard: EscapeGuard | null, event: KeyboardEvent) {\n  if (!guard || !escapeBelongsToNestedLayer(event)) return;\n  Object.defineProperty(event, 'defaultPrevented', { configurable: true, get: () => false });\n  guard.current = true;\n  queueMicrotask(() => {\n    guard.current = false;\n  });\n}\n\n// Open state that can veto a close while the guard is set. It works controlled and uncontrolled.\nexport function useGuardedOpen({\n  open,\n  defaultOpen,\n  onOpenChange,\n}: {\n  open?: boolean;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean) => void;\n}) {\n  const guard = React.useRef(false);\n  const [inner, setInner] = React.useState(defaultOpen ?? false);\n  const controlled = open !== undefined;\n  const handleOpenChange = React.useCallback(\n    (next: boolean) => {\n      if (!next && guard.current) return;\n      if (!controlled) setInner(next);\n      onOpenChange?.(next);\n    },\n    [controlled, onOpenChange],\n  );\n  return { guard, open: controlled ? open : inner, onOpenChange: handleOpenChange };\n}\n",
      "type": "registry:lib"
    }
  ],
  "type": "registry:lib"
}