@puzzle-ui/ui 0.4.0 → 0.5.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 (156) hide show
  1. package/README.md +3 -4
  2. package/dist/components/actions/button/button.css +5 -2
  3. package/dist/components/actions/button-group/button-group.css +16 -17
  4. package/dist/components/data-display/badge/badge.css +15 -2
  5. package/dist/components/data-display/badge/index.cjs +13 -2
  6. package/dist/components/data-display/badge/index.cjs.map +1 -1
  7. package/dist/components/data-display/badge/index.d.cts +7 -2
  8. package/dist/components/data-display/badge/index.d.ts +7 -2
  9. package/dist/components/data-display/badge/index.js +13 -2
  10. package/dist/components/data-display/badge/index.js.map +1 -1
  11. package/dist/components/data-display/rating/index.cjs +84 -0
  12. package/dist/components/data-display/rating/index.cjs.map +1 -0
  13. package/dist/components/data-display/rating/index.d.cts +3 -0
  14. package/dist/components/data-display/rating/index.d.ts +3 -0
  15. package/dist/components/data-display/rating/index.js +84 -0
  16. package/dist/components/data-display/rating/index.js.map +1 -0
  17. package/dist/components/data-display/rating/rating.css +72 -0
  18. package/dist/components/data-display/rating/rating.types.d.cts +15 -0
  19. package/dist/components/data-display/rating/rating.types.d.ts +15 -0
  20. package/dist/components/data-display/rating/rating.utils.cjs +27 -0
  21. package/dist/components/data-display/rating/rating.utils.cjs.map +1 -0
  22. package/dist/components/data-display/rating/rating.utils.js +25 -0
  23. package/dist/components/data-display/rating/rating.utils.js.map +1 -0
  24. package/dist/components/forms/checkbox/checkbox.css +2 -10
  25. package/dist/components/forms/input-group/input-group.d.cts +4 -2
  26. package/dist/components/forms/input-group/input-group.d.ts +4 -2
  27. package/dist/components/forms/radio-group/index.d.cts +2 -1
  28. package/dist/components/forms/radio-group/index.d.ts +2 -1
  29. package/dist/components/forms/stepper/index.d.cts +4 -2
  30. package/dist/components/forms/stepper/index.d.ts +4 -2
  31. package/dist/components/forms/time-picker/index.cjs +108 -0
  32. package/dist/components/forms/time-picker/index.cjs.map +1 -0
  33. package/dist/components/forms/time-picker/index.d.cts +3 -0
  34. package/dist/components/forms/time-picker/index.d.ts +3 -0
  35. package/dist/components/forms/time-picker/index.js +108 -0
  36. package/dist/components/forms/time-picker/index.js.map +1 -0
  37. package/dist/components/forms/time-picker/time-picker.css +166 -0
  38. package/dist/components/forms/time-picker/time-picker.types.d.cts +34 -0
  39. package/dist/components/forms/time-picker/time-picker.types.d.ts +34 -0
  40. package/dist/components/forms/time-picker/time-picker.utils.cjs +25 -0
  41. package/dist/components/forms/time-picker/time-picker.utils.cjs.map +1 -0
  42. package/dist/components/forms/time-picker/time-picker.utils.js +24 -0
  43. package/dist/components/forms/time-picker/time-picker.utils.js.map +1 -0
  44. package/dist/components/forms/token-input/index.cjs +189 -0
  45. package/dist/components/forms/token-input/index.cjs.map +1 -0
  46. package/dist/components/forms/token-input/index.d.cts +3 -0
  47. package/dist/components/forms/token-input/index.d.ts +3 -0
  48. package/dist/components/forms/token-input/index.js +189 -0
  49. package/dist/components/forms/token-input/index.js.map +1 -0
  50. package/dist/components/forms/token-input/token-input.css +145 -0
  51. package/dist/components/forms/token-input/token-input.types.d.cts +48 -0
  52. package/dist/components/forms/token-input/token-input.types.d.ts +48 -0
  53. package/dist/components/forms/token-input/token-input.utils.cjs +30 -0
  54. package/dist/components/forms/token-input/token-input.utils.cjs.map +1 -0
  55. package/dist/components/forms/token-input/token-input.utils.js +24 -0
  56. package/dist/components/forms/token-input/token-input.utils.js.map +1 -0
  57. package/dist/components/layout/aspect-ratio/aspect-ratio.css +14 -0
  58. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs +11 -0
  59. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.cjs.map +1 -0
  60. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js +11 -0
  61. package/dist/components/layout/aspect-ratio/aspect-ratio.utils.js.map +1 -0
  62. package/dist/components/layout/aspect-ratio/index.cjs +16 -0
  63. package/dist/components/layout/aspect-ratio/index.cjs.map +1 -0
  64. package/dist/components/layout/aspect-ratio/index.d.cts +11 -0
  65. package/dist/components/layout/aspect-ratio/index.d.ts +11 -0
  66. package/dist/components/layout/aspect-ratio/index.js +16 -0
  67. package/dist/components/layout/aspect-ratio/index.js.map +1 -0
  68. package/dist/components/layout/container/container.css +1 -0
  69. package/dist/components/layout/page-layout/page-layout.css +1 -0
  70. package/dist/components/layout/scroll-area/index.cjs +27 -0
  71. package/dist/components/layout/scroll-area/index.cjs.map +1 -0
  72. package/dist/components/layout/scroll-area/index.d.cts +15 -0
  73. package/dist/components/layout/scroll-area/index.d.ts +15 -0
  74. package/dist/components/layout/scroll-area/index.js +27 -0
  75. package/dist/components/layout/scroll-area/index.js.map +1 -0
  76. package/dist/components/layout/scroll-area/scroll-area.css +25 -0
  77. package/dist/components/layout/scroll-area/scroll-area.utils.cjs +8 -0
  78. package/dist/components/layout/scroll-area/scroll-area.utils.cjs.map +1 -0
  79. package/dist/components/layout/scroll-area/scroll-area.utils.d.cts +2 -0
  80. package/dist/components/layout/scroll-area/scroll-area.utils.d.ts +2 -0
  81. package/dist/components/layout/scroll-area/scroll-area.utils.js +8 -0
  82. package/dist/components/layout/scroll-area/scroll-area.utils.js.map +1 -0
  83. package/dist/components/layout/section/index.cjs +10 -4
  84. package/dist/components/layout/section/index.cjs.map +1 -1
  85. package/dist/components/layout/section/index.d.cts +1 -1
  86. package/dist/components/layout/section/index.d.ts +1 -1
  87. package/dist/components/layout/section/index.js +11 -5
  88. package/dist/components/layout/section/index.js.map +1 -1
  89. package/dist/components/layout/section/section.css +9 -3
  90. package/dist/components/layout/section/types.d.cts +5 -5
  91. package/dist/components/layout/section/types.d.ts +5 -5
  92. package/dist/components/layout/separator/index.cjs +18 -0
  93. package/dist/components/layout/separator/index.cjs.map +1 -0
  94. package/dist/components/layout/separator/index.d.cts +17 -0
  95. package/dist/components/layout/separator/index.d.ts +17 -0
  96. package/dist/components/layout/separator/index.js +18 -0
  97. package/dist/components/layout/separator/index.js.map +1 -0
  98. package/dist/components/layout/separator/separator.css +15 -0
  99. package/dist/components/layout/separator/separator.utils.cjs +11 -0
  100. package/dist/components/layout/separator/separator.utils.cjs.map +1 -0
  101. package/dist/components/layout/separator/separator.utils.d.cts +2 -0
  102. package/dist/components/layout/separator/separator.utils.d.ts +2 -0
  103. package/dist/components/layout/separator/separator.utils.js +11 -0
  104. package/dist/components/layout/separator/separator.utils.js.map +1 -0
  105. package/dist/components/layout/stack/index.cjs +18 -2
  106. package/dist/components/layout/stack/index.cjs.map +1 -1
  107. package/dist/components/layout/stack/index.d.cts +8 -6
  108. package/dist/components/layout/stack/index.d.ts +8 -6
  109. package/dist/components/layout/stack/index.js +18 -2
  110. package/dist/components/layout/stack/index.js.map +1 -1
  111. package/dist/components/layout/stack/stack.css +118 -138
  112. package/dist/components/navigation/carousel/index.cjs +4 -1
  113. package/dist/components/navigation/carousel/index.cjs.map +1 -1
  114. package/dist/components/navigation/carousel/index.js +4 -1
  115. package/dist/components/navigation/carousel/index.js.map +1 -1
  116. package/dist/components/navigation/tabs/index.d.cts +3 -2
  117. package/dist/components/navigation/tabs/index.d.ts +3 -2
  118. package/dist/components/overlays/context-menu/context-menu.css +151 -0
  119. package/dist/components/overlays/context-menu/context-menu.types.d.cts +69 -0
  120. package/dist/components/overlays/context-menu/context-menu.types.d.ts +69 -0
  121. package/dist/components/overlays/context-menu/context-menu.utils.cjs +46 -0
  122. package/dist/components/overlays/context-menu/context-menu.utils.cjs.map +1 -0
  123. package/dist/components/overlays/context-menu/context-menu.utils.js +40 -0
  124. package/dist/components/overlays/context-menu/context-menu.utils.js.map +1 -0
  125. package/dist/components/overlays/context-menu/index.cjs +830 -0
  126. package/dist/components/overlays/context-menu/index.cjs.map +1 -0
  127. package/dist/components/overlays/context-menu/index.d.cts +42 -0
  128. package/dist/components/overlays/context-menu/index.d.ts +42 -0
  129. package/dist/components/overlays/context-menu/index.js +818 -0
  130. package/dist/components/overlays/context-menu/index.js.map +1 -0
  131. package/dist/components/typography/heading.cjs +6 -2
  132. package/dist/components/typography/heading.cjs.map +1 -1
  133. package/dist/components/typography/heading.d.cts +3 -2
  134. package/dist/components/typography/heading.d.ts +3 -2
  135. package/dist/components/typography/heading.js +6 -2
  136. package/dist/components/typography/heading.js.map +1 -1
  137. package/dist/components/typography/text.cjs +6 -2
  138. package/dist/components/typography/text.cjs.map +1 -1
  139. package/dist/components/typography/text.d.cts +3 -2
  140. package/dist/components/typography/text.d.ts +3 -2
  141. package/dist/components/typography/text.js +6 -2
  142. package/dist/components/typography/text.js.map +1 -1
  143. package/dist/components/utilities/preview/index.cjs +88 -20
  144. package/dist/components/utilities/preview/index.cjs.map +1 -1
  145. package/dist/components/utilities/preview/index.d.cts +6 -2
  146. package/dist/components/utilities/preview/index.d.ts +6 -2
  147. package/dist/components/utilities/preview/index.js +88 -20
  148. package/dist/components/utilities/preview/index.js.map +1 -1
  149. package/dist/components/utilities/preview/preview.css +26 -11
  150. package/dist/components/utilities/transition/index.d.cts +1 -1
  151. package/dist/components/utilities/transition/index.d.ts +1 -1
  152. package/dist/index.cjs +123 -97
  153. package/dist/index.d.cts +15 -2
  154. package/dist/index.d.ts +15 -2
  155. package/dist/index.js +8 -1
  156. package/package.json +6 -6
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../../src/components/overlays/context-menu/index.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n Children,\n cloneElement,\n createContext,\n forwardRef,\n Fragment,\n isValidElement,\n useCallback,\n useContext,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type KeyboardEvent,\n type MouseEvent,\n type MutableRefObject,\n type PointerEvent,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\n\nimport { cn } from \"@puzzle-ui/core\";\n\nimport {\n Popout,\n usePopoutPositioned,\n type PopoutTriggerProps,\n} from \"../popout\";\n\nimport {\n findMenuItemIndexByText,\n findNextMenuItemIndex,\n focusElement,\n getEnabledMenuItems,\n getMenuItemText,\n setRef,\n} from \"./context-menu.utils\";\n\nimport type {\n ContextMenuCheckboxItemProps,\n ContextMenuContentProps,\n ContextMenuGroupProps,\n ContextMenuItemProps,\n ContextMenuLabelProps,\n ContextMenuProps,\n ContextMenuRadioGroupProps,\n ContextMenuRadioItemProps,\n ContextMenuSeparatorProps,\n ContextMenuSubContentProps,\n ContextMenuSubProps,\n ContextMenuSubTriggerProps,\n ContextMenuTriggerProps,\n} from \"./context-menu.types\";\n\nimport \"./context-menu.css\";\n\ntype ContextMenuPoint = {\n x: number;\n y: number;\n};\n\ntype FocusPosition = \"first\" | \"last\";\n\ntype ContextMenuContextValue = {\n open: boolean;\n disabled: boolean;\n triggerId: string;\n contentId: string;\n triggerRef: RefObject<HTMLElement | null>;\n focusPositionRef: RefObject<FocusPosition>;\n openAt: (point: ContextMenuPoint, position?: FocusPosition) => void;\n changeOpen: (open: boolean) => void;\n close: (restoreFocus?: boolean) => void;\n};\n\ntype RadioGroupContextValue = {\n value: string | undefined;\n setValue: (value: string) => void;\n};\n\ntype SubContextValue = {\n open: boolean;\n setOpen: (open: boolean) => void;\n triggerId: string;\n contentId: string;\n triggerRef: MutableRefObject<HTMLButtonElement | null>;\n close: (restoreFocus?: boolean) => void;\n};\n\nconst ContextMenuContext = createContext<ContextMenuContextValue | null>(null);\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null);\nconst SubContext = createContext<SubContextValue | null>(null);\n\nconst useContextMenuContext = () => {\n const context = useContext(ContextMenuContext);\n\n if (!context) {\n throw new Error(\n \"ContextMenu components must be rendered inside ContextMenu.\",\n );\n }\n\n return context;\n};\n\nconst useRadioGroupContext = () => {\n const context = useContext(RadioGroupContext);\n\n if (!context) {\n throw new Error(\n \"ContextMenu.RadioItem must be rendered inside ContextMenu.RadioGroup.\",\n );\n }\n\n return context;\n};\n\nconst useSubContext = () => {\n const context = useContext(SubContext);\n\n if (!context) {\n throw new Error(\n \"ContextMenu.SubTrigger and SubContent must be rendered inside ContextMenu.Sub.\",\n );\n }\n\n return context;\n};\n\nconst getMenuElements = (children: ReactNode): ReactElement[] =>\n Children.toArray(children).flatMap((child): ReactElement[] => {\n if (\n isValidElement<{ children?: ReactNode }>(child) &&\n child.type === Fragment\n ) {\n return getMenuElements(child.props.children);\n }\n\n return isValidElement(child) ? [child] : [];\n });\n\nconst ContextMenuRoot = ({\n children,\n open,\n defaultOpen = false,\n onOpenChange,\n disabled = false,\n triggerClassName,\n contentClassName,\n}: ContextMenuProps) => {\n const baseId = useId();\n const triggerId = `${baseId}-trigger`;\n const contentId = `${baseId}-content`;\n\n const childElements = getMenuElements(children);\n const triggers = childElements.filter(\n (child) => child.type === ContextMenuTrigger,\n );\n const contents = childElements.filter(\n (child) => child.type === ContextMenuContent,\n );\n\n const triggerElement = triggers[0] as\n | ReactElement<ContextMenuTriggerProps>\n | undefined;\n const contentElement = contents[0] as\n | ReactElement<ContextMenuContentProps>\n | undefined;\n\n if (\n triggers.length !== 1 ||\n contents.length !== 1 ||\n !triggerElement ||\n !contentElement\n ) {\n throw new Error(\n \"ContextMenu requires exactly one ContextMenu.Trigger and one ContextMenu.Content.\",\n );\n }\n\n const controlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const triggerDisabled = disabled || triggerElement.props.disabled === true;\n const isOpen =\n !triggerDisabled && (controlled ? (open ?? false) : internalOpen);\n\n const [point, setPoint] = useState<ContextMenuPoint>({\n x: 0,\n y: 0,\n });\n\n const triggerRef = useRef<HTMLElement | null>(null);\n const focusPositionRef = useRef<FocusPosition>(\"first\");\n\n const changeOpen = useCallback(\n (nextOpen: boolean) => {\n if (triggerDisabled && nextOpen) {\n return;\n }\n\n if (nextOpen === isOpen) {\n return;\n }\n\n if (!controlled) {\n setInternalOpen(nextOpen);\n }\n\n onOpenChange?.(nextOpen);\n },\n [controlled, isOpen, onOpenChange, triggerDisabled],\n );\n\n const openAt = useCallback(\n (nextPoint: ContextMenuPoint, position: FocusPosition = \"first\") => {\n if (triggerDisabled) {\n return;\n }\n\n setPoint({\n x: Math.max(0, nextPoint.x),\n y: Math.max(0, nextPoint.y),\n });\n\n focusPositionRef.current = position;\n changeOpen(true);\n },\n [changeOpen, triggerDisabled],\n );\n\n const close = useCallback(\n (restoreFocus = false) => {\n changeOpen(false);\n\n if (restoreFocus) {\n focusElement(triggerRef.current ?? undefined);\n }\n },\n [changeOpen],\n );\n\n const context = useMemo<ContextMenuContextValue>(\n () => ({\n open: isOpen,\n disabled: triggerDisabled,\n triggerId,\n contentId,\n triggerRef,\n focusPositionRef,\n openAt,\n changeOpen,\n close,\n }),\n [isOpen, triggerDisabled, triggerId, contentId, openAt, changeOpen, close],\n );\n\n const trigger = cloneElement(triggerElement, {\n id: triggerId,\n disabled: triggerDisabled,\n className: cn(triggerElement.props.className, triggerClassName),\n });\n\n const content = cloneElement(contentElement, {\n id: contentId,\n className: cn(contentElement.props.className, contentClassName),\n });\n\n const anchor = (\n <span\n aria-hidden=\"true\"\n className=\"puzzle-context-menu__anchor\"\n style={{\n left: point.x,\n top: point.y,\n }}\n tabIndex={-1}\n />\n );\n\n useEffect(() => {\n if (!isOpen || !triggerRef.current) {\n return;\n }\n\n const ownerDocument = triggerRef.current.ownerDocument;\n\n const handleOutsidePointerDown = (event: globalThis.PointerEvent) => {\n const target = event.target;\n\n if (!(target instanceof ownerDocument.defaultView!.Node)) {\n return;\n }\n\n if (\n triggerRef.current?.contains(target) ||\n (target instanceof Element &&\n target.closest(\".puzzle-context-menu__popover\"))\n ) {\n return;\n }\n\n changeOpen(false);\n };\n\n ownerDocument.addEventListener(\n \"pointerdown\",\n handleOutsidePointerDown,\n true,\n );\n\n return () => {\n ownerDocument.removeEventListener(\n \"pointerdown\",\n handleOutsidePointerDown,\n true,\n );\n };\n }, [isOpen, changeOpen]);\n\n return (\n <ContextMenuContext.Provider value={context}>\n {trigger}\n\n <Popout\n trigger={anchor as ReactElement<PopoutTriggerProps>}\n open={isOpen}\n onOpenChange={(nextOpen) => {\n if (nextOpen) {\n changeOpen(true);\n } else {\n close(true);\n }\n }}\n position=\"bottom\"\n align=\"start\"\n offset={0}\n collisionPadding={8}\n closeOnOutsideClick={false}\n closeOnEscape\n contentClassName=\"puzzle-context-menu__popover\"\n >\n {content}\n </Popout>\n </ContextMenuContext.Provider>\n );\n};\n\nconst ContextMenuTrigger = ({\n children,\n asChild = false,\n disabled = false,\n id,\n className,\n ref,\n onContextMenu,\n onClick,\n onKeyDown,\n onPointerDown,\n onPointerMove,\n onPointerUp,\n onPointerCancel,\n ...triggerProps\n}: ContextMenuTriggerProps) => {\n const context = useContextMenuContext();\n const longPressTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pointerStartRef = useRef<{ x: number; y: number } | null>(null);\n\n const isDisabled = disabled || context.disabled;\n\n const clearLongPress = useCallback(() => {\n if (longPressTimerRef.current !== null) {\n clearTimeout(longPressTimerRef.current);\n longPressTimerRef.current = null;\n }\n }, []);\n\n useEffect(() => clearLongPress, [clearLongPress]);\n\n const handleRef = useCallback(\n (node: HTMLElement | null) => {\n context.triggerRef.current = node;\n setRef(ref, node);\n },\n [context.triggerRef, ref],\n );\n\n const handleContextMenu = (event: MouseEvent<HTMLElement>) => {\n onContextMenu?.(event);\n\n if (event.defaultPrevented || isDisabled) {\n return;\n }\n\n event.preventDefault();\n context.triggerRef.current = event.currentTarget;\n\n context.openAt({\n x: event.clientX,\n y: event.clientY,\n });\n };\n\n const handleClick = (event: MouseEvent<HTMLElement>) => {\n onClick?.(event);\n\n if (event.defaultPrevented || isDisabled || event.button !== 0) {\n return;\n }\n\n if (event.ctrlKey) {\n event.preventDefault();\n context.triggerRef.current = event.currentTarget;\n context.openAt({\n x: event.clientX,\n y: event.clientY,\n });\n return;\n }\n\n if (context.open) {\n context.close(false);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented || isDisabled) {\n return;\n }\n\n const target = event.currentTarget;\n const rect = target.getBoundingClientRect();\n\n if (\n event.key === \"ContextMenu\" ||\n (event.shiftKey && event.key === \"F10\")\n ) {\n event.preventDefault();\n context.triggerRef.current = target;\n context.openAt({ x: rect.left, y: rect.bottom });\n return;\n }\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n context.triggerRef.current = target;\n context.openAt(\n { x: rect.left, y: rect.bottom },\n event.key === \"ArrowUp\" ? \"last\" : \"first\",\n );\n }\n };\n\n const handlePointerDown = (event: PointerEvent<HTMLElement>) => {\n onPointerDown?.(event);\n\n if (event.defaultPrevented || isDisabled || event.pointerType !== \"touch\") {\n return;\n }\n\n pointerStartRef.current = {\n x: event.clientX,\n y: event.clientY,\n };\n\n const target = event.currentTarget;\n\n longPressTimerRef.current = setTimeout(() => {\n const rect = target.getBoundingClientRect();\n\n context.triggerRef.current = target;\n context.openAt({\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n });\n }, 550);\n };\n\n const handlePointerMove = (event: PointerEvent<HTMLElement>) => {\n onPointerMove?.(event);\n\n const start = pointerStartRef.current;\n\n if (\n start &&\n (Math.abs(event.clientX - start.x) > 10 ||\n Math.abs(event.clientY - start.y) > 10)\n ) {\n clearLongPress();\n pointerStartRef.current = null;\n }\n };\n\n const handlePointerEnd = (\n event: PointerEvent<HTMLElement>,\n callback?: (event: PointerEvent<HTMLElement>) => void,\n ) => {\n callback?.(event);\n clearLongPress();\n pointerStartRef.current = null;\n };\n\n const commonProps = {\n ...triggerProps,\n id,\n ref: handleRef,\n className: cn(\"puzzle-context-menu__trigger\", className),\n role: \"button\",\n tabIndex: isDisabled ? -1 : (triggerProps.tabIndex ?? 0),\n \"aria-haspopup\": \"menu\" as const,\n \"aria-expanded\": context.open,\n \"aria-controls\": context.open ? context.contentId : undefined,\n \"aria-disabled\": isDisabled || undefined,\n \"data-state\": context.open ? \"open\" : \"closed\",\n onContextMenu: handleContextMenu,\n onClick: handleClick,\n onKeyDown: handleKeyDown,\n onPointerDown: handlePointerDown,\n onPointerMove: handlePointerMove,\n onPointerUp: (event: PointerEvent<HTMLElement>) =>\n handlePointerEnd(event, onPointerUp),\n onPointerCancel: (event: PointerEvent<HTMLElement>) =>\n handlePointerEnd(event, onPointerCancel),\n };\n\n if (!asChild) {\n return <div {...commonProps}>{children}</div>;\n }\n\n const child = Children.only(children);\n\n if (!isValidElement(child) || child.type === Fragment) {\n throw new Error(\n \"ContextMenu.Trigger with asChild expects one non-Fragment element.\",\n );\n }\n\n const childProps = child.props as HTMLAttributes<HTMLElement> & {\n ref?: Ref<HTMLElement>;\n className?: string;\n disabled?: boolean;\n onContextMenu?: (event: MouseEvent<HTMLElement>) => void;\n onClick?: (event: MouseEvent<HTMLElement>) => void;\n onKeyDown?: (event: KeyboardEvent<HTMLElement>) => void;\n onPointerDown?: (event: PointerEvent<HTMLElement>) => void;\n onPointerMove?: (event: PointerEvent<HTMLElement>) => void;\n onPointerUp?: (event: PointerEvent<HTMLElement>) => void;\n onPointerCancel?: (event: PointerEvent<HTMLElement>) => void;\n };\n\n const childDisabled =\n isDisabled ||\n childProps.disabled === true ||\n childProps[\"aria-disabled\"] === true ||\n childProps[\"aria-disabled\"] === \"true\";\n\n return cloneElement(child as ReactElement<Record<string, unknown>>, {\n ...commonProps,\n ref: (node: HTMLElement | null) => {\n handleRef(node);\n setRef(childProps.ref, node);\n },\n className: cn(\n \"puzzle-context-menu__trigger\",\n childProps.className,\n className,\n ),\n role: child.type === \"button\" ? undefined : \"button\",\n tabIndex: childDisabled ? -1 : (childProps.tabIndex ?? 0),\n \"aria-disabled\": childDisabled || undefined,\n disabled: child.type === \"button\" ? childDisabled : undefined,\n onContextMenu: (event: MouseEvent<HTMLElement>) => {\n if (childDisabled) {\n event.preventDefault();\n return;\n }\n\n childProps.onContextMenu?.(event);\n\n if (!event.defaultPrevented) {\n handleContextMenu(event);\n }\n },\n onClick: (event: MouseEvent<HTMLElement>) => {\n if (childDisabled) {\n return;\n }\n\n childProps.onClick?.(event);\n\n if (!event.defaultPrevented) {\n handleClick(event);\n }\n },\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => {\n childProps.onKeyDown?.(event);\n if (!event.defaultPrevented) {\n handleKeyDown(event);\n }\n },\n onPointerDown: (event: PointerEvent<HTMLElement>) => {\n childProps.onPointerDown?.(event);\n if (!event.defaultPrevented) {\n handlePointerDown(event);\n }\n },\n onPointerMove: (event: PointerEvent<HTMLElement>) => {\n childProps.onPointerMove?.(event);\n if (!event.defaultPrevented) {\n handlePointerMove(event);\n }\n },\n onPointerUp: (event: PointerEvent<HTMLElement>) => {\n childProps.onPointerUp?.(event);\n handlePointerEnd(event);\n },\n onPointerCancel: (event: PointerEvent<HTMLElement>) => {\n childProps.onPointerCancel?.(event);\n handlePointerEnd(event);\n },\n });\n};\n\nconst ContextMenuContent = ({\n children,\n id,\n className,\n style,\n maxHeight = \"min(24rem, calc(100dvh - 1rem))\",\n onKeyDown,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...contentProps\n}: ContextMenuContentProps) => {\n const context = useContextMenuContext();\n const positioned = usePopoutPositioned();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const typeaheadRef = useRef(\"\");\n const typeaheadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const initialFocusDoneRef = useRef(false);\n\n useEffect(() => {\n if (!context.open) {\n initialFocusDoneRef.current = false;\n typeaheadRef.current = \"\";\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n typeaheadTimerRef.current = null;\n }\n }\n }, [context.open]);\n\n useEffect(() => {\n if (!context.open || !positioned || initialFocusDoneRef.current) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n initialFocusDoneRef.current = true;\n\n const items = getEnabledMenuItems(menu);\n const target =\n context.focusPositionRef.current === \"last\"\n ? items[items.length - 1]\n : items[0];\n\n focusElement(target ?? menu);\n }, [context.open, context.focusPositionRef, positioned]);\n\n useEffect(\n () => () => {\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n },\n [],\n );\n\n const focusIndex = (items: HTMLElement[], index: number) => {\n if (index >= 0 && index < items.length) {\n focusElement(items[index]);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n context.close(true);\n return;\n }\n\n if (event.key === \"Tab\") {\n const ownerDocument = event.currentTarget.ownerDocument;\n const trigger = context.triggerRef.current;\n const selector = [\n \"a[href]\",\n \"area[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled]):not([type='hidden'])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n \"iframe\",\n \"summary\",\n \"[contenteditable='true']\",\n \"[tabindex]:not([tabindex='-1'])\",\n ].join(\",\");\n\n const tabbableElements = Array.from(\n ownerDocument.querySelectorAll<HTMLElement>(selector),\n ).filter((element) => {\n if (\n menu.contains(element) ||\n element.hidden ||\n element.tabIndex < 0 ||\n element.getAttribute(\"aria-disabled\") === \"true\" ||\n element.closest(\"[hidden], [inert], [aria-hidden='true']\")\n ) {\n return false;\n }\n\n const computedStyle =\n ownerDocument.defaultView?.getComputedStyle(element);\n\n return (\n computedStyle?.display !== \"none\" &&\n computedStyle?.visibility !== \"hidden\"\n );\n });\n\n const triggerIndex = trigger ? tabbableElements.indexOf(trigger) : -1;\n const direction = event.shiftKey ? -1 : 1;\n const targetIndex = triggerIndex + direction;\n const target =\n triggerIndex >= 0 && tabbableElements.length > 0\n ? tabbableElements[\n (targetIndex + tabbableElements.length) % tabbableElements.length\n ]\n : undefined;\n\n context.close(false);\n\n if (target) {\n event.preventDefault();\n focusElement(target);\n }\n\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const activeIndex = items.indexOf(\n menu.ownerDocument.activeElement as HTMLElement,\n );\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n\n const direction = event.key === \"ArrowDown\" ? 1 : -1;\n const startIndex =\n activeIndex < 0 ? (direction === 1 ? -1 : 0) : activeIndex;\n\n const nextIndex = findNextMenuItemIndex(\n items.map(() => ({ disabled: false })),\n startIndex,\n direction,\n );\n\n focusIndex(items, nextIndex);\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n focusIndex(items, event.key === \"Home\" ? 0 : items.length - 1);\n return;\n }\n\n if (event.key === \"ArrowRight\") {\n const activeItem = items[activeIndex];\n\n if (activeItem?.hasAttribute(\"data-puzzle-context-menu-sub-trigger\")) {\n event.preventDefault();\n activeItem.click();\n }\n\n return;\n }\n\n if (\n event.key.length !== 1 ||\n event.key === \" \" ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey\n ) {\n return;\n }\n\n event.preventDefault();\n\n const nextBuffer = `${typeaheadRef.current}${event.key}`;\n const repeatedCharacter = [...nextBuffer].every(\n (character) =>\n character.toLocaleLowerCase() === nextBuffer[0]!.toLocaleLowerCase(),\n );\n const query = repeatedCharacter ? event.key : nextBuffer;\n\n typeaheadRef.current = query;\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n\n typeaheadTimerRef.current = setTimeout(() => {\n typeaheadRef.current = \"\";\n typeaheadTimerRef.current = null;\n }, 500);\n\n const nextIndex = findMenuItemIndexByText(\n items.map((item) => ({\n text: getMenuItemText(item),\n })),\n query,\n activeIndex,\n );\n\n focusIndex(items, nextIndex);\n };\n\n return (\n <div\n {...contentProps}\n ref={menuRef}\n id={id ?? context.contentId}\n className={cn(\"puzzle-context-menu__content\", className)}\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={ariaLabel}\n aria-labelledby={\n ariaLabel ? undefined : (ariaLabelledBy ?? context.triggerId)\n }\n tabIndex={-1}\n data-state={context.open ? \"open\" : \"closed\"}\n style={{ ...style, maxHeight }}\n onKeyDown={handleKeyDown}\n >\n {children}\n </div>\n );\n};\n\nconst ContextMenuItem = ({\n children,\n className,\n disabled = false,\n \"aria-disabled\": ariaDisabled,\n textValue,\n closeOnSelect = true,\n variant = \"default\",\n onClick,\n onSelect,\n ...itemProps\n}: ContextMenuItemProps) => {\n const context = useContextMenuContext();\n const itemDisabled =\n disabled || ariaDisabled === true || ariaDisabled === \"true\";\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n if (itemDisabled) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n onClick?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n onSelect?.(event);\n\n if (!event.defaultPrevented && closeOnSelect) {\n context.close(true);\n }\n };\n\n return (\n <button\n {...(itemProps as ButtonHTMLAttributes<HTMLButtonElement>)}\n type=\"button\"\n className={cn(\n \"puzzle-context-menu__item\",\n variant === \"danger\" && \"puzzle-context-menu__item--danger\",\n className,\n )}\n role=\"menuitem\"\n tabIndex={-1}\n disabled={itemDisabled}\n aria-disabled={itemDisabled || undefined}\n data-puzzle-context-menu-item=\"true\"\n data-text-value={textValue}\n onClick={handleClick}\n >\n <span className=\"puzzle-context-menu__item-label\">{children}</span>\n </button>\n );\n};\n\nconst ContextMenuGroup = ({\n children,\n className,\n \"aria-label\": ariaLabel,\n ...groupProps\n}: ContextMenuGroupProps) => (\n <div\n {...groupProps}\n className={cn(\"puzzle-context-menu__group\", className)}\n role=\"group\"\n aria-label={ariaLabel}\n >\n {children}\n </div>\n);\n\nconst ContextMenuLabel = ({\n children,\n className,\n ...labelProps\n}: ContextMenuLabelProps) => (\n <div {...labelProps} className={cn(\"puzzle-context-menu__label\", className)}>\n {children}\n </div>\n);\n\nconst ContextMenuSeparator = ({\n className,\n ...separatorProps\n}: ContextMenuSeparatorProps) => (\n <div\n {...separatorProps}\n className={cn(\"puzzle-context-menu__separator\", className)}\n role=\"separator\"\n aria-orientation=\"horizontal\"\n />\n);\n\nconst ContextMenuCheckboxItem = ({\n children,\n checked,\n defaultChecked = false,\n onCheckedChange,\n closeOnSelect = false,\n textValue,\n className,\n disabled = false,\n \"aria-disabled\": ariaDisabled,\n onClick,\n onSelect,\n ...itemProps\n}: ContextMenuCheckboxItemProps) => {\n const context = useContextMenuContext();\n const itemDisabled =\n disabled || ariaDisabled === true || ariaDisabled === \"true\";\n const controlled = checked !== undefined;\n const [internalChecked, setInternalChecked] = useState(defaultChecked);\n const resolvedChecked = checked ?? internalChecked;\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n if (itemDisabled) {\n event.preventDefault();\n return;\n }\n\n onClick?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n onSelect?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n const nextChecked = resolvedChecked !== true;\n\n if (!controlled) {\n setInternalChecked(nextChecked);\n }\n\n onCheckedChange?.(nextChecked);\n\n if (closeOnSelect) {\n context.close(true);\n }\n };\n\n return (\n <button\n {...(itemProps as ButtonHTMLAttributes<HTMLButtonElement>)}\n type=\"button\"\n className={cn(\"puzzle-context-menu__item\", className)}\n role=\"menuitemcheckbox\"\n tabIndex={-1}\n disabled={itemDisabled}\n aria-disabled={itemDisabled || undefined}\n aria-checked={\n resolvedChecked === \"indeterminate\" ? \"mixed\" : resolvedChecked\n }\n data-state={\n resolvedChecked === \"indeterminate\"\n ? \"indeterminate\"\n : resolvedChecked\n ? \"checked\"\n : \"unchecked\"\n }\n data-puzzle-context-menu-item=\"true\"\n data-text-value={textValue}\n onClick={handleClick}\n >\n <span className=\"puzzle-context-menu__indicator\" aria-hidden=\"true\">\n {resolvedChecked === \"indeterminate\" ? \"−\" : resolvedChecked ? \"✓\" : \"\"}\n </span>\n <span className=\"puzzle-context-menu__item-label\">{children}</span>\n </button>\n );\n};\n\nconst ContextMenuRadioGroup = ({\n children,\n value,\n defaultValue,\n onValueChange,\n className,\n ...groupProps\n}: ContextMenuRadioGroupProps) => {\n const controlled = value !== undefined;\n const [internalValue, setInternalValue] = useState(defaultValue);\n const resolvedValue = controlled ? value : internalValue;\n\n const setValue = useCallback(\n (nextValue: string) => {\n if (nextValue === resolvedValue) {\n return;\n }\n\n if (!controlled) {\n setInternalValue(nextValue);\n }\n\n onValueChange?.(nextValue);\n },\n [controlled, onValueChange, resolvedValue],\n );\n\n return (\n <RadioGroupContext.Provider value={{ value: resolvedValue, setValue }}>\n <div\n {...groupProps}\n className={cn(\"puzzle-context-menu__group\", className)}\n role=\"group\"\n >\n {children}\n </div>\n </RadioGroupContext.Provider>\n );\n};\n\nconst ContextMenuRadioItem = ({\n children,\n value,\n closeOnSelect = true,\n textValue,\n className,\n disabled = false,\n \"aria-disabled\": ariaDisabled,\n onClick,\n onSelect,\n ...itemProps\n}: ContextMenuRadioItemProps) => {\n const context = useContextMenuContext();\n const radioGroup = useRadioGroupContext();\n const checked = radioGroup.value === value;\n const itemDisabled =\n disabled || ariaDisabled === true || ariaDisabled === \"true\";\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n if (itemDisabled) {\n event.preventDefault();\n return;\n }\n\n onClick?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n onSelect?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n radioGroup.setValue(value);\n\n if (closeOnSelect) {\n context.close(true);\n }\n };\n\n return (\n <button\n {...(itemProps as ButtonHTMLAttributes<HTMLButtonElement>)}\n type=\"button\"\n className={cn(\"puzzle-context-menu__item\", className)}\n role=\"menuitemradio\"\n tabIndex={-1}\n disabled={itemDisabled}\n aria-disabled={itemDisabled || undefined}\n aria-checked={checked}\n data-state={checked ? \"checked\" : \"unchecked\"}\n data-puzzle-context-menu-item=\"true\"\n data-text-value={textValue}\n onClick={handleClick}\n >\n <span className=\"puzzle-context-menu__indicator\" aria-hidden=\"true\">\n {checked ? \"●\" : \"\"}\n </span>\n <span className=\"puzzle-context-menu__item-label\">{children}</span>\n </button>\n );\n};\n\nconst ContextMenuSub = ({\n children,\n defaultOpen = false,\n}: ContextMenuSubProps) => {\n const rootContext = useContextMenuContext();\n const baseId = useId();\n const triggerId = `${baseId}-trigger`;\n const contentId = `${baseId}-content`;\n\n const [open, setOpen] = useState(defaultOpen);\n const triggerRef = useRef<HTMLButtonElement | null>(null);\n\n const elements = getMenuElements(children);\n const triggers = elements.filter(\n (child) => child.type === ContextMenuSubTrigger,\n );\n const contents = elements.filter(\n (child) => child.type === ContextMenuSubContent,\n );\n\n const triggerElement = triggers[0] as\n | ReactElement<ContextMenuSubTriggerProps>\n | undefined;\n const contentElement = contents[0] as\n | ReactElement<ContextMenuSubContentProps>\n | undefined;\n\n if (\n triggers.length !== 1 ||\n contents.length !== 1 ||\n !triggerElement ||\n !contentElement\n ) {\n throw new Error(\n \"ContextMenu.Sub requires exactly one SubTrigger and one SubContent.\",\n );\n }\n\n useEffect(() => {\n if (!rootContext.open) {\n setOpen(false);\n }\n }, [rootContext.open]);\n\n const close = useCallback((restoreFocus = false) => {\n setOpen(false);\n\n if (restoreFocus) {\n focusElement(triggerRef.current ?? undefined);\n }\n }, []);\n\n const subContext = useMemo<SubContextValue>(\n () => ({\n open,\n setOpen,\n triggerId,\n contentId,\n triggerRef,\n close,\n }),\n [open, triggerId, contentId, close],\n );\n\n const trigger = cloneElement(triggerElement, {\n id: triggerId,\n });\n\n const content = cloneElement(contentElement, {\n id: contentId,\n });\n\n return (\n <SubContext.Provider value={subContext}>\n <Popout\n trigger={trigger as ReactElement<PopoutTriggerProps>}\n open={open}\n onOpenChange={setOpen}\n position=\"right\"\n align=\"start\"\n offset={4}\n collisionPadding={8}\n action=\"hover\"\n closeOnOutsideClick\n closeOnEscape\n contentClassName=\"puzzle-context-menu__popover puzzle-context-menu__submenu-popover\"\n >\n {content}\n </Popout>\n </SubContext.Provider>\n );\n};\n\nconst ContextMenuSubTrigger = forwardRef<\n HTMLButtonElement,\n ContextMenuSubTriggerProps\n>(\n (\n { children, className, disabled = false, onClick, onKeyDown, ...props },\n ref,\n ) => {\n const context = useSubContext();\n\n const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.defaultPrevented && !disabled) {\n context.setOpen(true);\n }\n };\n\n const handleKeyDown = (event: KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(event);\n\n if (!event.defaultPrevented && !disabled && event.key === \"ArrowRight\") {\n event.preventDefault();\n context.setOpen(true);\n }\n\n if (!event.defaultPrevented && !disabled && event.key === \"ArrowLeft\") {\n event.preventDefault();\n context.close(true);\n }\n };\n\n return (\n <button\n {...props}\n ref={(node) => {\n context.triggerRef.current = node;\n setRef(ref, node);\n }}\n id={context.triggerId}\n type=\"button\"\n role=\"menuitem\"\n tabIndex={-1}\n className={cn(\"puzzle-context-menu__item\", className)}\n aria-haspopup=\"menu\"\n aria-expanded={context.open}\n aria-controls={context.open ? context.contentId : undefined}\n aria-disabled={disabled || undefined}\n disabled={disabled}\n data-puzzle-context-menu-item=\"true\"\n data-puzzle-context-menu-sub-trigger=\"true\"\n onClick={handleClick}\n onKeyDown={handleKeyDown}\n onPointerEnter={() => {\n if (!disabled) {\n context.setOpen(true);\n }\n }}\n >\n <span className=\"puzzle-context-menu__item-label\">{children}</span>\n <span\n className=\"puzzle-context-menu__submenu-indicator\"\n aria-hidden=\"true\"\n >\n ›\n </span>\n </button>\n );\n },\n);\n\nContextMenuSubTrigger.displayName = \"ContextMenuSubTrigger\";\n\nconst ContextMenuSubContent = ({\n children,\n id,\n className,\n style,\n maxHeight = \"min(24rem, calc(100dvh - 1rem))\",\n onKeyDown,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n ...contentProps\n}: ContextMenuSubContentProps) => {\n const context = useSubContext();\n const positioned = usePopoutPositioned();\n const menuRef = useRef<HTMLDivElement | null>(null);\n const typeaheadRef = useRef(\"\");\n const typeaheadTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const initialFocusDoneRef = useRef(false);\n\n useEffect(() => {\n if (!context.open) {\n initialFocusDoneRef.current = false;\n typeaheadRef.current = \"\";\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n typeaheadTimerRef.current = null;\n }\n }\n }, [context.open]);\n\n useEffect(\n () => () => {\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n },\n [],\n );\n\n useEffect(() => {\n if (!context.open || !positioned || initialFocusDoneRef.current) {\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n initialFocusDoneRef.current = true;\n const items = getEnabledMenuItems(menu);\n focusElement(items[0] ?? menu);\n }, [context.open, positioned]);\n\n const handleKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n\n if (event.defaultPrevented) {\n return;\n }\n\n event.stopPropagation();\n\n if (event.key === \"ArrowLeft\") {\n event.preventDefault();\n context.close(true);\n return;\n }\n\n if (event.key === \"Escape\") {\n event.preventDefault();\n context.close(true);\n return;\n }\n\n const menu = menuRef.current;\n\n if (!menu) {\n return;\n }\n\n const items = getEnabledMenuItems(menu);\n const activeIndex = items.indexOf(\n menu.ownerDocument.activeElement as HTMLElement,\n );\n\n if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n event.preventDefault();\n\n const direction = event.key === \"ArrowDown\" ? 1 : -1;\n const startIndex =\n activeIndex < 0 ? (direction === 1 ? -1 : 0) : activeIndex;\n\n const nextIndex = findNextMenuItemIndex(\n items.map(() => ({ disabled: false })),\n startIndex,\n direction,\n );\n\n if (nextIndex >= 0) {\n focusElement(items[nextIndex]);\n }\n\n return;\n }\n\n if (event.key === \"Home\" || event.key === \"End\") {\n event.preventDefault();\n const target = event.key === \"Home\" ? items[0] : items[items.length - 1];\n\n if (target) {\n focusElement(target);\n }\n\n return;\n }\n\n if (\n event.key.length !== 1 ||\n event.key === \" \" ||\n event.ctrlKey ||\n event.metaKey ||\n event.altKey\n ) {\n return;\n }\n\n event.preventDefault();\n\n const nextBuffer = `${typeaheadRef.current}${event.key}`;\n const repeatedCharacter = [...nextBuffer].every(\n (character) =>\n character.toLocaleLowerCase() === nextBuffer[0]!.toLocaleLowerCase(),\n );\n const query = repeatedCharacter ? event.key : nextBuffer;\n\n typeaheadRef.current = query;\n\n if (typeaheadTimerRef.current !== null) {\n clearTimeout(typeaheadTimerRef.current);\n }\n\n typeaheadTimerRef.current = setTimeout(() => {\n typeaheadRef.current = \"\";\n typeaheadTimerRef.current = null;\n }, 500);\n\n const nextIndex = findMenuItemIndexByText(\n items.map((item) => ({\n text: getMenuItemText(item),\n })),\n query,\n activeIndex,\n );\n\n if (nextIndex >= 0) {\n focusElement(items[nextIndex]);\n }\n };\n\n return (\n <div\n {...contentProps}\n ref={menuRef}\n id={id ?? context.contentId}\n className={cn(\"puzzle-context-menu__content\", className)}\n role=\"menu\"\n aria-orientation=\"vertical\"\n aria-label={ariaLabel}\n aria-labelledby={\n ariaLabel ? undefined : (ariaLabelledBy ?? context.triggerId)\n }\n tabIndex={-1}\n data-state={context.open ? \"open\" : \"closed\"}\n style={{ ...style, maxHeight }}\n onKeyDown={handleKeyDown}\n >\n {children}\n </div>\n );\n};\n\ntype ContextMenuComponent = typeof ContextMenuRoot & {\n Trigger: typeof ContextMenuTrigger;\n Content: typeof ContextMenuContent;\n Item: typeof ContextMenuItem;\n Group: typeof ContextMenuGroup;\n Label: typeof ContextMenuLabel;\n Separator: typeof ContextMenuSeparator;\n CheckboxItem: typeof ContextMenuCheckboxItem;\n RadioGroup: typeof ContextMenuRadioGroup;\n RadioItem: typeof ContextMenuRadioItem;\n Sub: typeof ContextMenuSub & {\n Trigger: typeof ContextMenuSubTrigger;\n Content: typeof ContextMenuSubContent;\n };\n SubTrigger: typeof ContextMenuSubTrigger;\n SubContent: typeof ContextMenuSubContent;\n};\n\nconst ContextMenuSubCompound = Object.assign(ContextMenuSub, {\n Trigger: ContextMenuSubTrigger,\n Content: ContextMenuSubContent,\n});\n\nconst ContextMenu = Object.assign(ContextMenuRoot, {\n Trigger: ContextMenuTrigger,\n Content: ContextMenuContent,\n Item: ContextMenuItem,\n Group: ContextMenuGroup,\n Label: ContextMenuLabel,\n Separator: ContextMenuSeparator,\n CheckboxItem: ContextMenuCheckboxItem,\n RadioGroup: ContextMenuRadioGroup,\n RadioItem: ContextMenuRadioItem,\n Sub: ContextMenuSubCompound,\n SubTrigger: ContextMenuSubTrigger,\n SubContent: ContextMenuSubContent,\n}) as ContextMenuComponent;\n\nexport {\n ContextMenu,\n ContextMenuTrigger,\n ContextMenuContent,\n ContextMenuItem,\n ContextMenuGroup,\n ContextMenuLabel,\n ContextMenuSeparator,\n ContextMenuCheckboxItem,\n ContextMenuRadioGroup,\n ContextMenuRadioItem,\n ContextMenuSubCompound as ContextMenuSub,\n ContextMenuSubTrigger,\n ContextMenuSubContent,\n};\n\nexport type {\n ContextMenuProps,\n ContextMenuTriggerProps,\n ContextMenuContentProps,\n ContextMenuItemProps,\n ContextMenuGroupProps,\n ContextMenuLabelProps,\n ContextMenuSeparatorProps,\n ContextMenuCheckboxItemProps,\n ContextMenuRadioGroupProps,\n ContextMenuRadioItemProps,\n ContextMenuSubProps,\n ContextMenuSubTriggerProps,\n ContextMenuSubContentProps,\n};\n\nexport type {\n ContextMenuItemVariant,\n ContextMenuCheckedState,\n} from \"./context-menu.types\";\n"],"mappings":"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"}
@@ -1,12 +1,16 @@
1
1
  let _puzzle_ui_core = require("@puzzle-ui/core");
