@neynar/ui 0.1.3 → 0.2.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.
@@ -11,16 +11,18 @@ import { cn } from "@/lib/utils";
11
11
  * Uses Tailwind CSS 4 with custom CSS properties for theming.
12
12
  * Provides consistent text styling across the entire application.
13
13
  *
14
- * @variant heading - Primary headings for page/section titles (text-lg, font-semibold, leading-tight)
15
- * @variant subheading - Secondary headings for subsections (text-base, font-medium, leading-relaxed)
16
- * @variant body - Standard body text for readable content (text-sm, leading-relaxed)
17
- * @variant bodyEmphasized - Emphasized body text with medium weight for important information (text-sm, font-medium)
18
- * @variant details - Smaller text for details, captions, and descriptions (text-xs, leading-normal)
19
- * @variant field - Text for form fields, labels, and input elements (text-base, leading-normal)
20
- * @variant code - Monospace text for code snippets and technical content (text-base, font-mono)
21
14
  * @variant microcopy - Very small text for fine print, timestamps, and metadata (text-microcopy, leading-tight)
22
- * @variant tableCell - Text optimized for table cell content with proper line height (text-base, leading-normal)
23
- * @variant tableHeader - Text for table headers with medium weight for emphasis (text-base, font-medium)
15
+ * @variant detail - Smaller text for details, captions, and descriptions (text-xs, leading-normal)
16
+ * @variant body - Standard body text for readable content (text-sm, leading-snug)
17
+ * @variant blogBody - Body text for blog posts and long form content (text-lg, leading-loose)
18
+ * @variant paragraphLead - Paragraph lead text for blog posts and long form content (text-lg)
19
+ * @variant eyebrow - Eyebrow text for blog posts and long form content (text-xl)
20
+ * @variant subHeadline - Secondary headings for subsections (text-base, font-medium, leading-relaxed)
21
+ * @variant headline - Primary headings for page/section titles (text-lg, font-semibold, leading-tight)
22
+ * @variant sectionTitle - Section titles (text-2xl, leading-relaxed)
23
+ * @variant pageTitle - Page titles (text-3xl, leading-relaxed)
24
+ * @variant displayTitle - Display titles (text-4xl, leading-snug)
25
+ * @variant heroTitle - Hero titles (text-5xl, leading-snug)
24
26
  *
