@fabio.caffarello/react-design-system 3.12.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/dist/granular/index.js +393 -389
  2. package/dist/granular/index.js.map +1 -1
  3. package/dist/granular/ui/components/Autocomplete/Autocomplete.js +103 -86
  4. package/dist/granular/ui/components/Autocomplete/Autocomplete.js.map +1 -1
  5. package/dist/granular/ui/components/Autocomplete/AutocompleteList.js +57 -47
  6. package/dist/granular/ui/components/Autocomplete/AutocompleteList.js.map +1 -1
  7. package/dist/granular/ui/components/Autocomplete/AutocompleteOption.js +21 -20
  8. package/dist/granular/ui/components/Autocomplete/AutocompleteOption.js.map +1 -1
  9. package/dist/granular/ui/components/Breadcrumb/Breadcrumb.js.map +1 -1
  10. package/dist/granular/ui/components/ButtonGroup/ButtonGroup.js +68 -0
  11. package/dist/granular/ui/components/ButtonGroup/ButtonGroup.js.map +1 -0
  12. package/dist/granular/ui/components/ColorPicker/ColorPicker.js.map +1 -1
  13. package/dist/granular/ui/components/CommandPalette/CommandPalette.js +187 -149
  14. package/dist/granular/ui/components/CommandPalette/CommandPalette.js.map +1 -1
  15. package/dist/granular/ui/components/DataGrid/DataGrid.js +92 -92
  16. package/dist/granular/ui/components/DataGrid/DataGrid.js.map +1 -1
  17. package/dist/granular/ui/components/DatePicker/DatePickerCalendar.js +154 -139
  18. package/dist/granular/ui/components/DatePicker/DatePickerCalendar.js.map +1 -1
  19. package/dist/granular/ui/components/Dialog/AlertDialog.js +73 -40
  20. package/dist/granular/ui/components/Dialog/AlertDialog.js.map +1 -1
  21. package/dist/granular/ui/components/Dialog/DialogContent.js +54 -48
  22. package/dist/granular/ui/components/Dialog/DialogContent.js.map +1 -1
  23. package/dist/granular/ui/components/Dialog/DialogDescription.js +31 -31
  24. package/dist/granular/ui/components/Dialog/DialogDescription.js.map +1 -1
  25. package/dist/granular/ui/components/Dialog/DialogTitle.js +30 -30
  26. package/dist/granular/ui/components/Dialog/DialogTitle.js.map +1 -1
  27. package/dist/granular/ui/components/Drawer/Drawer.js.map +1 -1
  28. package/dist/granular/ui/components/Dropdown/Dropdown.js.map +1 -1
  29. package/dist/granular/ui/components/EmptyState/EmptyState.js.map +1 -1
  30. package/dist/granular/ui/components/FileUpload/FileUpload.js.map +1 -1
  31. package/dist/granular/ui/components/Form/Form.js +38 -37
  32. package/dist/granular/ui/components/Form/Form.js.map +1 -1
  33. package/dist/granular/ui/components/Form/FormField.js +28 -26
  34. package/dist/granular/ui/components/Form/FormField.js.map +1 -1
  35. package/dist/granular/ui/components/Header/Header.js.map +1 -1
  36. package/dist/granular/ui/components/Header/components/HeaderActions.js.map +1 -1
  37. package/dist/granular/ui/components/Header/components/HeaderHamburger.js.map +1 -1
  38. package/dist/granular/ui/components/Header/components/HeaderLogo.js.map +1 -1
  39. package/dist/granular/ui/components/Header/components/HeaderMobileMenu.js.map +1 -1
  40. package/dist/granular/ui/components/Header/components/HeaderNavigation.js.map +1 -1
  41. package/dist/granular/ui/components/Header/contexts/HeaderContext.js.map +1 -1
  42. package/dist/granular/ui/components/Menu/Menu.js.map +1 -1
  43. package/dist/granular/ui/components/Modal/Modal.js +98 -86
  44. package/dist/granular/ui/components/Modal/Modal.js.map +1 -1
  45. package/dist/granular/ui/components/MultiSelect/MultiSelect.js +122 -106
  46. package/dist/granular/ui/components/MultiSelect/MultiSelect.js.map +1 -1
  47. package/dist/granular/ui/components/Navigation/Navigation.js.map +1 -1
  48. package/dist/granular/ui/components/PageHeader/PageHeader.js.map +1 -1
  49. package/dist/granular/ui/components/Pagination/Pagination.js.map +1 -1
  50. package/dist/granular/ui/components/Popover/Popover.js.map +1 -1
  51. package/dist/granular/ui/components/Rating/Rating.js.map +1 -1
  52. package/dist/granular/ui/components/SearchInput/SearchInput.js.map +1 -1
  53. package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarGroup.js +82 -64
  54. package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarGroup.js.map +1 -1
  55. package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarItem.js +30 -29
  56. package/dist/granular/ui/components/SideNavbar/components/Navbar/NavbarItem.js.map +1 -1
  57. package/dist/granular/ui/components/SideNavbar/components/SideNavbarResizeHandle.js +37 -35
  58. package/dist/granular/ui/components/SideNavbar/components/SideNavbarResizeHandle.js.map +1 -1
  59. package/dist/granular/ui/components/SideNavbar/providers/SideNavbarStateProvider.js +57 -57
  60. package/dist/granular/ui/components/SideNavbar/providers/SideNavbarStateProvider.js.map +1 -1
  61. package/dist/granular/ui/components/Stepper/Stepper.js +102 -94
  62. package/dist/granular/ui/components/Stepper/Stepper.js.map +1 -1
  63. package/dist/granular/ui/components/Table/Table.js +41 -35
  64. package/dist/granular/ui/components/Table/Table.js.map +1 -1
  65. package/dist/granular/ui/components/Table/TableActions/TableActions.js.map +1 -1
  66. package/dist/granular/ui/components/Table/TableFilters/TableFilters.js +49 -46
  67. package/dist/granular/ui/components/Table/TableFilters/TableFilters.js.map +1 -1
  68. package/dist/granular/ui/components/Table/TablePagination/TablePagination.js.map +1 -1
  69. package/dist/granular/ui/components/Table/TableProvider.js +82 -80
  70. package/dist/granular/ui/components/Table/TableProvider.js.map +1 -1
  71. package/dist/granular/ui/components/Table/TableRow.js +57 -53
  72. package/dist/granular/ui/components/Table/TableRow.js.map +1 -1
  73. package/dist/granular/ui/components/Table/useColumnResizing.js +53 -53
  74. package/dist/granular/ui/components/Table/useColumnResizing.js.map +1 -1
  75. package/dist/granular/ui/components/TimePicker/TimePicker.js +149 -103
  76. package/dist/granular/ui/components/TimePicker/TimePicker.js.map +1 -1
  77. package/dist/granular/ui/components/Timeline/Timeline.js.map +1 -1
  78. package/dist/granular/ui/hooks/useFocusRestore.js +14 -15
  79. package/dist/granular/ui/hooks/useFocusRestore.js.map +1 -1
  80. package/dist/granular/ui/primitives/Badge/Badge.js.map +1 -1
  81. package/dist/granular/ui/primitives/Checkbox/Checkbox.js.map +1 -1
  82. package/dist/granular/ui/primitives/Chip/Chip.js +91 -71
  83. package/dist/granular/ui/primitives/Chip/Chip.js.map +1 -1
  84. package/dist/granular/ui/primitives/Dot/Dot.js +99 -0
  85. package/dist/granular/ui/primitives/Dot/Dot.js.map +1 -0
  86. package/dist/granular/ui/primitives/ErrorMessage/ErrorMessage.js.map +1 -1
  87. package/dist/granular/ui/primitives/Input/Input.js.map +1 -1
  88. package/dist/granular/ui/primitives/Label/Label.js.map +1 -1
  89. package/dist/granular/ui/primitives/NavLink/NavLink.js.map +1 -1
  90. package/dist/granular/ui/primitives/Radio/Radio.js.map +1 -1
  91. package/dist/granular/ui/primitives/Select/Select.js.map +1 -1
  92. package/dist/granular/ui/primitives/Separator/Separator.js.map +1 -1
  93. package/dist/granular/ui/primitives/Skeleton/Skeleton.js.map +1 -1
  94. package/dist/granular/ui/primitives/Slider/Slider.js.map +1 -1
  95. package/dist/granular/ui/primitives/Spinner/Spinner.js.map +1 -1
  96. package/dist/granular/ui/primitives/Switch/Switch.js.map +1 -1
  97. package/dist/granular/ui/primitives/Tooltip/Tooltip.js.map +1 -1
  98. package/dist/granular/ui/providers/DialogContext.js.map +1 -1
  99. package/dist/granular/ui/providers/DialogProvider.js +24 -20
  100. package/dist/granular/ui/providers/DialogProvider.js.map +1 -1
  101. package/dist/index.cjs +134 -134
  102. package/dist/index.cjs.map +1 -1
  103. package/dist/index.js +5945 -5542
  104. package/dist/index.js.map +1 -1
  105. package/dist/react-design-system.css +1 -1
  106. package/dist/server/index.cjs +7 -7
  107. package/dist/server/index.cjs.map +1 -1
  108. package/dist/server/index.js +404 -384
  109. package/dist/server/index.js.map +1 -1
  110. package/dist/ui/components/Autocomplete/AutocompleteList.d.ts +4 -0
  111. package/dist/ui/components/Autocomplete/AutocompleteOption.d.ts +8 -0
  112. package/dist/ui/components/Breadcrumb/Breadcrumb.d.ts +0 -1
  113. package/dist/ui/components/ButtonGroup/ButtonGroup.d.ts +2 -2
  114. package/dist/ui/components/ColorPicker/ColorPicker.d.ts +0 -1
  115. package/dist/ui/components/CommandPalette/CommandPalette.d.ts +0 -1
  116. package/dist/ui/components/DataGrid/DataGrid.d.ts +0 -1
  117. package/dist/ui/components/Dialog/DialogContent.d.ts +20 -1
  118. package/dist/ui/components/Drawer/Drawer.d.ts +0 -1
  119. package/dist/ui/components/Dropdown/Dropdown.d.ts +0 -1
  120. package/dist/ui/components/EmptyState/EmptyState.d.ts +0 -1
  121. package/dist/ui/components/FileUpload/FileUpload.d.ts +0 -1
  122. package/dist/ui/components/Form/FormField.d.ts +7 -0
  123. package/dist/ui/components/Header/Header.d.ts +1 -1
  124. package/dist/ui/components/Header/components/HeaderActions.d.ts +1 -1
  125. package/dist/ui/components/Header/components/HeaderHamburger.d.ts +1 -1
  126. package/dist/ui/components/Header/components/HeaderLogo.d.ts +1 -1
  127. package/dist/ui/components/Header/components/HeaderMobileMenu.d.ts +1 -1
  128. package/dist/ui/components/Header/components/HeaderNavigation.d.ts +1 -1
  129. package/dist/ui/components/Header/contexts/HeaderContext.d.ts +1 -1
  130. package/dist/ui/components/Menu/Menu.d.ts +0 -1
  131. package/dist/ui/components/Modal/Modal.d.ts +1 -2
  132. package/dist/ui/components/Navigation/Navigation.d.ts +1 -1
  133. package/dist/ui/components/PageHeader/PageHeader.d.ts +1 -1
  134. package/dist/ui/components/Pagination/Pagination.d.ts +0 -1
  135. package/dist/ui/components/Popover/Popover.d.ts +0 -1
  136. package/dist/ui/components/Rating/Rating.d.ts +0 -1
  137. package/dist/ui/components/SearchInput/SearchInput.d.ts +0 -1
  138. package/dist/ui/components/Stepper/Stepper.d.ts +0 -1
  139. package/dist/ui/components/Table/TableActions/TableActions.d.ts +0 -1
  140. package/dist/ui/components/Table/TableFilters/TableFilters.d.ts +0 -1
  141. package/dist/ui/components/Table/TablePagination/TablePagination.d.ts +0 -1
  142. package/dist/ui/components/TimePicker/TimePicker.d.ts +0 -1
  143. package/dist/ui/components/Timeline/Timeline.d.ts +0 -1
  144. package/dist/ui/components/index.d.ts +2 -0
  145. package/dist/ui/primitives/Checkbox/Checkbox.d.ts +0 -1
  146. package/dist/ui/primitives/Chip/Chip.d.ts +21 -0
  147. package/dist/ui/primitives/ErrorMessage/ErrorMessage.d.ts +0 -1
  148. package/dist/ui/primitives/Input/Input.d.ts +0 -1
  149. package/dist/ui/primitives/Label/Label.d.ts +0 -1
  150. package/dist/ui/primitives/NavLink/NavLink.d.ts +1 -1
  151. package/dist/ui/primitives/Radio/Radio.d.ts +0 -1
  152. package/dist/ui/primitives/Select/Select.d.ts +0 -1
  153. package/dist/ui/primitives/Skeleton/Skeleton.d.ts +0 -1
  154. package/dist/ui/primitives/Slider/Slider.d.ts +0 -1
  155. package/dist/ui/primitives/Switch/Switch.d.ts +0 -1
  156. package/dist/ui/primitives/Tooltip/Tooltip.d.ts +0 -1
  157. package/dist/ui/primitives/index.d.ts +2 -0
  158. package/dist/ui/providers/DialogContext.d.ts +8 -0
  159. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"Spinner.js","sources":["../../../../../src/ui/primitives/Spinner/Spinner.tsx"],"sourcesContent":["\"use client\";\n\nimport { memo } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { Loader2 } from \"lucide-react\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { getTypographySize } from \"../../tokens/typography\";\nimport { cn, cva } from \"../../utils\";\n\nexport type SpinnerSize = \"sm\" | \"md\" | \"lg\";\nexport type SpinnerVariant = \"primary\" | \"secondary\" | \"neutral\";\n\nexport interface SpinnerProps extends HTMLAttributes<HTMLDivElement> {\n size?: SpinnerSize;\n variant?: SpinnerVariant;\n label?: string;\n}\n\n/**\n * Spinner Component\n *\n * A loading spinner component for indicating loading states.\n * Follows Atomic Design principles as an Atom component.\n * Uses Strategy Pattern for different size/variant combinations.\n *\n * @example\n * ```tsx\n * <Spinner size=\"md\" variant=\"primary\" label=\"Loading...\" />\n * ```\n */\n// Spinner variants using CVA\nconst spinnerVariants = cva(\"motion-safe:animate-spin\", {\n variants: {\n size: {\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-8 w-8\",\n },\n variant: {\n primary: \"text-fg-brand\",\n secondary: \"text-fg-brand-secondary\",\n neutral: \"text-fg-secondary\",\n },\n },\n defaultVariants: {\n size: \"md\",\n variant: \"primary\",\n },\n});\n\nconst Spinner = memo(function Spinner({\n size = \"md\",\n variant = \"primary\",\n label,\n className = \"\",\n ...props\n}: SpinnerProps) {\n return (\n <div\n className={cn(\"inline-flex\", \"items-center\", className)}\n role=\"status\"\n aria-label={label || \"Loading\"}\n aria-live=\"polite\"\n {...props}\n >\n <Loader2\n className={cn(spinnerVariants({ size, variant }))}\n aria-hidden=\"true\"\n />\n {label && (\n <span\n className={cn(\n getSpacingClass(\"sm\", \"ml\"),\n getTypographySize(\"bodySmall\"),\n \"text-fg-secondary\",\n \"sr-only\",\n )}\n >\n {label}\n </span>\n )}\n </div>\n );\n});\n\nSpinner.displayName = \"Spinner\";\n\nexport default Spinner;\n"],"names":["spinnerVariants","cva","Spinner","memo","_a","_b","size","variant","label","className","props","__objRest","jsxs","__spreadProps","__spreadValues","cn","jsx","Loader2","getSpacingClass","getTypographySize"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BA,MAAMA,IAAkBC,EAAI,4BAA4B;AAAA,EACtD,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,IAEN,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,IAAA;AAAA,EACX;AAAA,EAEF,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,SAAS;AAAA,EAAA;AAEb,CAAC,GAEKC,IAAUC,EAAK,SAAiBC,GAMrB;AANqB,MAAAC,IAAAD,GACpC;AAAA,UAAAE,IAAO;AAAA,IACP,SAAAC,IAAU;AAAA,IACV,OAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,MAJwBJ,GAKjCK,IAAAC,EALiCN,GAKjC;AAAA,IAJH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAGA,SACE,gBAAAO;AAAA,IAAC;AAAA,IAAAC,EAAAC,EAAA;AAAA,MACC,WAAWC,EAAG,eAAe,gBAAgBN,CAAS;AAAA,MACtD,MAAK;AAAA,MACL,cAAYD,KAAS;AAAA,MACrB,aAAU;AAAA,OACNE,IALL;AAAA,MAOC,UAAA;AAAA,QAAA,gBAAAM;AAAA,UAACC;AAAA,UAAA;AAAA,YACC,WAAWF,EAAGf,EAAgB,EAAE,MAAAM,GAAM,SAAAC,EAAA,CAAS,CAAC;AAAA,YAChD,eAAY;AAAA,UAAA;AAAA,QAAA;AAAA,QAEbC,KACC,gBAAAQ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWD;AAAA,cACTG,EAAgB,MAAM,IAAI;AAAA,cAC1BC,EAAkB,WAAW;AAAA,cAC7B;AAAA,cACA;AAAA,YAAA;AAAA,YAGD,UAAAX;AAAA,UAAA;AAAA,QAAA;AAAA,MACH;AAAA,IAAA;AAAA,EAAA;AAIR,CAAC;AAEDN,EAAQ,cAAc;"}
1
+ {"version":3,"file":"Spinner.js","sources":["../../../../../src/ui/primitives/Spinner/Spinner.tsx"],"sourcesContent":["\"use client\";\n\nimport { memo } from \"react\";\nimport type { HTMLAttributes } from \"react\";\nimport { Loader2 } from \"lucide-react\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { getTypographySize } from \"../../tokens/typography\";\nimport { cn, cva } from \"../../utils\";\n\nexport type SpinnerSize = \"sm\" | \"md\" | \"lg\";\nexport type SpinnerVariant = \"primary\" | \"secondary\" | \"neutral\";\n\nexport interface SpinnerProps extends HTMLAttributes<HTMLDivElement> {\n size?: SpinnerSize;\n variant?: SpinnerVariant;\n label?: string;\n}\n\n/**\n * Spinner Component\n *\n * A loading spinner component for indicating loading states.\n * Uses Strategy Pattern for different size/variant combinations.\n *\n * @example\n * ```tsx\n * <Spinner size=\"md\" variant=\"primary\" label=\"Loading...\" />\n * ```\n */\n// Spinner variants using CVA\nconst spinnerVariants = cva(\"motion-safe:animate-spin\", {\n variants: {\n size: {\n sm: \"h-4 w-4\",\n md: \"h-5 w-5\",\n lg: \"h-8 w-8\",\n },\n variant: {\n primary: \"text-fg-brand\",\n secondary: \"text-fg-brand-secondary\",\n neutral: \"text-fg-secondary\",\n },\n },\n defaultVariants: {\n size: \"md\",\n variant: \"primary\",\n },\n});\n\nconst Spinner = memo(function Spinner({\n size = \"md\",\n variant = \"primary\",\n label,\n className = \"\",\n ...props\n}: SpinnerProps) {\n return (\n <div\n className={cn(\"inline-flex\", \"items-center\", className)}\n role=\"status\"\n aria-label={label || \"Loading\"}\n aria-live=\"polite\"\n {...props}\n >\n <Loader2\n className={cn(spinnerVariants({ size, variant }))}\n aria-hidden=\"true\"\n />\n {label && (\n <span\n className={cn(\n getSpacingClass(\"sm\", \"ml\"),\n getTypographySize(\"bodySmall\"),\n \"text-fg-secondary\",\n \"sr-only\",\n )}\n >\n {label}\n </span>\n )}\n </div>\n );\n});\n\nSpinner.displayName = \"Spinner\";\n\nexport default Spinner;\n"],"names":["spinnerVariants","cva","Spinner","memo","_a","_b","size","variant","label","className","props","__objRest","jsxs","__spreadProps","__spreadValues","cn","jsx","Loader2","getSpacingClass","getTypographySize"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,MAAMA,IAAkBC,EAAI,4BAA4B;AAAA,EACtD,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,IAAA;AAAA,IAEN,SAAS;AAAA,MACP,SAAS;AAAA,MACT,WAAW;AAAA,MACX,SAAS;AAAA,IAAA;AAAA,EACX;AAAA,EAEF,iBAAiB;AAAA,IACf,MAAM;AAAA,IACN,SAAS;AAAA,EAAA;AAEb,CAAC,GAEKC,IAAUC,EAAK,SAAiBC,GAMrB;AANqB,MAAAC,IAAAD,GACpC;AAAA,UAAAE,IAAO;AAAA,IACP,SAAAC,IAAU;AAAA,IACV,OAAAC;AAAA,IACA,WAAAC,IAAY;AAAA,MAJwBJ,GAKjCK,IAAAC,EALiCN,GAKjC;AAAA,IAJH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAGA,SACE,gBAAAO;AAAA,IAAC;AAAA,IAAAC,EAAAC,EAAA;AAAA,MACC,WAAWC,EAAG,eAAe,gBAAgBN,CAAS;AAAA,MACtD,MAAK;AAAA,MACL,cAAYD,KAAS;AAAA,MACrB,aAAU;AAAA,OACNE,IALL;AAAA,MAOC,UAAA;AAAA,QAAA,gBAAAM;AAAA,UAACC;AAAA,UAAA;AAAA,YACC,WAAWF,EAAGf,EAAgB,EAAE,MAAAM,GAAM,SAAAC,EAAA,CAAS,CAAC;AAAA,YAChD,eAAY;AAAA,UAAA;AAAA,QAAA;AAAA,QAEbC,KACC,gBAAAQ;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,WAAWD;AAAA,cACTG,EAAgB,MAAM,IAAI;AAAA,cAC1BC,EAAkB,WAAW;AAAA,cAC7B;AAAA,cACA;AAAA,YAAA;AAAA,YAGD,UAAAX;AAAA,UAAA;AAAA,QAAA;AAAA,MACH;AAAA,IAAA;AAAA,EAAA;AAIR,CAAC;AAEDN,EAAQ,cAAc;"}
@@ -1 +1 @@
1
- {"version":3,"file":"Switch.js","sources":["../../../../../src/ui/primitives/Switch/Switch.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRef, memo, useId, useMemo, useCallback, useState } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { getAnimationClass } from \"../../tokens/animations\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { getSwitchClasses } from \"../../tokens/switch\";\nimport {\n getTypographySize,\n getTypographyWeight,\n} from \"../../tokens/typography\";\nimport { cn } from \"../../utils\";\n\nexport type SwitchSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface SwitchProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"size\" | \"type\"\n> {\n size?: SwitchSize;\n label?: string;\n /**\n * Secondary text rendered beneath the label, wired through\n * `aria-describedby`. Named `helperText` to match Input, Select,\n * Checkbox, and Radio — every form primitive in the DS uses the\n * same prop name for this role.\n */\n helperText?: string;\n error?: boolean;\n /**\n * Validation success state — paints the (off-state) track border\n * and (when `helperText` is also set) the helper-text color green.\n * Matches the Input + Select + Checkbox + Radio + Textarea\n * convention. Error takes precedence when both `error` and\n * `success` are set.\n */\n success?: boolean;\n}\n\n/**\n * Switch Component\n *\n * A toggle switch component for on/off states.\n * Follows Atomic Design principles as an Atom component.\n *\n * @example\n * ```tsx\n * <Switch checked={isEnabled} onChange={(e) => setIsEnabled(e.target.checked)} />\n *\n * <Switch\n * label=\"Enable notifications\"\n * helperText=\"Receive email notifications\"\n * checked={notifications}\n * onChange={(e) => setNotifications(e.target.checked)}\n * />\n * ```\n */\nconst Switch = memo(\n forwardRef<HTMLInputElement, SwitchProps>(function Switch(\n {\n size = \"md\",\n label,\n helperText,\n error = false,\n success = false,\n className = \"\",\n disabled = false,\n checked,\n defaultChecked,\n onChange,\n id,\n ...props\n },\n ref,\n ) {\n // Controlled / uncontrolled pattern.\n //\n // Previously this primitive accepted `defaultChecked` via\n // `...props` and forwarded it to the hidden `<input type=\"checkbox\">`\n // (form-integration shim), but the visible `<button role=\"switch\">`\n // bound `aria-checked={checked}` directly. With `checked` undefined\n // in uncontrolled mode, `aria-checked` was missing — axe\n // `aria-required-attr` (critical) flagged every uncontrolled Switch\n // because `role=\"switch\"` REQUIRES `aria-checked`. The visual track\n // and thumb also stuck at the off state because their classes\n // derived from the same `checked` prop.\n //\n // The fix is the standard React pattern: when `checked` is provided\n // the consumer controls state; otherwise `defaultChecked` seeds\n // internal state and the click/keydown handlers update it locally\n // AND notify `onChange`. The visible button, the hidden input, and\n // every classes() consumer all read from a single resolved\n // `currentChecked`.\n const isControlled = checked !== undefined;\n const [internalChecked, setInternalChecked] = useState<boolean>(\n defaultChecked ?? false,\n );\n const currentChecked = isControlled ? !!checked : internalChecked;\n // Stable fallback id when the consumer doesn't provide one. useId\n // is SSR-safe and stable across renders, replacing the deprecated\n // Math.random().substr() pattern.\n const reactId = useId();\n const switchId = id || `switch-${reactId}`;\n\n const labelId = useMemo(\n () => (label ? `${switchId}-label` : undefined),\n [label, switchId],\n );\n\n const helperId = useMemo(\n () => (helperText ? `${switchId}-helper` : undefined),\n [helperText, switchId],\n );\n\n // Component-scoped tokens (SWITCH_TOKENS) drive track/thumb/translate.\n const config = useMemo(() => getSwitchClasses(size), [size]);\n\n // Memoize focus ring color\n const focusRingColor = useMemo(\n () => \"focus:border-line-focus\".replace(\"focus:border-\", \"focus:ring-\"),\n [],\n );\n\n // Memoize classes — all consume `currentChecked` (the resolved\n // controlled-or-uncontrolled state), not the raw `checked` prop.\n const trackClasses = useMemo(\n () =>\n cn(\n \"relative\",\n \"inline-flex\",\n \"shrink-0\",\n \"cursor-pointer\",\n getRadiusClass(\"full\"),\n \"border-2\",\n \"border-transparent\",\n getAnimationClass(\"base\"),\n \"focus:outline-none\",\n \"focus:ring-2\",\n focusRingColor,\n \"focus:ring-offset-2\",\n config.track,\n currentChecked ? \"bg-surface-brand\" : \"bg-surface-muted\",\n // Border feedback only shows in the off state — the on-state\n // brand background already saturates the track and overrides\n // any colored outline visually. Error wins over success.\n error && !currentChecked && \"border-error\",\n !error && success && !currentChecked && \"border-success\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className,\n ),\n [\n focusRingColor,\n config.track,\n currentChecked,\n error,\n success,\n disabled,\n className,\n ],\n );\n\n const thumbClasses = useMemo(\n () =>\n cn(\n \"pointer-events-none\",\n \"inline-block\",\n getRadiusClass(\"full\"),\n \"bg-surface-base\",\n \"shadow\",\n \"transform\",\n getAnimationClass(\"base\"),\n config.thumb,\n currentChecked ? config.translate : \"translate-x-0\",\n ),\n [config.thumb, config.translate, currentChecked],\n );\n\n return (\n <div className={cn(\"flex\", \"items-start\", getSpacingClass(\"md\", \"gap\"))}>\n <div className=\"flex items-center\">\n <button\n type=\"button\"\n className={trackClasses}\n role=\"switch\"\n aria-checked={currentChecked}\n aria-labelledby={labelId}\n aria-describedby={helperId}\n disabled={disabled}\n onClick={useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n if (disabled) return;\n const next = !currentChecked;\n if (!isControlled) setInternalChecked(next);\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: { ...e.target, checked: next },\n currentTarget: { ...e.currentTarget, checked: next },\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n },\n [disabled, onChange, currentChecked, isControlled],\n )}\n onKeyDown={useCallback(\n (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (disabled) return;\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n e.preventDefault();\n const next = !currentChecked;\n if (!isControlled) setInternalChecked(next);\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: { ...e.target, checked: next },\n currentTarget: { ...e.currentTarget, checked: next },\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n },\n [disabled, onChange, currentChecked, isControlled],\n )}\n >\n <span className={thumbClasses} />\n </button>\n {/* Hidden checkbox for form-data integration. Follows the\n resolved `currentChecked` so submission picks up the\n correct value in both controlled and uncontrolled modes.\n `aria-hidden` + tabIndex=-1 keep it out of AT and Tab\n order — interaction happens on the visible button above.\n The onChange is a no-op fallback (real state changes\n flow through the button's handler); React requires it\n alongside `checked` to suppress the controlled-input\n warning when the consumer doesn't supply onChange. */}\n <input\n ref={ref}\n type=\"checkbox\"\n id={switchId}\n checked={currentChecked}\n onChange={onChange ?? (() => {})}\n disabled={disabled}\n className=\"sr-only\"\n aria-hidden=\"true\"\n tabIndex={-1}\n {...props}\n />\n </div>\n {(label || helperText) && (\n <div className=\"flex-1\">\n {label && (\n <label\n id={labelId}\n htmlFor={switchId}\n className={cn(\n \"block\",\n getTypographySize(\"bodySmall\"),\n getTypographyWeight(\"label\"),\n error ? \"text-fg-error\" : \"text-fg-primary\",\n disabled ? \"opacity-50\" : \"cursor-pointer\",\n )}\n >\n {label}\n </label>\n )}\n {helperText && (\n <p\n id={helperId}\n className={cn(\n getSpacingClass(\"xs\", \"mt\"),\n getTypographySize(\"bodySmall\"),\n error\n ? \"text-fg-error\"\n : success\n ? \"text-fg-success\"\n : \"text-fg-secondary\",\n )}\n >\n {helperText}\n </p>\n )}\n </div>\n )}\n </div>\n );\n }),\n);\n\nSwitch.displayName = \"Switch\";\n\nexport default Switch;\n"],"names":["Switch","memo","forwardRef","_a","ref","_b","size","label","helperText","error","success","className","disabled","checked","defaultChecked","onChange","id","props","__objRest","isControlled","internalChecked","setInternalChecked","useState","currentChecked","reactId","useId","switchId","labelId","useMemo","helperId","config","getSwitchClasses","focusRingColor","trackClasses","cn","getRadiusClass","getAnimationClass","thumbClasses","jsxs","getSpacingClass","jsx","useCallback","e","next","syntheticEvent","__spreadProps","__spreadValues","getTypographySize","getTypographyWeight"],"mappings":"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"}
1
+ {"version":3,"file":"Switch.js","sources":["../../../../../src/ui/primitives/Switch/Switch.tsx"],"sourcesContent":["\"use client\";\n\nimport { forwardRef, memo, useId, useMemo, useCallback, useState } from \"react\";\nimport type { InputHTMLAttributes } from \"react\";\nimport { getAnimationClass } from \"../../tokens/animations\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { getSwitchClasses } from \"../../tokens/switch\";\nimport {\n getTypographySize,\n getTypographyWeight,\n} from \"../../tokens/typography\";\nimport { cn } from \"../../utils\";\n\nexport type SwitchSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface SwitchProps extends Omit<\n InputHTMLAttributes<HTMLInputElement>,\n \"size\" | \"type\"\n> {\n size?: SwitchSize;\n label?: string;\n /**\n * Secondary text rendered beneath the label, wired through\n * `aria-describedby`. Named `helperText` to match Input, Select,\n * Checkbox, and Radio — every form primitive in the DS uses the\n * same prop name for this role.\n */\n helperText?: string;\n error?: boolean;\n /**\n * Validation success state — paints the (off-state) track border\n * and (when `helperText` is also set) the helper-text color green.\n * Matches the Input + Select + Checkbox + Radio + Textarea\n * convention. Error takes precedence when both `error` and\n * `success` are set.\n */\n success?: boolean;\n}\n\n/**\n * Switch Component\n *\n * A toggle switch component for on/off states.\n *\n * @example\n * ```tsx\n * <Switch checked={isEnabled} onChange={(e) => setIsEnabled(e.target.checked)} />\n *\n * <Switch\n * label=\"Enable notifications\"\n * helperText=\"Receive email notifications\"\n * checked={notifications}\n * onChange={(e) => setNotifications(e.target.checked)}\n * />\n * ```\n */\nconst Switch = memo(\n forwardRef<HTMLInputElement, SwitchProps>(function Switch(\n {\n size = \"md\",\n label,\n helperText,\n error = false,\n success = false,\n className = \"\",\n disabled = false,\n checked,\n defaultChecked,\n onChange,\n id,\n ...props\n },\n ref,\n ) {\n // Controlled / uncontrolled pattern.\n //\n // Previously this primitive accepted `defaultChecked` via\n // `...props` and forwarded it to the hidden `<input type=\"checkbox\">`\n // (form-integration shim), but the visible `<button role=\"switch\">`\n // bound `aria-checked={checked}` directly. With `checked` undefined\n // in uncontrolled mode, `aria-checked` was missing — axe\n // `aria-required-attr` (critical) flagged every uncontrolled Switch\n // because `role=\"switch\"` REQUIRES `aria-checked`. The visual track\n // and thumb also stuck at the off state because their classes\n // derived from the same `checked` prop.\n //\n // The fix is the standard React pattern: when `checked` is provided\n // the consumer controls state; otherwise `defaultChecked` seeds\n // internal state and the click/keydown handlers update it locally\n // AND notify `onChange`. The visible button, the hidden input, and\n // every classes() consumer all read from a single resolved\n // `currentChecked`.\n const isControlled = checked !== undefined;\n const [internalChecked, setInternalChecked] = useState<boolean>(\n defaultChecked ?? false,\n );\n const currentChecked = isControlled ? !!checked : internalChecked;\n // Stable fallback id when the consumer doesn't provide one. useId\n // is SSR-safe and stable across renders, replacing the deprecated\n // Math.random().substr() pattern.\n const reactId = useId();\n const switchId = id || `switch-${reactId}`;\n\n const labelId = useMemo(\n () => (label ? `${switchId}-label` : undefined),\n [label, switchId],\n );\n\n const helperId = useMemo(\n () => (helperText ? `${switchId}-helper` : undefined),\n [helperText, switchId],\n );\n\n // Component-scoped tokens (SWITCH_TOKENS) drive track/thumb/translate.\n const config = useMemo(() => getSwitchClasses(size), [size]);\n\n // Memoize focus ring color\n const focusRingColor = useMemo(\n () => \"focus:border-line-focus\".replace(\"focus:border-\", \"focus:ring-\"),\n [],\n );\n\n // Memoize classes — all consume `currentChecked` (the resolved\n // controlled-or-uncontrolled state), not the raw `checked` prop.\n const trackClasses = useMemo(\n () =>\n cn(\n \"relative\",\n \"inline-flex\",\n \"shrink-0\",\n \"cursor-pointer\",\n getRadiusClass(\"full\"),\n \"border-2\",\n \"border-transparent\",\n getAnimationClass(\"base\"),\n \"focus:outline-none\",\n \"focus:ring-2\",\n focusRingColor,\n \"focus:ring-offset-2\",\n config.track,\n currentChecked ? \"bg-surface-brand\" : \"bg-surface-muted\",\n // Border feedback only shows in the off state — the on-state\n // brand background already saturates the track and overrides\n // any colored outline visually. Error wins over success.\n error && !currentChecked && \"border-error\",\n !error && success && !currentChecked && \"border-success\",\n disabled && \"opacity-50 cursor-not-allowed\",\n className,\n ),\n [\n focusRingColor,\n config.track,\n currentChecked,\n error,\n success,\n disabled,\n className,\n ],\n );\n\n const thumbClasses = useMemo(\n () =>\n cn(\n \"pointer-events-none\",\n \"inline-block\",\n getRadiusClass(\"full\"),\n \"bg-surface-base\",\n \"shadow\",\n \"transform\",\n getAnimationClass(\"base\"),\n config.thumb,\n currentChecked ? config.translate : \"translate-x-0\",\n ),\n [config.thumb, config.translate, currentChecked],\n );\n\n return (\n <div className={cn(\"flex\", \"items-start\", getSpacingClass(\"md\", \"gap\"))}>\n <div className=\"flex items-center\">\n <button\n type=\"button\"\n className={trackClasses}\n role=\"switch\"\n aria-checked={currentChecked}\n aria-labelledby={labelId}\n aria-describedby={helperId}\n disabled={disabled}\n onClick={useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n if (disabled) return;\n const next = !currentChecked;\n if (!isControlled) setInternalChecked(next);\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: { ...e.target, checked: next },\n currentTarget: { ...e.currentTarget, checked: next },\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n },\n [disabled, onChange, currentChecked, isControlled],\n )}\n onKeyDown={useCallback(\n (e: React.KeyboardEvent<HTMLButtonElement>) => {\n if (disabled) return;\n if (e.key !== \"Enter\" && e.key !== \" \") return;\n e.preventDefault();\n const next = !currentChecked;\n if (!isControlled) setInternalChecked(next);\n if (onChange) {\n const syntheticEvent = {\n ...e,\n target: { ...e.target, checked: next },\n currentTarget: { ...e.currentTarget, checked: next },\n } as unknown as React.ChangeEvent<HTMLInputElement>;\n onChange(syntheticEvent);\n }\n },\n [disabled, onChange, currentChecked, isControlled],\n )}\n >\n <span className={thumbClasses} />\n </button>\n {/* Hidden checkbox for form-data integration. Follows the\n resolved `currentChecked` so submission picks up the\n correct value in both controlled and uncontrolled modes.\n `aria-hidden` + tabIndex=-1 keep it out of AT and Tab\n order — interaction happens on the visible button above.\n The onChange is a no-op fallback (real state changes\n flow through the button's handler); React requires it\n alongside `checked` to suppress the controlled-input\n warning when the consumer doesn't supply onChange. */}\n <input\n ref={ref}\n type=\"checkbox\"\n id={switchId}\n checked={currentChecked}\n onChange={onChange ?? (() => {})}\n disabled={disabled}\n className=\"sr-only\"\n aria-hidden=\"true\"\n tabIndex={-1}\n {...props}\n />\n </div>\n {(label || helperText) && (\n <div className=\"flex-1\">\n {label && (\n <label\n id={labelId}\n htmlFor={switchId}\n className={cn(\n \"block\",\n getTypographySize(\"bodySmall\"),\n getTypographyWeight(\"label\"),\n error ? \"text-fg-error\" : \"text-fg-primary\",\n disabled ? \"opacity-50\" : \"cursor-pointer\",\n )}\n >\n {label}\n </label>\n )}\n {helperText && (\n <p\n id={helperId}\n className={cn(\n getSpacingClass(\"xs\", \"mt\"),\n getTypographySize(\"bodySmall\"),\n error\n ? \"text-fg-error\"\n : success\n ? \"text-fg-success\"\n : \"text-fg-secondary\",\n )}\n >\n {helperText}\n </p>\n )}\n </div>\n )}\n </div>\n );\n }),\n);\n\nSwitch.displayName = \"Switch\";\n\nexport default Switch;\n"],"names":["Switch","memo","forwardRef","_a","ref","_b","size","label","helperText","error","success","className","disabled","checked","defaultChecked","onChange","id","props","__objRest","isControlled","internalChecked","setInternalChecked","useState","currentChecked","reactId","useId","switchId","labelId","useMemo","helperId","config","getSwitchClasses","focusRingColor","trackClasses","cn","getRadiusClass","getAnimationClass","thumbClasses","jsxs","getSpacingClass","jsx","useCallback","e","next","syntheticEvent","__spreadProps","__spreadValues","getTypographySize","getTypographyWeight"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.js","sources":["../../../../../src/ui/primitives/Tooltip/Tooltip.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n HTMLAttributes,\n ReactNode,\n KeyboardEvent,\n FocusEvent,\n ReactElement,\n} from \"react\";\nimport {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useId,\n cloneElement,\n isValidElement,\n} from \"react\";\nimport { getBorderWidthClass } from \"../../tokens/borders\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getShadowClass } from \"../../tokens/shadows\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { getTypographySize } from \"../../tokens/typography\";\nimport { getZIndexClass } from \"../../tokens/z-index\";\nimport { cn, cva, mergeRefs } from \"../../utils\";\n\nexport interface TooltipProps extends HTMLAttributes<HTMLDivElement> {\n content: string;\n children: ReactNode;\n position?: \"top\" | \"bottom\" | \"left\" | \"right\";\n delay?: number;\n \"aria-label\"?: string;\n /**\n * When true, the tooltip wrapper won't interfere with absolute positioning of children.\n * The wrapper will use `position: static` instead of `position: relative`.\n */\n preservePositioning?: boolean;\n}\n\n/**\n * Tooltip Component\n *\n * A tooltip component for displaying additional information on hover.\n * Follows Atomic Design principles as an Atom component.\n *\n * @example\n * ```tsx\n * <Tooltip content=\"This is a tooltip\">\n * <Button>Hover me</Button>\n * </Tooltip>\n * ```\n */\nconst Tooltip = forwardRef<HTMLDivElement, TooltipProps>(function Tooltip(\n {\n content,\n children,\n position = \"top\",\n delay = 200,\n className = \"\",\n \"aria-label\": _ariaLabel,\n preservePositioning = false,\n ...props\n },\n ref,\n) {\n const [isVisible, setIsVisible] = useState(false);\n const timeoutIdRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const tooltipRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n\n // Stable per-instance ID for the tooltip popup. useId is SSR-safe and\n // stable across renders — the previous Math.random() approach generated\n // a fresh ID on every render, which silently breaks the\n // aria-describedby <-> tooltip id pairing observed by assistive tech\n // across re-renders.\n const tooltipId = `tooltip-${useId()}`;\n\n const handleMouseEnter = () => {\n const id = setTimeout(() => {\n setIsVisible(true);\n }, delay);\n timeoutIdRef.current = id;\n };\n\n const handleMouseLeave = () => {\n if (timeoutIdRef.current) {\n clearTimeout(timeoutIdRef.current);\n timeoutIdRef.current = null;\n }\n setIsVisible(false);\n };\n\n const handleFocus = () => {\n // Show tooltip immediately on focus (no delay for keyboard users)\n setIsVisible(true);\n };\n\n const handleBlur = () => {\n setIsVisible(false);\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n setIsVisible(false);\n triggerRef.current?.blur();\n }\n };\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return () => {\n if (timeoutIdRef.current) {\n clearTimeout(timeoutIdRef.current);\n timeoutIdRef.current = null;\n }\n };\n }, []);\n\n // Close tooltip when clicking outside\n useEffect(() => {\n if (!isVisible) return;\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n tooltipRef.current &&\n !tooltipRef.current.contains(event.target as Node) &&\n triggerRef.current &&\n !triggerRef.current.contains(event.target as Node)\n ) {\n setIsVisible(false);\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, [isVisible]);\n\n // Helper to get arrow border color\n // Uses complete classes that Tailwind can detect\n const getArrowBorderColor = (\n position: \"top\" | \"bottom\" | \"left\" | \"right\",\n ): string => {\n // Arrow follows the tooltip body's surface-inverse color so the\n // triangle's point visually merges into the body.\n const borderMap: Record<\"top\" | \"bottom\" | \"left\" | \"right\", string> = {\n top: \"border-t-surface-inverse\",\n bottom: \"border-b-surface-inverse\",\n left: \"border-l-surface-inverse\",\n right: \"border-r-surface-inverse\",\n };\n return borderMap[position];\n };\n\n // Tooltip variants using CVA\n const tooltipVariants = cva(\n cn(\n \"absolute\",\n getZIndexClass(\"tooltip\"),\n getSpacingClass(\"sm\", \"px\"),\n getSpacingClass(\"xs\", \"py\"),\n getTypographySize(\"caption\"),\n \"text-fg-inverse\",\n \"bg-surface-inverse\",\n getRadiusClass(\"md\"),\n getShadowClass(\"lg\"),\n \"whitespace-nowrap\",\n ),\n {\n variants: {\n position: {\n top: cn(\n \"bottom-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getSpacingClass(\"sm\", \"mb\"),\n ),\n bottom: cn(\n \"top-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getSpacingClass(\"sm\", \"mt\"),\n ),\n left: cn(\n \"right-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getSpacingClass(\"sm\", \"mr\"),\n ),\n right: cn(\n \"left-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getSpacingClass(\"sm\", \"ml\"),\n ),\n },\n },\n defaultVariants: {\n position: \"top\",\n },\n },\n );\n\n const arrowVariants = cva(\n cn(\n \"absolute\",\n \"w-0\",\n \"h-0\",\n getBorderWidthClass(\"thick\"),\n \"border-transparent\",\n ),\n {\n variants: {\n position: {\n top: cn(\n \"top-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getArrowBorderColor(\"top\"),\n ),\n bottom: cn(\n \"bottom-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getArrowBorderColor(\"bottom\"),\n ),\n left: cn(\n \"left-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getArrowBorderColor(\"left\"),\n ),\n right: cn(\n \"right-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getArrowBorderColor(\"right\"),\n ),\n },\n },\n defaultVariants: {\n position: \"top\",\n },\n },\n );\n\n // Clone children to add accessibility props\n const childrenWithProps = isValidElement(children)\n ? (() => {\n const childElement = children as ReactElement<\n HTMLAttributes<HTMLElement> & { ref?: React.Ref<HTMLElement> }\n >;\n const existingProps = childElement.props;\n const existingRef = existingProps.ref;\n\n return cloneElement(childElement, {\n ref: mergeRefs<HTMLElement>(triggerRef, existingRef),\n \"aria-describedby\": isVisible\n ? tooltipId\n : existingProps[\"aria-describedby\"],\n onMouseEnter: (e: React.MouseEvent<HTMLElement>) => {\n handleMouseEnter();\n existingProps.onMouseEnter?.(e);\n },\n onMouseLeave: (e: React.MouseEvent<HTMLElement>) => {\n handleMouseLeave();\n existingProps.onMouseLeave?.(e);\n },\n onFocus: (e: FocusEvent<HTMLElement>) => {\n handleFocus();\n existingProps.onFocus?.(e);\n },\n onBlur: (e: FocusEvent<HTMLElement>) => {\n handleBlur();\n existingProps.onBlur?.(e);\n },\n onKeyDown: (e: KeyboardEvent<HTMLElement>) => {\n handleKeyDown(e);\n existingProps.onKeyDown?.(e);\n },\n } as Partial<typeof existingProps>);\n })()\n : children;\n\n // When preservePositioning is true, use static positioning to avoid interfering\n // with absolute positioned children. The tooltip will still be positioned correctly\n // using absolute positioning relative to the viewport/nearest positioned ancestor.\n const wrapperClassName = preservePositioning\n ? cn(\"static\", \"inline-block\", className)\n : cn(\"relative\", \"inline-block\", className);\n\n return (\n <div ref={ref} className={wrapperClassName} {...props}>\n {childrenWithProps}\n {isVisible && (\n <div\n ref={tooltipRef}\n id={tooltipId}\n className={cn(tooltipVariants({ position }))}\n role=\"tooltip\"\n aria-live=\"polite\"\n >\n {content}\n <div className={cn(arrowVariants({ position }))} aria-hidden=\"true\" />\n </div>\n )}\n </div>\n );\n});\n\nTooltip.displayName = \"Tooltip\";\n\nexport default Tooltip;\n"],"names":["Tooltip","forwardRef","_a","ref","_b","content","children","position","delay","className","_ariaLabel","preservePositioning","props","__objRest","isVisible","setIsVisible","useState","timeoutIdRef","useRef","tooltipRef","triggerRef","tooltipId","useId","handleMouseEnter","id","handleMouseLeave","handleFocus","handleBlur","handleKeyDown","e","useEffect","handleClickOutside","event","getArrowBorderColor","tooltipVariants","cva","cn","getZIndexClass","getSpacingClass","getTypographySize","getRadiusClass","getShadowClass","arrowVariants","getBorderWidthClass","childrenWithProps","isValidElement","childElement","existingProps","existingRef","cloneElement","mergeRefs","wrapperClassName","__spreadProps","__spreadValues","jsxs","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"Tooltip.js","sources":["../../../../../src/ui/primitives/Tooltip/Tooltip.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n HTMLAttributes,\n ReactNode,\n KeyboardEvent,\n FocusEvent,\n ReactElement,\n} from \"react\";\nimport {\n forwardRef,\n useState,\n useRef,\n useEffect,\n useId,\n cloneElement,\n isValidElement,\n} from \"react\";\nimport { getBorderWidthClass } from \"../../tokens/borders\";\nimport { getRadiusClass } from \"../../tokens/radius\";\nimport { getShadowClass } from \"../../tokens/shadows\";\nimport { getSpacingClass } from \"../../tokens/spacing\";\nimport { getTypographySize } from \"../../tokens/typography\";\nimport { getZIndexClass } from \"../../tokens/z-index\";\nimport { cn, cva, mergeRefs } from \"../../utils\";\n\nexport interface TooltipProps extends HTMLAttributes<HTMLDivElement> {\n content: string;\n children: ReactNode;\n position?: \"top\" | \"bottom\" | \"left\" | \"right\";\n delay?: number;\n \"aria-label\"?: string;\n /**\n * When true, the tooltip wrapper won't interfere with absolute positioning of children.\n * The wrapper will use `position: static` instead of `position: relative`.\n */\n preservePositioning?: boolean;\n}\n\n/**\n * Tooltip Component\n *\n * A tooltip component for displaying additional information on hover.\n *\n * @example\n * ```tsx\n * <Tooltip content=\"This is a tooltip\">\n * <Button>Hover me</Button>\n * </Tooltip>\n * ```\n */\nconst Tooltip = forwardRef<HTMLDivElement, TooltipProps>(function Tooltip(\n {\n content,\n children,\n position = \"top\",\n delay = 200,\n className = \"\",\n \"aria-label\": _ariaLabel,\n preservePositioning = false,\n ...props\n },\n ref,\n) {\n const [isVisible, setIsVisible] = useState(false);\n const timeoutIdRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const tooltipRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLElement | null>(null);\n\n // Stable per-instance ID for the tooltip popup. useId is SSR-safe and\n // stable across renders — the previous Math.random() approach generated\n // a fresh ID on every render, which silently breaks the\n // aria-describedby <-> tooltip id pairing observed by assistive tech\n // across re-renders.\n const tooltipId = `tooltip-${useId()}`;\n\n const handleMouseEnter = () => {\n const id = setTimeout(() => {\n setIsVisible(true);\n }, delay);\n timeoutIdRef.current = id;\n };\n\n const handleMouseLeave = () => {\n if (timeoutIdRef.current) {\n clearTimeout(timeoutIdRef.current);\n timeoutIdRef.current = null;\n }\n setIsVisible(false);\n };\n\n const handleFocus = () => {\n // Show tooltip immediately on focus (no delay for keyboard users)\n setIsVisible(true);\n };\n\n const handleBlur = () => {\n setIsVisible(false);\n };\n\n const handleKeyDown = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n setIsVisible(false);\n triggerRef.current?.blur();\n }\n };\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return () => {\n if (timeoutIdRef.current) {\n clearTimeout(timeoutIdRef.current);\n timeoutIdRef.current = null;\n }\n };\n }, []);\n\n // Close tooltip when clicking outside\n useEffect(() => {\n if (!isVisible) return;\n\n const handleClickOutside = (event: MouseEvent) => {\n if (\n tooltipRef.current &&\n !tooltipRef.current.contains(event.target as Node) &&\n triggerRef.current &&\n !triggerRef.current.contains(event.target as Node)\n ) {\n setIsVisible(false);\n }\n };\n\n document.addEventListener(\"mousedown\", handleClickOutside);\n return () => {\n document.removeEventListener(\"mousedown\", handleClickOutside);\n };\n }, [isVisible]);\n\n // Helper to get arrow border color\n // Uses complete classes that Tailwind can detect\n const getArrowBorderColor = (\n position: \"top\" | \"bottom\" | \"left\" | \"right\",\n ): string => {\n // Arrow follows the tooltip body's surface-inverse color so the\n // triangle's point visually merges into the body.\n const borderMap: Record<\"top\" | \"bottom\" | \"left\" | \"right\", string> = {\n top: \"border-t-surface-inverse\",\n bottom: \"border-b-surface-inverse\",\n left: \"border-l-surface-inverse\",\n right: \"border-r-surface-inverse\",\n };\n return borderMap[position];\n };\n\n // Tooltip variants using CVA\n const tooltipVariants = cva(\n cn(\n \"absolute\",\n getZIndexClass(\"tooltip\"),\n getSpacingClass(\"sm\", \"px\"),\n getSpacingClass(\"xs\", \"py\"),\n getTypographySize(\"caption\"),\n \"text-fg-inverse\",\n \"bg-surface-inverse\",\n getRadiusClass(\"md\"),\n getShadowClass(\"lg\"),\n \"whitespace-nowrap\",\n ),\n {\n variants: {\n position: {\n top: cn(\n \"bottom-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getSpacingClass(\"sm\", \"mb\"),\n ),\n bottom: cn(\n \"top-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getSpacingClass(\"sm\", \"mt\"),\n ),\n left: cn(\n \"right-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getSpacingClass(\"sm\", \"mr\"),\n ),\n right: cn(\n \"left-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getSpacingClass(\"sm\", \"ml\"),\n ),\n },\n },\n defaultVariants: {\n position: \"top\",\n },\n },\n );\n\n const arrowVariants = cva(\n cn(\n \"absolute\",\n \"w-0\",\n \"h-0\",\n getBorderWidthClass(\"thick\"),\n \"border-transparent\",\n ),\n {\n variants: {\n position: {\n top: cn(\n \"top-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getArrowBorderColor(\"top\"),\n ),\n bottom: cn(\n \"bottom-full\",\n \"left-1/2\",\n \"transform\",\n \"-translate-x-1/2\",\n getArrowBorderColor(\"bottom\"),\n ),\n left: cn(\n \"left-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getArrowBorderColor(\"left\"),\n ),\n right: cn(\n \"right-full\",\n \"top-1/2\",\n \"transform\",\n \"-translate-y-1/2\",\n getArrowBorderColor(\"right\"),\n ),\n },\n },\n defaultVariants: {\n position: \"top\",\n },\n },\n );\n\n // Clone children to add accessibility props\n const childrenWithProps = isValidElement(children)\n ? (() => {\n const childElement = children as ReactElement<\n HTMLAttributes<HTMLElement> & { ref?: React.Ref<HTMLElement> }\n >;\n const existingProps = childElement.props;\n const existingRef = existingProps.ref;\n\n return cloneElement(childElement, {\n ref: mergeRefs<HTMLElement>(triggerRef, existingRef),\n \"aria-describedby\": isVisible\n ? tooltipId\n : existingProps[\"aria-describedby\"],\n onMouseEnter: (e: React.MouseEvent<HTMLElement>) => {\n handleMouseEnter();\n existingProps.onMouseEnter?.(e);\n },\n onMouseLeave: (e: React.MouseEvent<HTMLElement>) => {\n handleMouseLeave();\n existingProps.onMouseLeave?.(e);\n },\n onFocus: (e: FocusEvent<HTMLElement>) => {\n handleFocus();\n existingProps.onFocus?.(e);\n },\n onBlur: (e: FocusEvent<HTMLElement>) => {\n handleBlur();\n existingProps.onBlur?.(e);\n },\n onKeyDown: (e: KeyboardEvent<HTMLElement>) => {\n handleKeyDown(e);\n existingProps.onKeyDown?.(e);\n },\n } as Partial<typeof existingProps>);\n })()\n : children;\n\n // When preservePositioning is true, use static positioning to avoid interfering\n // with absolute positioned children. The tooltip will still be positioned correctly\n // using absolute positioning relative to the viewport/nearest positioned ancestor.\n const wrapperClassName = preservePositioning\n ? cn(\"static\", \"inline-block\", className)\n : cn(\"relative\", \"inline-block\", className);\n\n return (\n <div ref={ref} className={wrapperClassName} {...props}>\n {childrenWithProps}\n {isVisible && (\n <div\n ref={tooltipRef}\n id={tooltipId}\n className={cn(tooltipVariants({ position }))}\n role=\"tooltip\"\n aria-live=\"polite\"\n >\n {content}\n <div className={cn(arrowVariants({ position }))} aria-hidden=\"true\" />\n </div>\n )}\n </div>\n );\n});\n\nTooltip.displayName = \"Tooltip\";\n\nexport default Tooltip;\n"],"names":["Tooltip","forwardRef","_a","ref","_b","content","children","position","delay","className","_ariaLabel","preservePositioning","props","__objRest","isVisible","setIsVisible","useState","timeoutIdRef","useRef","tooltipRef","triggerRef","tooltipId","useId","handleMouseEnter","id","handleMouseLeave","handleFocus","handleBlur","handleKeyDown","e","useEffect","handleClickOutside","event","getArrowBorderColor","tooltipVariants","cva","cn","getZIndexClass","getSpacingClass","getTypographySize","getRadiusClass","getShadowClass","arrowVariants","getBorderWidthClass","childrenWithProps","isValidElement","childElement","existingProps","existingRef","cloneElement","mergeRefs","wrapperClassName","__spreadProps","__spreadValues","jsxs","jsx"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"DialogContext.js","sources":["../../../../src/ui/providers/DialogContext.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\n\nexport interface DialogContextValue {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n onClose: () => void;\n titleId?: string;\n descriptionId?: string;\n}\n\nexport const DialogContext = createContext<DialogContextValue | undefined>(\n undefined,\n);\n\nexport function useDialogContext(): DialogContextValue {\n const context = useContext(DialogContext);\n if (!context) {\n throw new Error(\"Dialog components must be used within a Dialog component\");\n }\n return context;\n}\n\nexport function useDialogContextOptional(): DialogContextValue | undefined {\n return useContext(DialogContext);\n}\n"],"names":["DialogContext","createContext","useDialogContext","context","useContext","useDialogContextOptional"],"mappings":";;AAYO,MAAMA,IAAgBC;AAAA,EAC3B;AACF;AAEO,SAASC,IAAuC;AACrD,QAAMC,IAAUC,EAAWJ,CAAa;AACxC,MAAI,CAACG;AACH,UAAM,IAAI,MAAM,0DAA0D;AAE5E,SAAOA;AACT;AAEO,SAASE,IAA2D;AACzE,SAAOD,EAAWJ,CAAa;AACjC;"}
1
+ {"version":3,"file":"DialogContext.js","sources":["../../../../src/ui/providers/DialogContext.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext } from \"react\";\n\nexport interface DialogContextValue {\n isOpen: boolean;\n onOpenChange: (open: boolean) => void;\n onClose: () => void;\n titleId?: string;\n descriptionId?: string;\n /** True while at least one Dialog.Title is mounted. */\n hasTitle: boolean;\n /** True while at least one Dialog.Description is mounted. */\n hasDescription: boolean;\n /** Register a mounted Title; returns an unregister cleanup. */\n registerTitle: () => () => void;\n /** Register a mounted Description; returns an unregister cleanup. */\n registerDescription: () => () => void;\n}\n\nexport const DialogContext = createContext<DialogContextValue | undefined>(\n undefined,\n);\n\nexport function useDialogContext(): DialogContextValue {\n const context = useContext(DialogContext);\n if (!context) {\n throw new Error(\"Dialog components must be used within a Dialog component\");\n }\n return context;\n}\n\nexport function useDialogContextOptional(): DialogContextValue | undefined {\n return useContext(DialogContext);\n}\n"],"names":["DialogContext","createContext","useDialogContext","context","useContext","useDialogContextOptional"],"mappings":";;AAoBO,MAAMA,IAAgBC;AAAA,EAC3B;AACF;AAEO,SAASC,IAAuC;AACrD,QAAMC,IAAUC,EAAWJ,CAAa;AACxC,MAAI,CAACG;AACH,UAAM,IAAI,MAAM,0DAA0D;AAE5E,SAAOA;AACT;AAEO,SAASE,IAA2D;AACzE,SAAOD,EAAWJ,CAAa;AACjC;"}
@@ -1,32 +1,36 @@
1
1
  "use client";
2
- import { jsx as n } from "react/jsx-runtime";
3
- import { useState as v, useEffect as y } from "react";
4
- import { DialogContext as a } from "./DialogContext.js";
5
- import { useFocusRestore as p } from "../hooks/useFocusRestore.js";
6
- function P({
7
- children: i,
2
+ import { jsx as C } from "react/jsx-runtime";
3
+ import { useState as r, useCallback as l, useEffect as T } from "react";
4
+ import { DialogContext as w } from "./DialogContext.js";
5
+ import { useFocusRestore as P } from "../hooks/useFocusRestore.js";
6
+ function F({
7
+ children: u,
8
8
  open: e,
9
- defaultOpen: l = !1,
10
- onOpenChange: t,
11
- titleId: f,
12
- descriptionId: u
9
+ defaultOpen: f = !1,
10
+ onOpenChange: s,
11
+ titleId: d,
12
+ descriptionId: m
13
13
  }) {
14
- const [c, d] = v(l), o = e !== void 0 ? e : c, s = (r) => {
15
- e === void 0 && d(r), t == null || t(r);
14
+ const [a, p] = r(f), [v, i] = r(0), [y, n] = r(0), D = l(() => (i((t) => t + 1), () => i((t) => t - 1)), []), b = l(() => (n((t) => t + 1), () => n((t) => t - 1)), []), o = e !== void 0 ? e : a, c = (t) => {
15
+ e === void 0 && p(t), s == null || s(t);
16
16
  };
17
- p(o), y(() => (o ? document.body.style.overflow = "hidden" : document.body.style.overflow = "", () => {
17
+ P(o), T(() => (o ? document.body.style.overflow = "hidden" : document.body.style.overflow = "", () => {
18
18
  document.body.style.overflow = "";
19
19
  }), [o]);
20
- const m = {
20
+ const x = {
21
21
  isOpen: o,
22
- onOpenChange: s,
23
- onClose: () => s(!1),
24
- titleId: f,
25
- descriptionId: u
22
+ onOpenChange: c,
23
+ onClose: () => c(!1),
24
+ titleId: d,
25
+ descriptionId: m,
26
+ hasTitle: v > 0,
27
+ hasDescription: y > 0,
28
+ registerTitle: D,
29
+ registerDescription: b
26
30
  };
27
- return /* @__PURE__ */ n(a.Provider, { value: m, children: i });
31
+ return /* @__PURE__ */ C(w.Provider, { value: x, children: u });
28
32
  }
29
33
  export {
30
- P as DialogProvider
34
+ F as DialogProvider
31
35
  };
32
36
  //# sourceMappingURL=DialogProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DialogProvider.js","sources":["../../../../src/ui/providers/DialogProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, type ReactNode } from \"react\";\nimport { DialogContext, type DialogContextValue } from \"./DialogContext\";\nimport { useFocusRestore } from \"../hooks/useFocusRestore\";\n\nexport interface DialogProviderProps {\n children: ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n titleId?: string;\n descriptionId?: string;\n}\n\nexport function DialogProvider({\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n titleId,\n descriptionId,\n}: DialogProviderProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n\n // Use controlled or uncontrolled state\n const isOpen =\n controlledOpen !== undefined ? controlledOpen : uncontrolledOpen;\n const setIsOpen = (newOpen: boolean) => {\n if (controlledOpen === undefined) {\n setUncontrolledOpen(newOpen);\n }\n onOpenChange?.(newOpen);\n };\n\n // Modal focus restore — consumed from the shared hook introduced in\n // Phase 3 PR 1. Replaces an inline `previousActiveElement` ref +\n // `setTimeout(0)` block that this hook now owns. Timing identity is\n // preserved (the hook uses setTimeout(0)), so Dialog.test.tsx's\n // restore tests do not need to change.\n useFocusRestore(isOpen);\n\n // Prevent body scroll when dialog is open\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = \"hidden\";\n } else {\n document.body.style.overflow = \"\";\n }\n return () => {\n document.body.style.overflow = \"\";\n };\n }, [isOpen]);\n\n const contextValue: DialogContextValue = {\n isOpen,\n onOpenChange: setIsOpen,\n onClose: () => setIsOpen(false),\n titleId,\n descriptionId,\n };\n\n return (\n <DialogContext.Provider value={contextValue}>\n {children}\n </DialogContext.Provider>\n );\n}\n"],"names":["DialogProvider","children","controlledOpen","defaultOpen","onOpenChange","titleId","descriptionId","uncontrolledOpen","setUncontrolledOpen","useState","isOpen","setIsOpen","newOpen","useFocusRestore","useEffect","contextValue","DialogContext"],"mappings":";;;;;AAeO,SAASA,EAAe;AAAA,EAC7B,UAAAC;AAAA,EACA,MAAMC;AAAA,EACN,aAAAC,IAAc;AAAA,EACd,cAAAC;AAAA,EACA,SAAAC;AAAA,EACA,eAAAC;AACF,GAAwB;AACtB,QAAM,CAACC,GAAkBC,CAAmB,IAAIC,EAASN,CAAW,GAG9DO,IACJR,MAAmB,SAAYA,IAAiBK,GAC5CI,IAAY,CAACC,MAAqB;AACtC,IAAIV,MAAmB,UACrBM,EAAoBI,CAAO,GAE7BR,KAAA,QAAAA,EAAeQ;AAAA,EACjB;AAOA,EAAAC,EAAgBH,CAAM,GAGtBI,EAAU,OACJJ,IACF,SAAS,KAAK,MAAM,WAAW,WAE/B,SAAS,KAAK,MAAM,WAAW,IAE1B,MAAM;AACX,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,IACC,CAACA,CAAM,CAAC;AAEX,QAAMK,IAAmC;AAAA,IACvC,QAAAL;AAAA,IACA,cAAcC;AAAA,IACd,SAAS,MAAMA,EAAU,EAAK;AAAA,IAC9B,SAAAN;AAAA,IACA,eAAAC;AAAA,EAAA;AAGF,2BACGU,EAAc,UAAd,EAAuB,OAAOD,GAC5B,UAAAd,GACH;AAEJ;"}
1
+ {"version":3,"file":"DialogProvider.js","sources":["../../../../src/ui/providers/DialogProvider.tsx"],"sourcesContent":["\"use client\";\n\nimport { useState, useEffect, useCallback, type ReactNode } from \"react\";\nimport { DialogContext, type DialogContextValue } from \"./DialogContext\";\nimport { useFocusRestore } from \"../hooks/useFocusRestore\";\n\nexport interface DialogProviderProps {\n children: ReactNode;\n open?: boolean;\n defaultOpen?: boolean;\n onOpenChange?: (open: boolean) => void;\n titleId?: string;\n descriptionId?: string;\n}\n\nexport function DialogProvider({\n children,\n open: controlledOpen,\n defaultOpen = false,\n onOpenChange,\n titleId,\n descriptionId,\n}: DialogProviderProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = useState(defaultOpen);\n\n // Presence tracking so DialogContent only emits aria-labelledby /\n // aria-describedby when a Title / Description is actually mounted.\n // Without this the dialog always pointed those IDREFs at ids that\n // only exist when the corresponding subcomponent is rendered — a\n // dangling reference for every title-only (or bare) dialog.\n const [titleCount, setTitleCount] = useState(0);\n const [descriptionCount, setDescriptionCount] = useState(0);\n\n const registerTitle = useCallback(() => {\n setTitleCount((c) => c + 1);\n return () => setTitleCount((c) => c - 1);\n }, []);\n const registerDescription = useCallback(() => {\n setDescriptionCount((c) => c + 1);\n return () => setDescriptionCount((c) => c - 1);\n }, []);\n\n // Use controlled or uncontrolled state\n const isOpen =\n controlledOpen !== undefined ? controlledOpen : uncontrolledOpen;\n const setIsOpen = (newOpen: boolean) => {\n if (controlledOpen === undefined) {\n setUncontrolledOpen(newOpen);\n }\n onOpenChange?.(newOpen);\n };\n\n // Modal focus restore — consumed from the shared hook introduced in\n // Phase 3 PR 1. Replaces an inline `previousActiveElement` ref +\n // `setTimeout(0)` block that this hook now owns. Timing identity is\n // preserved (the hook uses setTimeout(0)), so Dialog.test.tsx's\n // restore tests do not need to change.\n useFocusRestore(isOpen);\n\n // Prevent body scroll when dialog is open\n useEffect(() => {\n if (isOpen) {\n document.body.style.overflow = \"hidden\";\n } else {\n document.body.style.overflow = \"\";\n }\n return () => {\n document.body.style.overflow = \"\";\n };\n }, [isOpen]);\n\n const contextValue: DialogContextValue = {\n isOpen,\n onOpenChange: setIsOpen,\n onClose: () => setIsOpen(false),\n titleId,\n descriptionId,\n hasTitle: titleCount > 0,\n hasDescription: descriptionCount > 0,\n registerTitle,\n registerDescription,\n };\n\n return (\n <DialogContext.Provider value={contextValue}>\n {children}\n </DialogContext.Provider>\n );\n}\n"],"names":["DialogProvider","children","controlledOpen","defaultOpen","onOpenChange","titleId","descriptionId","uncontrolledOpen","setUncontrolledOpen","useState","titleCount","setTitleCount","descriptionCount","setDescriptionCount","registerTitle","useCallback","c","registerDescription","isOpen","setIsOpen","newOpen","useFocusRestore","useEffect","contextValue","DialogContext"],"mappings":";;;;;AAeO,SAASA,EAAe;AAAA,EAC7B,UAAAC;AAAA,EACA,MAAMC;AAAA,EACN,aAAAC,IAAc;AAAA,EACd,cAAAC;AAAA,EACA,SAAAC;AAAA,EACA,eAAAC;AACF,GAAwB;AACtB,QAAM,CAACC,GAAkBC,CAAmB,IAAIC,EAASN,CAAW,GAO9D,CAACO,GAAYC,CAAa,IAAIF,EAAS,CAAC,GACxC,CAACG,GAAkBC,CAAmB,IAAIJ,EAAS,CAAC,GAEpDK,IAAgBC,EAAY,OAChCJ,EAAc,CAACK,MAAMA,IAAI,CAAC,GACnB,MAAML,EAAc,CAACK,MAAMA,IAAI,CAAC,IACtC,CAAA,CAAE,GACCC,IAAsBF,EAAY,OACtCF,EAAoB,CAACG,MAAMA,IAAI,CAAC,GACzB,MAAMH,EAAoB,CAACG,MAAMA,IAAI,CAAC,IAC5C,CAAA,CAAE,GAGCE,IACJhB,MAAmB,SAAYA,IAAiBK,GAC5CY,IAAY,CAACC,MAAqB;AACtC,IAAIlB,MAAmB,UACrBM,EAAoBY,CAAO,GAE7BhB,KAAA,QAAAA,EAAegB;AAAA,EACjB;AAOA,EAAAC,EAAgBH,CAAM,GAGtBI,EAAU,OACJJ,IACF,SAAS,KAAK,MAAM,WAAW,WAE/B,SAAS,KAAK,MAAM,WAAW,IAE1B,MAAM;AACX,aAAS,KAAK,MAAM,WAAW;AAAA,EACjC,IACC,CAACA,CAAM,CAAC;AAEX,QAAMK,IAAmC;AAAA,IACvC,QAAAL;AAAA,IACA,cAAcC;AAAA,IACd,SAAS,MAAMA,EAAU,EAAK;AAAA,IAC9B,SAAAd;AAAA,IACA,eAAAC;AAAA,IACA,UAAUI,IAAa;AAAA,IACvB,gBAAgBE,IAAmB;AAAA,IACnC,eAAAE;AAAA,IACA,qBAAAG;AAAA,EAAA;AAGF,2BACGO,EAAc,UAAd,EAAuB,OAAOD,GAC5B,UAAAtB,GACH;AAEJ;"}