2
2
  let react_jsx_runtime = require("react/jsx-runtime");
3
3
  // src/components/typography/heading.tsx
4
- const Heading = ({ level, as, className, ...props }) => {
4
+ const Heading = ({ level, as, className, textAlign, style, ...props }) => {
5
5
  const Component = as ?? "h2";
6
6
  const classes = (0, _puzzle_ui_core.cn)("puzzle-heading", `puzzle-typography-${level}`, className);
7
7
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
8
+ ...props,
8
9
  className: classes,
9
- ...props
10
+ style: textAlign === void 0 ? style : {
11
+ ...style,
12
+ textAlign
13
+ }
10
14
  });
11
15
  };
12
16
  exports.Heading = Heading;
@@ -1 +1 @@
1
- {"version":3,"file":"heading.cjs","names":["cn"],"sources":["../../../src/components/typography/heading.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { ComponentPropsWithRef, ElementType } from \"react\";\n\ntype HeadingLevel =\n | \"display1\"\n | \"display2\"\n | \"headline1\"\n | \"headline2\"\n | \"headline3\"\n | \"headline4\";\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype HeadingOwnProps = {\n level: HeadingLevel;\n};\n\ntype HeadingProps<E extends ElementType = \"h2\"> = PolymorphicProps<\n E,\n HeadingOwnProps\n>;\n\nconst Heading = <E extends ElementType = \"h2\">({\n level,\n as,\n className,\n ...props\n}: HeadingProps<E>) => {\n const Component = as ?? \"h2\";\n const classes = cn(\"puzzle-heading\", `puzzle-typography-${level}`, className);\n return <Component className={classes} {...props}></Component>;\n};\n\nexport { Heading, type HeadingProps, type HeadingLevel };\n"],"mappings":";;;AAwBA,MAAM,WAAyC,EAC7C,OACA,IACA,WACA,GAAG,YACkB;CACrB,MAAM,YAAY,MAAM;CACxB,MAAM,WAAA,GAAUA,gBAAAA,GAAAA,CAAG,kBAAkB,qBAAqB,SAAS,SAAS;CAC5E,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;EAAW,WAAW;EAAS,GAAI;CAAkB,CAAA;AAC9D"}
1
+ {"version":3,"file":"heading.cjs","names":["cn"],"sources":["../../../src/components/typography/heading.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { ComponentPropsWithRef, CSSProperties, ElementType } from \"react\";\n\ntype HeadingLevel =\n | \"display1\"\n | \"display2\"\n | \"headline1\"\n | \"headline2\"\n | \"headline3\"\n | \"headline4\";\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype HeadingOwnProps = {\n level: HeadingLevel;\n textAlign?: CSSProperties[\"textAlign\"];\n};\n\ntype HeadingProps<E extends ElementType = \"h2\"> = PolymorphicProps<\n E,\n HeadingOwnProps\n>;\n\nconst Heading = <E extends ElementType = \"h2\">({\n level,\n as,\n className,\n textAlign,\n style,\n ...props\n}: HeadingProps<E>) => {\n const Component = as ?? \"h2\";\n const classes = cn(\"puzzle-heading\", `puzzle-typography-${level}`, className);\n return (\n <Component\n {...props}\n className={classes}\n style={textAlign === undefined ? style : { ...style, textAlign }}\n ></Component>\n );\n};\n\nexport { Heading, type HeadingProps, type HeadingLevel };\n"],"mappings":";;;AAyBA,MAAM,WAAyC,EAC7C,OACA,IACA,WACA,WACA,OACA,GAAG,YACkB;CACrB,MAAM,YAAY,MAAM;CACxB,MAAM,WAAA,GAAUA,gBAAAA,GAAAA,CAAG,kBAAkB,qBAAqB,SAAS,SAAS;CAC5E,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;EACE,GAAI;EACJ,WAAW;EACX,OAAO,cAAc,KAAA,IAAY,QAAQ;GAAE,GAAG;GAAO;EAAU;CACrD,CAAA;AAEhB"}
@@ -1,11 +1,12 @@
1
- import { ComponentPropsWithRef, ElementType } from "react";
1
+ import { CSSProperties, ComponentPropsWithRef, ElementType } from "react";
2
2
  type HeadingLevel = "display1" | "display2" | "headline1" | "headline2" | "headline3" | "headline4";