25
27
  * @see {@link https://cva.style/docs} CVA documentation for variant patterns
26
28
  * @see {@link https://ui.shadcn.com/docs/components/typography} Typography component inspiration
@@ -29,16 +31,19 @@ import { cn } from "@/lib/utils";
29
31
  const typographyVariants = cva("", {
30
32
  variants: {
31
33
  variant: {
32
- heading: "text-lg font-semibold leading-tight",
33
- subheading: "text-base font-medium leading-relaxed",
34
- body: "text-sm leading-relaxed",
35
- bodyEmphasized: "text-sm font-medium leading-relaxed",
36
- details: "text-xs leading-normal",
37
- field: "text-base leading-normal",
38
- code: "text-base font-mono leading-normal",
39
- microcopy: "text-microcopy leading-tight",
40
- tableCell: "text-base leading-normal",
41
- tableHeader: "text-base font-medium leading-normal",
34
+ microcopy: "text-xs",
35
+ detail: "text-sm",
36
+ body: "text-base leading-snug",
37
+ blogBody: "text-lg leading-loose",
38
+ paragraphLead: "text-lg",
39
+ eyebrow: "text-xl",
40
+ subHeadline: "text-2xl",
41
+ headline: "text-3xl",
42
+ sectionTitle: "text-4xl leading-relaxed",
43
+ pageTitle: "text-5xl leading-relaxed",
44
+ displayTitle: "text-6xl leading-snug",
45
+ heroTitle: "text-7xl leading-snug",
46
+ code: "text-base font-mono",
42
47
  },
43
48
  /**
44
49
  * Color variants for different semantic meanings and visual hierarchy
@@ -106,28 +111,35 @@ const typographyVariants = cva("", {
106
111
  },
107
112
  });
108
113
 
114
+ type TypographyVariant =
115
+ | "microcopy"
116
+ | "detail"
117
+ | "body"
118
+ | "blogBody"
119
+ | "paragraphLead"
120
+ | "eyebrow"
121
+ | "subHeadline"
122
+ | "headline"
123
+ | "sectionTitle"
124
+ | "pageTitle"
125
+ | "displayTitle"
126
+ | "heroTitle"
127
+ | "code";
128
+
129
+ type TypographyColor =
130
+ | "default"
131
+ | "muted"
132
+ | "accent"
133
+ | "destructive"
134
+ | "success"
135
+ | "warning";
136
+
109
137
  // eslint-disable-next-line unused-imports/no-unused-vars
110
138
  type TypographyDocsProps = {
111
139
  /** Typography variant that determines text size, weight, and line height @default "body" */
112
- variant?:
113
- | "heading"
114
- | "subheading"
115
- | "body"
116
- | "bodyEmphasized"
117
- | "details"
118
- | "field"
119
- | "code"
120
- | "microcopy"
121
- | "tableCell"
122
- | "tableHeader";
140
+ variant?: TypographyVariant;
123
141
  /** Color variant for semantic meaning and visual hierarchy @default "default" */
124
- color?:
125
- | "default"
126
- | "muted"
127
- | "accent"
128
- | "destructive"
129
- | "success"
130
- | "warning";
142
+ color?: TypographyColor;
131
143
  /** Text alignment within the container @default "left" */
132
144
  align?: "left" | "center" | "right" | "justify";
133
145
  /** Text transformation for stylistic effects */
@@ -161,9 +173,9 @@ type TypographyDocsProps = {
161
173
  */
162
174
  type TypographyBaseProps = {
163
175
  /** Typography variant that determines text size, weight, and line height */
164
- variant?: VariantProps<typeof typographyVariants>["variant"];
176
+ variant?: TypographyVariant;
165
177
  /** Color variant for semantic meaning and visual hierarchy */
166
- color?: VariantProps<typeof typographyVariants>["color"];
178
+ color?: TypographyColor;
167
179
  /** Text alignment within the container */
168
180
  align?: VariantProps<typeof typographyVariants>["align"];
169
181
  /** Text transformation for stylistic effects */
@@ -369,12 +381,12 @@ type H1DocsProps = {
369
381
  } & React.HTMLAttributes<HTMLHeadingElement>;
370
382
 
371
383
  /** Props for H1 heading component */
372
- type H1Props = Omit<TypographyProps, "as" | "variant">;
384
+ type H1Props = Omit<TypographyProps, "as">;
373
385
 
374
386
  /**
375
387
  * H1 - Primary page heading component
376
388
  *
377
- * The main heading for a page or major section. Uses the "heading" variant with h1 semantic element.
389
+ * The main heading for a page or major section. Uses the "displayTitle" variant with h1 semantic element.
378
390
  * Should be used once per page for proper document outline and SEO.
379
391
  *
380
392
  * @example
@@ -400,8 +412,8 @@ type H1Props = Omit<TypographyProps, "as" | "variant">;
400
412
  * @see {@link H2} Secondary heading component
401
413
  * @see {@link Typography} Base typography component
402
414
  */
403
- function H1(props: H1Props) {
404
- return <Typography variant="heading" as="h1" {...props} />;
415
+ function H1({ variant = "displayTitle", weight = "bold", ...props }: H1Props) {
416
+ return <Typography variant={variant} weight={weight} as="h1" {...props} />;
405
417
  }
406
418
 
407
419
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -441,12 +453,12 @@ type H2DocsProps = {
441
453
  } & React.HTMLAttributes<HTMLHeadingElement>;
442
454
 
443
455
  /** Props for H2 heading component */
444
- type H2Props = Omit<TypographyProps, "as" | "variant">;
456
+ type H2Props = Omit<TypographyProps, "as">;
445
457
 
446
458
  /**
447
459
  * H2 - Secondary section heading component
448
460
  *
449
- * Section headings that divide page content into logical groups. Uses the "subheading" variant
461
+ * Section headings that divide page content into logical groups. Uses the "sectionTitle" variant
450
462
  * with h2 semantic element. Essential for creating proper document hierarchy.
451
463
  *
452
464
  * @example
@@ -472,8 +484,8 @@ type H2Props = Omit<TypographyProps, "as" | "variant">;
472
484
  * @see {@link H1} Primary heading component
473
485
  * @see {@link H3} Tertiary heading component
474
486
  */
475
- function H2(props: H2Props) {
476
- return <Typography variant="subheading" as="h2" {...props} />;
487
+ function H2({ variant = "sectionTitle", weight = "bold", ...props }: H2Props) {
488
+ return <Typography variant={variant} weight={weight} as="h2" {...props} />;
477
489
  }
478
490
 
479
491
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -513,12 +525,12 @@ type H3DocsProps = {
513
525
  } & React.HTMLAttributes<HTMLHeadingElement>;
514
526
 
515
527
  /** Props for H3 heading component */
516
- type H3Props = Omit<TypographyProps, "as" | "variant">;
528
+ type H3Props = Omit<TypographyProps, "as">;
517
529
 
518
530
  /**
519
531
  * H3 - Tertiary subsection heading component
520
532
  *
521
- * Subsection headings for further content division. Uses the "subheading" variant
533
+ * Subsection headings for further content division. Uses the "headline" variant
522
534
  * with h3 semantic element for consistent visual hierarchy.
523
535
  *
524
536
  * @example
@@ -538,8 +550,8 @@ type H3Props = Omit<TypographyProps, "as" | "variant">;
538
550
  * - Improves navigation with assistive technologies
539
551
  * - Supports table of contents generation
540
552
  */
541
- function H3(props: H3Props) {
542
- return <Typography variant="subheading" as="h3" {...props} />;
553
+ function H3({ variant = "headline", weight = "bold", ...props }: H3Props) {
554
+ return <Typography variant={variant} weight={weight} as="h3" {...props} />;
543
555
  }
544
556
 
545
557
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -579,12 +591,12 @@ type H4DocsProps = {
579
591
  } & React.HTMLAttributes<HTMLHeadingElement>;
580
592
 
581
593
  /** Props for H4 heading component */
582
- type H4Props = Omit<TypographyProps, "as" | "variant">;
594
+ type H4Props = Omit<TypographyProps, "as">;
583
595
 
584
596
  /**
585
597
  * H4 - Minor heading component for detailed sections
586
598
  *
587
- * Minor headings for detailed content organization. Uses "bodyEmphasized" variant
599
+ * Minor headings for detailed content organization. Uses "subHeadline" variant
588
600
  * with h4 semantic element for subtle but distinct hierarchy.
589
601
  *
590
602
  * @example
@@ -601,8 +613,8 @@ type H4Props = Omit<TypographyProps, "as" | "variant">;
601
613
  * - Provides fine-grained content organization
602
614
  * - Supports screen reader document navigation
603
615
  */
604
- function H4(props: H4Props) {
605
- return <Typography variant="bodyEmphasized" as="h4" {...props} />;
616
+ function H4({ variant = "subHeadline", weight = "bold", ...props }: H4Props) {
617
+ return <Typography variant={variant} weight={weight} as="h4" {...props} />;
606
618
  }
607
619
 
608
620
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -642,12 +654,12 @@ type H5DocsProps = {
642
654
  } & React.HTMLAttributes<HTMLHeadingElement>;
643
655
 
644
656
  /** Props for H5 heading component */
645
- type H5Props = Omit<TypographyProps, "as" | "variant">;
657
+ type H5Props = Omit<TypographyProps, "as">;
646
658
 
647
659
  /**
648
660
  * H5 - Small heading component for micro-sections
649
661
  *
650
- * Small headings for very specific content divisions. Uses "bodyEmphasized" variant
662
+ * Small headings for very specific content divisions. Uses "eyebrow" variant
651
663
  * with h5 semantic element.
652
664
  *
653
665
  * @example
@@ -659,8 +671,8 @@ type H5Props = Omit<TypographyProps, "as" | "variant">;
659
671
  * <H5 weight="semibold">Step 1: Setup</H5>
660
672
  * ```
661
673
  */
662
- function H5(props: H5Props) {
663
- return <Typography variant="bodyEmphasized" as="h5" {...props} />;
674
+ function H5({ variant = "eyebrow", weight = "bold", ...props }: H5Props) {
675
+ return <Typography variant={variant} weight={weight} as="h5" {...props} />;
664
676
  }
665
677
 
666
678
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -700,7 +712,7 @@ type H6DocsProps = {
700
712
  } & React.HTMLAttributes<HTMLHeadingElement>;
701
713
 
702
714
  /** Props for H6 heading component */
703
- type H6Props = Omit<TypographyProps, "as" | "variant">;
715
+ type H6Props = Omit<TypographyProps, "as">;
704
716
 
705
717
  /**
706
718
  * H6 - Smallest heading component for minimal emphasis
@@ -717,8 +729,8 @@ type H6Props = Omit<TypographyProps, "as" | "variant">;
717
729
  * <H6 color="muted">Technical Details</H6>
718
730
  * ```
719
731
  */
720
- function H6(props: H6Props) {
721
- return <Typography variant="details" as="h6" {...props} />;
732
+ function H6({ variant = "body", weight = "bold", ...props }: H6Props) {
733
+ return <Typography variant={variant} weight={weight} as="h6" {...props} />;
722
734
  }
723
735
 
724
736
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -758,7 +770,7 @@ type PDocsProps = {
758
770
  } & React.HTMLAttributes<HTMLParagraphElement>;
759
771
 
760
772
  /** Props for P paragraph component */
761
- type PProps = Omit<TypographyProps, "as" | "variant">;
773
+ type PProps = Omit<TypographyProps, "as">;
762
774
 
763
775
  /**
764
776
  * P - Paragraph component for body text content
@@ -791,7 +803,7 @@ type PProps = Omit<TypographyProps, "as" | "variant">;
791
803
  * @see {@link Typography} Base typography component
792
804
  */
793
805
  function P(props: PProps) {
794
- return <Typography variant="body" as="p" {...props} />;
806
+ return <Typography as="p" {...props} />;
795
807
  }
796
808
 
797
809
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -989,7 +1001,7 @@ type SmallDocsProps = {
989
1001
  } & React.HTMLAttributes<HTMLElement>;
990
1002
 
991
1003
  /** Props for Small component */
992
- type SmallProps = Omit<TypographyProps, "as" | "variant">;
1004
+ type SmallProps = Omit<TypographyProps, "as">;
993
1005
 
994
1006
  /**
995
1007
  * Small - Fine print component for supplementary information
@@ -1020,8 +1032,8 @@ type SmallProps = Omit<TypographyProps, "as" | "variant">;
1020
1032
  * - Maintains sufficient contrast for readability
1021
1033
  * - Works well with form help text and descriptions
1022
1034
  */
1023
- function Small(props: SmallProps) {
1024
- return <Typography variant="microcopy" as="small" {...props} />;
1035
+ function Small({ variant = "detail", ...props }: SmallProps) {
1036
+ return <Typography variant={variant} as="small" {...props} />;
1025
1037
  }
1026
1038
 
1027
1039
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -1061,7 +1073,7 @@ type StrongDocsProps = {
1061
1073
  } & React.HTMLAttributes<HTMLElement>;
1062
1074
 
1063
1075
  /** Props for Strong component */
1064
- type StrongProps = Omit<TypographyProps, "as" | "variant">;
1076
+ type StrongProps = Omit<TypographyProps, "as">;
1065
1077
 
1066
1078
  /**
1067
1079
  * Strong - Emphasized text component for important content
@@ -1093,7 +1105,7 @@ type StrongProps = Omit<TypographyProps, "as" | "variant">;
1093
1105
  * - Maintains proper emphasis hierarchy in content
1094
1106
  */
1095
1107
  function Strong(props: StrongProps) {
1096
- return <Typography variant="bodyEmphasized" as="strong" {...props} />;
1108
+ return <Typography weight="bold" as="strong" {...props} />;
1097
1109
  }
1098
1110
 
1099
1111
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -1133,10 +1145,7 @@ type LeadDocsProps = {
1133
1145
  } & React.HTMLAttributes<HTMLParagraphElement>;
1134
1146
 
1135
1147
  /** Props for Lead component */
1136
- type LeadProps = Omit<TypographyProps, "as" | "variant" | "color"> & {
1137
- /** Color override for lead text @default "muted" */
1138
- color?: TypographyProps["color"];
1139
- };
1148
+ type LeadProps = Omit<TypographyProps, "as">;
1140
1149
 
1141
1150
  /**
1142
1151
  * Lead - Introductory paragraph component for article openings
@@ -1169,8 +1178,12 @@ type LeadProps = Omit<TypographyProps, "as" | "variant" | "color"> & {
1169
1178
  * - Larger text size improves readability for introductory content
1170
1179
  * - Maintains proper document flow and structure
1171
1180
  */
1172
- function Lead({ color = "muted", ...props }: LeadProps) {
1173
- return <Typography variant="subheading" as="p" color={color} {...props} />;
1181
+ function Lead({
1182
+ variant = "paragraphLead",
1183
+ color = "muted",
1184
+ ...props
1185
+ }: LeadProps) {
1186
+ return <Typography variant={variant} as="p" color={color} {...props} />;
1174
1187
  }
1175
1188
 
1176
1189
  // eslint-disable-next-line unused-imports/no-unused-vars
@@ -1224,7 +1237,7 @@ type ADocsProps = {
1224
1237
  } & React.AnchorHTMLAttributes<HTMLAnchorElement>;
1225
1238
 
1226
1239
  /** Props for A anchor component */
1227
- type AProps = Omit<TypographyProps, "as" | "variant"> & {
1240
+ type AProps = Omit<TypographyProps, "as"> & {
1228
1241
  /** Link destination URL */
1229
1242
  href?: string;
1230
1243
  } & React.AnchorHTMLAttributes<HTMLAnchorElement>;
@@ -1274,7 +1287,6 @@ type AProps = Omit<TypographyProps, "as" | "variant"> & {
1274
1287
  function A({ href, asChild = false, className, ...props }: AProps) {
1275
1288
  return (
1276
1289
  <Typography
1277
- variant="body"
1278
1290
  as={asChild ? undefined : "a"}
1279
1291
  asChild={asChild}
1280
1292
  className={cn(
@@ -1324,7 +1336,7 @@ type BlockquoteDocsProps = {
1324
1336
  } & React.HTMLAttributes<HTMLQuoteElement>;
1325
1337
 
1326
1338
  /** Props for Blockquote component */
1327
- type BlockquoteProps = Omit<TypographyProps, "as" | "variant">;
1339
+ type BlockquoteProps = Omit<TypographyProps, "as">;
1328
1340
 
1329
1341
  /**
1330
1342
  * Blockquote - Quoted text component for citations and excerpts
@@ -1367,7 +1379,6 @@ type BlockquoteProps = Omit<TypographyProps, "as" | "variant">;
1367
1379
  function Blockquote({ className, ...props }: BlockquoteProps) {
1368
1380
  return (
1369
1381
  <Typography
1370
- variant="body"
1371
1382
  as="blockquote"
1372
1383
  italic
1373
1384
  className={cn("border-l-4 border-border pl-4 my-2", className)}
@@ -7,6 +7,10 @@
7
7
 
8
8
  :root {
9
9
  --radius: 0.625rem;
10
+
11
+ /* Neynar Colors */
12
+ --neynar-surface-base-background: oklch(from #eeeeee l c h);
13
+
10
14
  /* Map Figma colors to shadcn semantic tokens */
11
15
  --background: oklch(from #ffffff l c h); /* Surface/Body */
12
16
  --foreground: oklch(from #000000 l c h); /* Text/Content/Headers */
@@ -53,11 +57,14 @@
53
57
  }
54
58
 
55
59
  .dark {
60
+ /* Neynar Colors */
61
+ --neynar-surface-base-background: oklch(from #161517 l c h);
62
+
56
63
  /* Dark mode using actual Figma-defined dark mode colors */
57
- --background: oklch(from #161517 l c h); /* Surface/Body Dark */
58
- --foreground: oklch(from #ffffff l c h); /* Text/UI/Active Dark */
59
- --card: oklch(from #222222 l c h); /* Surface/Feature Neutral Dark */
60
- --card-foreground: oklch(from #ffffff l c h); /* Text/UI/Active Dark */
64
+ --background: oklch(from #222222 l c h); /* Surface/Body Dark */
65
+ --foreground: oklch(from #dddddd l c h); /* Text/UI/Active Dark */
66
+ --card: oklch(from #2d2d2d l c h); /* Surface/Feature Neutral Dark */
67
+ --card-foreground: oklch(from #dddddd l c h); /* Text/UI/Active Dark */
61
68
  --popover: oklch(from #222222 l c h); /* Surface/Body Dark */
62
69
  --popover-foreground: oklch(from #ffffff l c h); /* Text/UI/Active Dark */
63
70
  --primary: oklch(from #7f62c6 l c h); /* Farcaster Purple */
@@ -101,6 +108,8 @@
101
108
  }
102
109
 
103
110
  @theme inline {
111
+ --color-neynar-surface-base-background: var(--neynar-surface-base-background);
112
+
104
113
  --color-background: var(--background);
105
114
  --color-foreground: var(--foreground);
106
115
  --color-card: var(--card);
@@ -143,11 +152,25 @@
143
152
  --color-sidebar-ring: var(--sidebar-ring);
144
153
 
145
154
  /* Override Tailwind's default fontSize scale to match design system */
146
- --text-xs: 0.75rem; /* 12px - Details */
147
- --text-sm: 0.875rem; /* 14px - Body */
148
- --text-base: 1.0625rem; /* 17px - Sub Headings, Fields, Code, Table */
149
- --text-lg: 1.25rem; /* 20px - Headings */
150
- --text-microcopy: 0.625rem; /* 10px - Microcopy (custom) */
155
+ --text-xs: 0.625rem; /* 10px - Microcopy */
156
+ --text-sm: 0.8125rem; /* 13px - Details */
157
+ --text-base: 0.9375rem; /* 15px - Body */
158
+ --text-lg: 1.0625rem; /* 17px - Paragraph Lead, Blog Body */
159
+ --text-xl: 1.25rem; /* 20px - Headings */
160
+ --text-2xl: 1.375rem; /* 22px - Paragraph Lead, Blog Body */
161
+ --text-3xl: 2.25rem; /* 36px - Headline */
162
+ --text-4xl: 2.8125rem; /* 45px - Section Title */
163
+ --text-5xl: 3.5rem; /* 56px - Page Title */
164
+ --text-6xl: 4.5rem; /* 72px - Display Title */
165
+ --text-7xl: 5.625rem; /* 90px - Hero Title */
166
+ /* --text-8xl: 6.75rem; */
167
+ /* --text-9xl: 8.25rem; */
168
+
169
+ /* --leading-tight: 1.1; */
170
+ --leading-snug: 1.1;
171
+ --leading-normal: 1.2;
172
+ --leading-relaxed: 1.4;
173
+ --leading-loose: 1.5;
151
174
  }
152
175
 
153
176
  @layer base {
@@ -155,6 +178,6 @@
155
178
  @apply border-border outline-ring/50;
156
179
  }
157
180
  body {
158
- @apply bg-background text-foreground;
181
+ @apply bg-neynar-surface-base-background text-foreground;
159
182
  }
160
183
  }