{
  "$schema": "https://pdfx.akashpise.dev/schema/registry-item.json",
  "name": "heading",
  "type": "registry:ui",
  "title": "Heading",
  "description": "PDF heading component with 6 levels (h1-h6)",
  "files": [
    {
      "path": "components/pdfx/heading/pdfx-heading.tsx",
      "content": "import { StyleSheet, Text } from '@react-pdf/renderer';\nimport type { Style } from '@react-pdf/types';\nimport { usePdfxTheme, useSafeMemo } from '../lib/pdfx-theme-context';\nimport type React from 'react';\ntype PdfxTheme = ReturnType<typeof usePdfxTheme>;\n\nexport type HeadingWeight = 'normal' | 'medium' | 'semibold' | 'bold';\nexport type HeadingTracking = 'tighter' | 'tight' | 'normal' | 'wide' | 'wider';\n\n/**\n * PDF heading mapped to h1–h6 font sizes from the theme.\n * Props - `level` | `align` | `color` | `transform` | `weight` | `tracking` | `noMargin` | `keepWithNext` | `children` | `style`\n * @see {@link HeadingProps}\n */\nexport interface HeadingProps {\n  /** Custom styles to merge with component defaults */\n  style?: Style;\n  /** Content to render */\n  children: React.ReactNode;\n  /**\n   * @default 1\n   */\n  level?: 1 | 2 | 3 | 4 | 5 | 6;\n  /**\n   * @default 'left'\n   */\n  align?: 'left' | 'center' | 'right';\n  color?: string;\n  transform?: 'uppercase' | 'lowercase' | 'capitalize';\n  /**\n   * @default 'bold'\n   */\n  weight?: HeadingWeight;\n  /**\n   * @default 'normal'\n   */\n  tracking?: HeadingTracking;\n  /**\n   * @default false\n   */\n  noMargin?: boolean;\n  keepWithNext?: boolean;\n}\n\nconst THEME_COLOR_KEYS = ['foreground','muted','mutedForeground','primary','primaryForeground','accent','destructive','success','warning','info'] as const;\nfunction resolveColor(value: string, colors: Record<string, string>): string {\n  return THEME_COLOR_KEYS.includes(value as (typeof THEME_COLOR_KEYS)[number]) ? colors[value] : value;\n}\nfunction createHeadingStyles(t: PdfxTheme) {\n  const { heading } = t.typography;\n  const { spacing, fontWeights, letterSpacing } = t.primitives;\n  const { sectionGap, componentGap, paragraphGap } = t.spacing;\n  const base = {\n    fontFamily: heading.fontFamily,\n    fontWeight: fontWeights.bold,\n    lineHeight: heading.lineHeight,\n    color: t.colors.foreground,\n  };\n  return StyleSheet.create({\n    h1: {\n      ...base,\n      fontSize: heading.fontSize.h1,\n      marginTop: spacing[0],\n      marginBottom: paragraphGap,\n    },\n    h2: {\n      ...base,\n      fontSize: heading.fontSize.h2,\n      marginTop: sectionGap,\n      marginBottom: paragraphGap,\n    },\n    h3: {\n      ...base,\n      fontSize: heading.fontSize.h3,\n      marginTop: componentGap,\n      marginBottom: paragraphGap,\n    },\n    h4: {\n      ...base,\n      fontSize: heading.fontSize.h4,\n      marginTop: paragraphGap,\n      marginBottom: paragraphGap,\n    },\n    h5: {\n      ...base,\n      fontSize: heading.fontSize.h5,\n      marginTop: paragraphGap,\n      marginBottom: spacing[1],\n    },\n    h6: {\n      ...base,\n      fontSize: heading.fontSize.h6,\n      marginTop: paragraphGap,\n      marginBottom: spacing[1],\n    },\n    weightNormal: { fontWeight: fontWeights.regular },\n    weightMedium: { fontWeight: fontWeights.medium },\n    weightSemibold: { fontWeight: fontWeights.semibold },\n    weightBold: { fontWeight: fontWeights.bold },\n    trackingTighter: { letterSpacing: letterSpacing.tight * 15 },\n    trackingTight: { letterSpacing: letterSpacing.tight * 10 },\n    trackingNormal: { letterSpacing: letterSpacing.normal },\n    trackingWide: { letterSpacing: letterSpacing.wide * 10 },\n    trackingWider: { letterSpacing: letterSpacing.wider * 10 },\n    uppercase: { textTransform: 'uppercase', letterSpacing: letterSpacing.wider * 10 },\n    lowercase: { textTransform: 'lowercase' },\n    capitalize: { textTransform: 'capitalize' },\n    noMargin: { marginTop: 0, marginBottom: 0 },\n  });\n}\n\nexport function Heading({\n  level = 1,\n  align,\n  color,\n  transform,\n  weight,\n  tracking,\n  noMargin,\n  keepWithNext = true,\n  children,\n  style,\n}: HeadingProps) {\n  const theme = usePdfxTheme();\n  const styles = useSafeMemo(() => createHeadingStyles(theme), [theme]);\n  const safeLevel = Math.min(Math.max(Math.round(level), 1), 6) as 1 | 2 | 3 | 4 | 5 | 6;\n  const weightMap = {\n    normal: styles.weightNormal,\n    medium: styles.weightMedium,\n    semibold: styles.weightSemibold,\n    bold: styles.weightBold,\n  };\n  const trackingMap = {\n    tighter: styles.trackingTighter,\n    tight: styles.trackingTight,\n    normal: styles.trackingNormal,\n    wide: styles.trackingWide,\n    wider: styles.trackingWider,\n  };\n  const transformMap = {\n    uppercase: styles.uppercase,\n    lowercase: styles.lowercase,\n    capitalize: styles.capitalize,\n  };\n  const styleArray: Style[] = [styles[`h${safeLevel}` as keyof typeof styles] as Style];\n  if (weight && weight in weightMap) styleArray.push(weightMap[weight]);\n  if (tracking && tracking in trackingMap) styleArray.push(trackingMap[tracking]);\n  if (transform && transform in transformMap)\n    styleArray.push(transformMap[transform as keyof typeof transformMap]);\n  if (noMargin) styleArray.push(styles.noMargin);\n  const semantic = {} as Style;\n  if (align) semantic.textAlign = align;\n  if (color) semantic.color = resolveColor(color, theme.colors);\n  if (Object.keys(semantic).length > 0) styleArray.push(semantic);\n  if (style) styleArray.push(...[style].flat());\n  return (\n    <Text style={styleArray} minPresenceAhead={keepWithNext ? 80 : undefined}>\n      {children}\n    </Text>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "dependencies": [
    "@react-pdf/renderer"
  ],
  "registryDependencies": [
    "theme"
  ]
}