3
3
  type PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {
4
4
  as?: E;
5
5
  } & Omit<ComponentPropsWithRef<E>, keyof OwnProps | "as">;
6
6
  type HeadingOwnProps = {
7
7
  level: HeadingLevel;
8
+ textAlign?: CSSProperties["textAlign"];
8
9
  };
9
10
  type HeadingProps<E extends ElementType = "h2"> = PolymorphicProps<E, HeadingOwnProps>;
10
- declare const Heading: <E extends ElementType = "h2">({ level, as, className, ...props }: HeadingProps<E>) => import("react").JSX.Element;
11
+ declare const Heading: <E extends ElementType = "h2">({ level, as, className, textAlign, style, ...props }: HeadingProps<E>) => import("react").JSX.Element;
11
12
  export { Heading, type HeadingLevel, type HeadingProps };
@@ -1,11 +1,12 @@
1
- import { ComponentPropsWithRef, ElementType } from "react";
1
+ import { CSSProperties, ComponentPropsWithRef, ElementType } from "react";
2
2
  type HeadingLevel = "display1" | "display2" | "headline1" | "headline2" | "headline3" | "headline4";
3
3
  type PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {
4
4
  as?: E;
5
5
  } & Omit<ComponentPropsWithRef<E>, keyof OwnProps | "as">;
6
6
  type HeadingOwnProps = {
7
7
  level: HeadingLevel;
8
+ textAlign?: CSSProperties["textAlign"];
8
9
  };
9
10
  type HeadingProps<E extends ElementType = "h2"> = PolymorphicProps<E, HeadingOwnProps>;
10
- declare const Heading: <E extends ElementType = "h2">({ level, as, className, ...props }: HeadingProps<E>) => import("react").JSX.Element;
11
+ declare const Heading: <E extends ElementType = "h2">({ level, as, className, textAlign, style, ...props }: HeadingProps<E>) => import("react").JSX.Element;
11
12
  export { Heading, type HeadingLevel, type HeadingProps };
@@ -1,12 +1,16 @@
1
1
  import { cn } from "@puzzle-ui/core";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  // src/components/typography/heading.tsx
4
- const Heading = ({ level, as, className, ...props }) => {
4
+ const Heading = ({ level, as, className, textAlign, style, ...props }) => {
5
5
  const Component = as ?? "h2";
6
6
  const classes = cn("puzzle-heading", `puzzle-typography-${level}`, className);
7
7
  return /* @__PURE__ */ jsx(Component, {
8
+ ...props,
8
9
  className: classes,
9
- ...props
10
+ style: textAlign === void 0 ? style : {
11
+ ...style,
12
+ textAlign
13
+ }
10
14
  });
11
15
  };
12
16
  export { Heading };
@@ -1 +1 @@
1
- {"version":3,"file":"heading.js","names":[],"sources":["../../../src/components/typography/heading.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { ComponentPropsWithRef, ElementType } from \"react\";\n\ntype HeadingLevel =\n | \"display1\"\n | \"display2\"\n | \"headline1\"\n | \"headline2\"\n | \"headline3\"\n | \"headline4\";\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype HeadingOwnProps = {\n level: HeadingLevel;\n};\n\ntype HeadingProps<E extends ElementType = \"h2\"> = PolymorphicProps<\n E,\n HeadingOwnProps\n>;\n\nconst Heading = <E extends ElementType = \"h2\">({\n level,\n as,\n className,\n ...props\n}: HeadingProps<E>) => {\n const Component = as ?? \"h2\";\n const classes = cn(\"puzzle-heading\", `puzzle-typography-${level}`, className);\n return <Component className={classes} {...props}></Component>;\n};\n\nexport { Heading, type HeadingProps, type HeadingLevel };\n"],"mappings":";;;AAwBA,MAAM,WAAyC,EAC7C,OACA,IACA,WACA,GAAG,YACkB;CACrB,MAAM,YAAY,MAAM;CACxB,MAAM,UAAU,GAAG,kBAAkB,qBAAqB,SAAS,SAAS;CAC5E,OAAO,oBAAC,WAAD;EAAW,WAAW;EAAS,GAAI;CAAkB,CAAA;AAC9D"}
1
+ {"version":3,"file":"heading.js","names":[],"sources":["../../../src/components/typography/heading.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { ComponentPropsWithRef, CSSProperties, ElementType } from \"react\";\n\ntype HeadingLevel =\n | \"display1\"\n | \"display2\"\n | \"headline1\"\n | \"headline2\"\n | \"headline3\"\n | \"headline4\";\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype HeadingOwnProps = {\n level: HeadingLevel;\n textAlign?: CSSProperties[\"textAlign\"];\n};\n\ntype HeadingProps<E extends ElementType = \"h2\"> = PolymorphicProps<\n E,\n HeadingOwnProps\n>;\n\nconst Heading = <E extends ElementType = \"h2\">({\n level,\n as,\n className,\n textAlign,\n style,\n ...props\n}: HeadingProps<E>) => {\n const Component = as ?? \"h2\";\n const classes = cn(\"puzzle-heading\", `puzzle-typography-${level}`, className);\n return (\n <Component\n {...props}\n className={classes}\n style={textAlign === undefined ? style : { ...style, textAlign }}\n ></Component>\n );\n};\n\nexport { Heading, type HeadingProps, type HeadingLevel };\n"],"mappings":";;;AAyBA,MAAM,WAAyC,EAC7C,OACA,IACA,WACA,WACA,OACA,GAAG,YACkB;CACrB,MAAM,YAAY,MAAM;CACxB,MAAM,UAAU,GAAG,kBAAkB,qBAAqB,SAAS,SAAS;CAC5E,OACE,oBAAC,WAAD;EACE,GAAI;EACJ,WAAW;EACX,OAAO,cAAc,KAAA,IAAY,QAAQ;GAAE,GAAG;GAAO;EAAU;CACrD,CAAA;AAEhB"}
@@ -1,12 +1,16 @@
1
1
  let _puzzle_ui_core = require("@puzzle-ui/core");
2
2
  let react_jsx_runtime = require("react/jsx-runtime");
3
3
  // src/components/typography/text.tsx
4
- const Text = ({ as, type = "body1", className, ...props }) => {
4
+ const Text = ({ as, type = "body1", className, textAlign, style, ...props }) => {
5
5
  const Component = as ?? "span";
6
6
  const classes = (0, _puzzle_ui_core.cn)("puzzle-text", `puzzle-typography-${type}`, className);
7
7
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
8
8
  ...props,
9
- className: classes
9
+ className: classes,
10
+ style: textAlign === void 0 ? style : {
11
+ ...style,
12
+ textAlign
13
+ }
10
14
  });
11
15
  };
12
16
  exports.Text = Text;
@@ -1 +1 @@
1
- {"version":3,"file":"text.cjs","names":["cn"],"sources":["../../../src/components/typography/text.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { TypographyStyle } from \"@puzzle-ui/theme\";\nimport type { ComponentPropsWithRef, ElementType } from \"react\";\n\ntype TextType = Omit<\n TypographyStyle,\n \"headline1\" | \"headline2\" | \"headline3\" | \"headline4\"\n>;\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype TextOwnProps = {\n type?: TextType;\n};\n\ntype TextProps<E extends ElementType = \"span\"> = PolymorphicProps<\n E,\n TextOwnProps\n>;\n\nconst Text = <E extends ElementType = \"span\">({\n as,\n type = \"body1\",\n className,\n ...props\n}: TextProps<E>) => {\n const Component = as ?? \"span\";\n const classes = cn(\"puzzle-text\", `puzzle-typography-${type}`, className);\n return <Component {...props} className={classes}></Component>;\n};\n\nexport { Text, type TextProps, type TextType };\n"],"mappings":";;;AAsBA,MAAM,QAAwC,EAC5C,IACA,OAAO,SACP,WACA,GAAG,YACe;CAClB,MAAM,YAAY,MAAM;CACxB,MAAM,WAAA,GAAUA,gBAAAA,GAAAA,CAAG,eAAe,qBAAqB,QAAQ,SAAS;CACxE,OAAO,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;EAAW,GAAI;EAAO,WAAW;CAAoB,CAAA;AAC9D"}
1
+ {"version":3,"file":"text.cjs","names":["cn"],"sources":["../../../src/components/typography/text.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { TypographyStyle } from \"@puzzle-ui/theme\";\nimport type { ComponentPropsWithRef, CSSProperties, ElementType } from \"react\";\n\ntype TextType = Omit<\n TypographyStyle,\n \"headline1\" | \"headline2\" | \"headline3\" | \"headline4\"\n>;\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype TextOwnProps = {\n type?: TextType;\n textAlign?: CSSProperties[\"textAlign\"];\n};\n\ntype TextProps<E extends ElementType = \"span\"> = PolymorphicProps<\n E,\n TextOwnProps\n>;\n\nconst Text = <E extends ElementType = \"span\">({\n as,\n type = \"body1\",\n className,\n textAlign,\n style,\n ...props\n}: TextProps<E>) => {\n const Component = as ?? \"span\";\n const classes = cn(\"puzzle-text\", `puzzle-typography-${type}`, className);\n return (\n <Component\n {...props}\n className={classes}\n style={textAlign === undefined ? style : { ...style, textAlign }}\n ></Component>\n );\n};\n\nexport { Text, type TextProps, type TextType };\n"],"mappings":";;;AAuBA,MAAM,QAAwC,EAC5C,IACA,OAAO,SACP,WACA,WACA,OACA,GAAG,YACe;CAClB,MAAM,YAAY,MAAM;CACxB,MAAM,WAAA,GAAUA,gBAAAA,GAAAA,CAAG,eAAe,qBAAqB,QAAQ,SAAS;CACxE,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,WAAD;EACE,GAAI;EACJ,WAAW;EACX,OAAO,cAAc,KAAA,IAAY,QAAQ;GAAE,GAAG;GAAO;EAAU;CACrD,CAAA;AAEhB"}
@@ -1,4 +1,4 @@
1
- import { ComponentPropsWithRef, ElementType } from "react";
1
+ import { CSSProperties, ComponentPropsWithRef, ElementType } from "react";
2
2
  import { TypographyStyle } from "@puzzle-ui/theme";
3
3
  type TextType = Omit<TypographyStyle, "headline1" | "headline2" | "headline3" | "headline4">;
4
4
  type PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {
@@ -6,7 +6,8 @@ type PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {
6
6
  } & Omit<ComponentPropsWithRef<E>, keyof OwnProps | "as">;
7
7
  type TextOwnProps = {
8
8
  type?: TextType;
9
+ textAlign?: CSSProperties["textAlign"];
9
10
  };
10
11
  type TextProps<E extends ElementType = "span"> = PolymorphicProps<E, TextOwnProps>;
11
- declare const Text: <E extends ElementType = "span">({ as, type, className, ...props }: TextProps<E>) => import("react").JSX.Element;
12
+ declare const Text: <E extends ElementType = "span">({ as, type, className, textAlign, style, ...props }: TextProps<E>) => import("react").JSX.Element;
12
13
  export { Text, type TextProps, type TextType };
@@ -1,4 +1,4 @@
1
- import { ComponentPropsWithRef, ElementType } from "react";
1
+ import { CSSProperties, ComponentPropsWithRef, ElementType } from "react";
2
2
  import { TypographyStyle } from "@puzzle-ui/theme";
3
3
  type TextType = Omit<TypographyStyle, "headline1" | "headline2" | "headline3" | "headline4">;
4
4
  type PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {
@@ -6,7 +6,8 @@ type PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {
6
6
  } & Omit<ComponentPropsWithRef<E>, keyof OwnProps | "as">;
7
7
  type TextOwnProps = {
8
8
  type?: TextType;
9
+ textAlign?: CSSProperties["textAlign"];
9
10
  };
10
11
  type TextProps<E extends ElementType = "span"> = PolymorphicProps<E, TextOwnProps>;
11
- declare const Text: <E extends ElementType = "span">({ as, type, className, ...props }: TextProps<E>) => import("react").JSX.Element;
12
+ declare const Text: <E extends ElementType = "span">({ as, type, className, textAlign, style, ...props }: TextProps<E>) => import("react").JSX.Element;
12
13
  export { Text, type TextProps, type TextType };
@@ -1,12 +1,16 @@
1
1
  import { cn } from "@puzzle-ui/core";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  // src/components/typography/text.tsx
4
- const Text = ({ as, type = "body1", className, ...props }) => {
4
+ const Text = ({ as, type = "body1", className, textAlign, style, ...props }) => {
5
5
  const Component = as ?? "span";
6
6
  const classes = cn("puzzle-text", `puzzle-typography-${type}`, className);
7
7
  return /* @__PURE__ */ jsx(Component, {
8
8
  ...props,
9
- className: classes
9
+ className: classes,
10
+ style: textAlign === void 0 ? style : {
11
+ ...style,
12
+ textAlign
13
+ }
10
14
  });
11
15
  };
12
16
  export { Text };
@@ -1 +1 @@
1
- {"version":3,"file":"text.js","names":[],"sources":["../../../src/components/typography/text.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { TypographyStyle } from \"@puzzle-ui/theme\";\nimport type { ComponentPropsWithRef, ElementType } from \"react\";\n\ntype TextType = Omit<\n TypographyStyle,\n \"headline1\" | \"headline2\" | \"headline3\" | \"headline4\"\n>;\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype TextOwnProps = {\n type?: TextType;\n};\n\ntype TextProps<E extends ElementType = \"span\"> = PolymorphicProps<\n E,\n TextOwnProps\n>;\n\nconst Text = <E extends ElementType = \"span\">({\n as,\n type = \"body1\",\n className,\n ...props\n}: TextProps<E>) => {\n const Component = as ?? \"span\";\n const classes = cn(\"puzzle-text\", `puzzle-typography-${type}`, className);\n return <Component {...props} className={classes}></Component>;\n};\n\nexport { Text, type TextProps, type TextType };\n"],"mappings":";;;AAsBA,MAAM,QAAwC,EAC5C,IACA,OAAO,SACP,WACA,GAAG,YACe;CAClB,MAAM,YAAY,MAAM;CACxB,MAAM,UAAU,GAAG,eAAe,qBAAqB,QAAQ,SAAS;CACxE,OAAO,oBAAC,WAAD;EAAW,GAAI;EAAO,WAAW;CAAoB,CAAA;AAC9D"}
1
+ {"version":3,"file":"text.js","names":[],"sources":["../../../src/components/typography/text.tsx"],"sourcesContent":["import { cn } from \"@puzzle-ui/core\";\nimport type { TypographyStyle } from \"@puzzle-ui/theme\";\nimport type { ComponentPropsWithRef, CSSProperties, ElementType } from \"react\";\n\ntype TextType = Omit<\n TypographyStyle,\n \"headline1\" | \"headline2\" | \"headline3\" | \"headline4\"\n>;\n\ntype PolymorphicProps<E extends ElementType, OwnProps> = OwnProps & {\n as?: E;\n} & Omit<ComponentPropsWithRef<E>, keyof OwnProps | \"as\">;\n\ntype TextOwnProps = {\n type?: TextType;\n textAlign?: CSSProperties[\"textAlign\"];\n};\n\ntype TextProps<E extends ElementType = \"span\"> = PolymorphicProps<\n E,\n TextOwnProps\n>;\n\nconst Text = <E extends ElementType = \"span\">({\n as,\n type = \"body1\",\n className,\n textAlign,\n style,\n ...props\n}: TextProps<E>) => {\n const Component = as ?? \"span\";\n const classes = cn(\"puzzle-text\", `puzzle-typography-${type}`, className);\n return (\n <Component\n {...props}\n className={classes}\n style={textAlign === undefined ? style : { ...style, textAlign }}\n ></Component>\n );\n};\n\nexport { Text, type TextProps, type TextType };\n"],"mappings":";;;AAuBA,MAAM,QAAwC,EAC5C,IACA,OAAO,SACP,WACA,WACA,OACA,GAAG,YACe;CAClB,MAAM,YAAY,MAAM;CACxB,MAAM,UAAU,GAAG,eAAe,qBAAqB,QAAQ,SAAS;CACxE,OACE,oBAAC,WAAD;EACE,GAAI;EACJ,WAAW;EACX,OAAO,cAAc,KAAA,IAAY,QAAQ;GAAE,GAAG;GAAO;EAAU;CACrD,CAAA;AAEhB"}
@@ -9,6 +9,7 @@ let _puzzle_ui_hooks = require("@puzzle-ui/hooks");
9
9
  let react_dom = require("react-dom");
10
10
  let _puzzle_ui_icons = require("@puzzle-ui/icons");
11
11
  let _puzzle_ui_theme_scope_context = require("@puzzle-ui/theme/scope-context");
12
+ let _puzzle_ui_theme = require("@puzzle-ui/theme");
12
13
  // src/components/utilities/preview/index.tsx
13
14
  const PREVIEW_DEVICES = {
14
15
  mobile: {
@@ -61,7 +62,7 @@ const PreviewBackground = (props) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
61
62
  patternOpacity: .25,
62
63
  ...props
63
64
  });
64
- const Preview = ({ children, className, defaultDevice = "mobile", code, height, align, justify, hideDevices = false }) => {
65
+ const Preview = ({ children, className, defaultDevice = "mobile", code, fit = "content", height, padding = "var(--puzzle-space-8, 2rem)", align = "center", justify = "center", hideDevices = false }) => {
65
66
  const generatedId = (0, react.useId)();
66
67
  const frameRootId = `${generatedId}-root`;
67
68
  const previewTabId = `${generatedId}-tab-preview`;
@@ -73,15 +74,28 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
73
74
  const [frameRoot, setFrameRoot] = (0, react.useState)(null);
74
75
  const [scale, setScale] = (0, react.useState)(1);
75
76
  const [copied, setCopied] = (0, react.useState)(false);
77
+ const [contentHeight, setContentHeight] = (0, react.useState)(PREVIEW_DEVICES.mobile.height);
78
+ const [contentMeasured, setContentMeasured] = (0, react.useState)(false);
76
79
  const containerRef = (0, react.useRef)(null);
80
+ const contentRef = (0, react.useRef)(null);
77
81
  const iframeRef = (0, react.useRef)(null);
78
82
  const copyTimeoutRef = (0, react.useRef)(null);
79
83
  const config = PREVIEW_DEVICES[device];
80
- const frameHeight = height ?? config.height;
84
+ const fitsContent = height === void 0 && fit === "content";
85
+ const frameHeight = height ?? (fitsContent ? contentHeight : config.height);
86
+ const showPlaceholder = fitsContent && !contentMeasured;
81
87
  const hasCode = code !== void 0;
82
88
  const [direction, setDirection] = (0, react.useState)("ltr");
89
+ const [desktopControlsVisible, setDesktopControlsVisible] = (0, react.useState)(true);
83
90
  const sectionRef = (0, react.useRef)(null);
84
91
  const isKeyboardNavigation = (0, react.useRef)(false);
92
+ (0, react.useEffect)(() => {
93
+ const query = window.matchMedia(`(min-width: ${_puzzle_ui_theme.BREAKPOINTS.desktop}px)`);
94
+ const update = () => setDesktopControlsVisible(query.matches);
95
+ update();
96
+ query.addEventListener("change", update);
97
+ return () => query.removeEventListener("change", update);
98
+ }, []);
85
99
  (0, react.useLayoutEffect)(() => {
86
100
  const section = sectionRef.current;
87
101
  if (section) {
@@ -95,7 +109,10 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
95
109
  initialActiveId: activeTab
96
110
  });
97
111
  const deviceFocus = (0, _puzzle_ui_hooks.useRovingFocus)({
98
- items: PREVIEW_DEVICE_ITEMS,
112
+ items: PREVIEW_DEVICE_ITEMS.map((item) => ({
113
+ ...item,
114
+ disabled: item.id === "desktop" && !desktopControlsVisible
115
+ })),
99
116
  dir: direction,
100
117
  initialActiveId: device
101
118
  });
@@ -142,6 +159,7 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
142
159
  targetRoot.style.setProperty("height", "100%", "important");
143
160
  targetRoot.style.setProperty("min-height", "100%", "important");
144
161
  targetRoot.style.setProperty("margin", "0", "important");
162
+ targetRoot.style.setProperty("padding", "0", "important");
145
163
  targetRoot.style.setProperty("overflow-x", "hidden", "important");
146
164
  targetRoot.style.setProperty("overflow-y", "auto", "important");
147
165
  targetRoot.style.setProperty("scrollbar-width", "none", "important");
@@ -153,6 +171,7 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
153
171
  body.style.setProperty("height", "auto", "important");
154
172
  body.style.setProperty("min-height", "100%", "important");
155
173
  body.style.setProperty("margin", "0", "important");
174
+ body.style.setProperty("padding", "0", "important");
156
175
  body.style.setProperty("overflow", "visible", "important");
157
176
  frameDocument.getElementById(frameRootId)?.style.removeProperty("min-height");
158
177
  const scrollbarStyle = frameDocument.createElement("style");
@@ -174,6 +193,7 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
174
193
  frameHead.appendChild(scrollbarStyle);
175
194
  }, [frameRootId]);
176
195
  const updateScale = (0, react.useCallback)((availableWidth) => {
196
+ if (availableWidth <= 0) return;
177
197
  const nextScale = Math.min(1, Math.max(0, availableWidth) / config.width);
178
198
  setScale((current) => Math.abs(current - nextScale) < .001 ? current : nextScale);
179
199
  }, [config.width]);
@@ -228,6 +248,33 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
228
248
  (0, react.useEffect)(() => {
229
249
  initializeFrame();
230
250
  }, [initializeFrame]);
251
+ useIsomorphicLayoutEffect(() => {
252
+ const content = contentRef.current;
253
+ if (!fitsContent || !frameRoot || !content || activeTab !== "preview") return;
254
+ const measure = () => {
255
+ const measuredHeight = Math.ceil(Math.max(content.getBoundingClientRect().height, content.scrollHeight));
256
+ setContentHeight(Math.min(PREVIEW_DEVICES.mobile.height, Math.max(1, measuredHeight)));
257
+ setContentMeasured(true);
258
+ };
259
+ measure();
260
+ const observer = new ResizeObserver(measure);
261
+ observer.observe(content);
262
+ const mutations = new MutationObserver(measure);
263
+ mutations.observe(content, {
264
+ subtree: true,
265
+ childList: true,
266
+ characterData: true,
267
+ attributes: true
268
+ });
269
+ return () => {
270
+ observer.disconnect();
271
+ mutations.disconnect();
272
+ };
273
+ }, [
274
+ activeTab,
275
+ fitsContent,
276
+ frameRoot
277
+ ]);
231
278
  const handleCopyCode = (0, react.useCallback)(async () => {
232
279
  if (code === void 0) return;
233
280
  try {
@@ -251,18 +298,26 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
251
298
  width: config.width,
252
299
  height: frameHeight,
253
300
  transform: `scale(${scale})`,
254
- transformOrigin: "top left"
301
+ transformOrigin: "top left",
302
+ visibility: showPlaceholder ? "hidden" : void 0
255
303
  };
256
304
  const contentStyle = {
257
305
  display: "flex",
258
306
  boxSizing: "border-box",
259
- minHeight: "100vh",
307
+ padding,
308
+ minHeight: fitsContent ? void 0 : "100vh",
260
309
  alignItems: align ? ALIGN_VALUES[align] : void 0,
261
310
  justifyContent: justify ? JUSTIFY_VALUES[justify] : void 0
262
311
  };
263
312
  const viewportStyle = {
264
313
  width: config.width * scale,
265
- aspectRatio: `${config.width} / ${frameHeight}`
314
+ height: showPlaceholder ? void 0 : frameHeight * scale,
315
+ maxHeight: showPlaceholder ? PREVIEW_DEVICES.mobile.height * scale : void 0
316
+ };
317
+ const placeholderStyle = {
318
+ ...contentStyle,
319
+ width: config.width,
320
+ zoom: scale === 1 ? void 0 : scale
266
321
  };
267
322
  const panelProps = {
268
323
  id: panelId,
@@ -313,6 +368,7 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
313
368
  role: "group",
314
369
  "aria-label": "Device size",
315
370
  children: Object.keys(PREVIEW_DEVICES).map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
371
+ "data-device": item,
316
372
  ref: deviceFocus.getItemRef(item),
317
373
  type: "button",
318
374
  className: (0, _puzzle_ui_core.cn)("puzzle-preview__device", device === item && "puzzle-preview__device--active"),
@@ -353,21 +409,33 @@ const Preview = ({ children, className, defaultDevice = "mobile", code, height,
353
409
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
354
410
  className: "puzzle-preview__viewport",
355
411
  style: viewportStyle,
356
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
357
- ref: iframeRef,
358
- className: "puzzle-preview__frame",
359
- srcDoc: createPreviewDocument(frameRootId),
360
- title: `${config.label} component preview`,
361
- onLoad: initializeFrame,
362
- style: frameStyle
363
- }), frameRoot && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_puzzle_ui_theme_scope_context.ThemeScopeProvider, {
364
- scopeId: themeScope?.scopeId ?? null,
365
- theme: themeScope?.theme ?? "system",
366
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
367
- style: contentStyle,
412
+ children: [
413
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("iframe", {
414
+ ref: iframeRef,
415
+ className: "puzzle-preview__frame",
416
+ srcDoc: createPreviewDocument(frameRootId),
417
+ title: `${config.label} component preview`,
418
+ onLoad: initializeFrame,
419
+ style: frameStyle
420
+ }),
421
+ showPlaceholder && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
422
+ className: "puzzle-preview__placeholder",
423
+ style: placeholderStyle,
424
+ "aria-hidden": "true",
425
+ inert: true,
426
+ "data-preview-placeholder": "",
368
427
  children
369
- })
370
- }), frameRoot)]
428
+ }),
429
+ frameRoot && (0, react_dom.createPortal)(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_puzzle_ui_theme_scope_context.ThemeScopeProvider, {
430
+ scopeId: themeScope?.scopeId ?? null,
431
+ theme: themeScope?.theme ?? "system",
432
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
433
+ ref: contentRef,
434
+ style: contentStyle,
435
+ children
436
+ })
437
+ }), frameRoot)
438
+ ]
371
439
  })
372
440
  }), activeTab === "code" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
373
441
  className: "puzzle-preview__code",