sheerly 0.0.1 → 0.0.2

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 (90) hide show
  1. package/lib/accordion.d.ts +13 -4
  2. package/lib/alert.d.ts +22 -7
  3. package/lib/avatar.css +1 -1
  4. package/lib/avatar.d.ts +21 -8
  5. package/lib/badge.d.ts +14 -4
  6. package/lib/breadcrumb.d.ts +18 -3
  7. package/lib/button.css +1 -1
  8. package/lib/button.d.ts +13 -4
  9. package/lib/card.d.ts +32 -12
  10. package/lib/carousel.d.ts +13 -7
  11. package/lib/checkbox.d.ts +6 -0
  12. package/lib/dialog.d.ts +20 -8
  13. package/lib/dropdown-menu.d.ts +30 -13
  14. package/lib/hover-card.d.ts +15 -6
  15. package/lib/index.css +1 -1
  16. package/lib/index.d.ts +1 -1
  17. package/lib/index.js +245 -237
  18. package/lib/input.css +1 -1
  19. package/lib/input.d.ts +6 -0
  20. package/lib/kbd.d.ts +10 -3
  21. package/lib/label.css +1 -1
  22. package/lib/label.d.ts +6 -0
  23. package/lib/pagination.d.ts +16 -2
  24. package/lib/popover.d.ts +15 -6
  25. package/lib/progress.d.ts +6 -0
  26. package/lib/radio.d.ts +13 -3
  27. package/lib/scrollbar.css +1 -0
  28. package/lib/scrollbar.d.ts +17 -0
  29. package/lib/select.css +1 -1
  30. package/lib/select.d.ts +6 -0
  31. package/lib/separator.d.ts +14 -4
  32. package/lib/sheet.d.ts +19 -6
  33. package/lib/skeleton.d.ts +12 -3
  34. package/lib/slider.d.ts +6 -0
  35. package/lib/spinner.d.ts +10 -4
  36. package/lib/switch.d.ts +6 -0
  37. package/lib/table.css +1 -1
  38. package/lib/table.d.ts +14 -3
  39. package/lib/tabs.d.ts +31 -8
  40. package/lib/textarea.d.ts +6 -0
  41. package/lib/toggle.d.ts +7 -0
  42. package/lib/tooltip.d.ts +15 -6
  43. package/lib/typography.d.ts +12 -4
  44. package/lib/utils/polymorphic.d.ts +14 -0
  45. package/package.json +12 -12
  46. package/src/accordion.tsx +20 -6
  47. package/src/alert.tsx +52 -14
  48. package/src/avatar.css +0 -1
  49. package/src/avatar.tsx +44 -15
  50. package/src/badge.tsx +34 -16
  51. package/src/breadcrumb.tsx +32 -8
  52. package/src/button.css +1 -0
  53. package/src/button.tsx +44 -27
  54. package/src/card.tsx +82 -23
  55. package/src/carousel.tsx +28 -11
  56. package/src/checkbox.tsx +7 -1
  57. package/src/dialog.tsx +55 -16
  58. package/src/dropdown-menu.tsx +94 -25
  59. package/src/hover-card.tsx +28 -9
  60. package/src/index.css +1 -0
  61. package/src/index.ts +1 -1
  62. package/src/input.css +1 -0
  63. package/src/input.tsx +7 -1
  64. package/src/kbd.tsx +17 -5
  65. package/src/label.css +1 -0
  66. package/src/label.tsx +7 -1
  67. package/src/pagination.tsx +23 -10
  68. package/src/popover.tsx +28 -9
  69. package/src/progress.tsx +7 -1
  70. package/src/radio.tsx +20 -5
  71. package/src/scrollbar.css +56 -0
  72. package/src/scrollbar.tsx +28 -0
  73. package/src/select.css +24 -0
  74. package/src/select.tsx +7 -1
  75. package/src/separator.tsx +23 -7
  76. package/src/sheet.tsx +53 -13
  77. package/src/skeleton.tsx +19 -5
  78. package/src/slider.tsx +7 -1
  79. package/src/spinner.tsx +21 -8
  80. package/src/switch.tsx +7 -1
  81. package/src/table.css +0 -1
  82. package/src/table.tsx +21 -5
  83. package/src/tabs.tsx +50 -17
  84. package/src/textarea.tsx +7 -1
  85. package/src/toggle.tsx +8 -1
  86. package/src/tooltip.tsx +28 -9
  87. package/src/typography.tsx +19 -5
  88. package/src/utils/polymorphic.ts +19 -0
  89. /package/lib/{cn.d.ts → utils/cn.d.ts} +0 -0
  90. /package/src/{cn.ts → utils/cn.ts} +0 -0
package/src/sheet.tsx CHANGED
@@ -1,5 +1,6 @@
1
- import type { ButtonHTMLAttributes, DialogHTMLAttributes, HTMLAttributes } from 'react'
2
- import { cn } from './cn'
1
+ import type { ButtonHTMLAttributes, DialogHTMLAttributes, ElementType } from 'react'
2
+ import { cn } from './utils/cn'
3
+ import type { PolymorphicProps } from './utils/polymorphic'
3
4
 
4
5
  export interface SheetProps extends DialogHTMLAttributes<HTMLDialogElement> {
5
6
  'data-side'?: 'right' | 'left' | 'top' | 'bottom'
@@ -9,32 +10,71 @@ export interface SheetProps extends DialogHTMLAttributes<HTMLDialogElement> {
9
10
  * Native <dialog> that slides in from an edge. Open via invoker command
10
11
  * (`command="show-modal"`) or `.showModal()`. Add `closedby="any"` for
11
12
  * light-dismiss.
13
+ *
14
+ * @example
15
+ * <button commandfor="s" command="show-modal">Open</button>
16
+ * <Sheet id="s" data-side="right" closedby="any">
17
+ * <SheetHeader><SheetTitle>Filters</SheetTitle></SheetHeader>
18
+ * <SheetBody>…</SheetBody>
19
+ * </Sheet>
12
20
  */
13
21
  export function Sheet({ className, ...props }: SheetProps) {
14
22
  return <dialog className={cn('sheerly-sheet', className)} {...props} />
15
23
  }
16
24
 
17
- export function SheetHeader({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
18
- return <div className={cn('sheerly-sheet-header', className)} {...props} />
25
+ export type SheetHeaderProps<T extends ElementType = 'div'> = PolymorphicProps<T>
26
+
27
+ export function SheetHeader<T extends ElementType = 'div'>({
28
+ as,
29
+ className,
30
+ ...props
31
+ }: SheetHeaderProps<T>) {
32
+ const Tag = as ?? 'div'
33
+ return <Tag className={cn('sheerly-sheet-header', className)} {...props} />
19
34
  }
20
35
 
21
- export function SheetTitle({ className, ...props }: HTMLAttributes<HTMLHeadingElement>) {
22
- return <h3 className={cn('sheerly-sheet-title', className)} {...props} />
36
+ export type SheetTitleProps<T extends ElementType = 'h3'> = PolymorphicProps<T>
37
+
38
+ export function SheetTitle<T extends ElementType = 'h3'>({
39
+ as,
40
+ className,
41
+ ...props
42
+ }: SheetTitleProps<T>) {
43
+ const Tag = as ?? 'h3'
44
+ return <Tag className={cn('sheerly-sheet-title', className)} {...props} />
23
45
  }
24
46
 
25
- export function SheetDescription({
47
+ export type SheetDescriptionProps<T extends ElementType = 'p'> = PolymorphicProps<T>
48
+
49
+ export function SheetDescription<T extends ElementType = 'p'>({
50
+ as,
26
51
  className,
27
52
  ...props
28
- }: HTMLAttributes<HTMLParagraphElement>) {
29
- return <p className={cn('sheerly-sheet-description', className)} {...props} />
53
+ }: SheetDescriptionProps<T>) {
54
+ const Tag = as ?? 'p'
55
+ return <Tag className={cn('sheerly-sheet-description', className)} {...props} />
30
56
  }
31
57
 
32
- export function SheetBody({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
33
- return <div className={cn('sheerly-sheet-body', className)} {...props} />
58
+ export type SheetBodyProps<T extends ElementType = 'div'> = PolymorphicProps<T>
59
+
60
+ export function SheetBody<T extends ElementType = 'div'>({
61
+ as,
62
+ className,
63
+ ...props
64
+ }: SheetBodyProps<T>) {
65
+ const Tag = as ?? 'div'
66
+ return <Tag className={cn('sheerly-sheet-body', className)} {...props} />
34
67
  }
35
68
 
36
- export function SheetFooter({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
37
- return <div className={cn('sheerly-sheet-footer', className)} {...props} />
69
+ export type SheetFooterProps<T extends ElementType = 'div'> = PolymorphicProps<T>
70
+
71
+ export function SheetFooter<T extends ElementType = 'div'>({
72
+ as,
73
+ className,
74
+ ...props
75
+ }: SheetFooterProps<T>) {
76
+ const Tag = as ?? 'div'
77
+ return <Tag className={cn('sheerly-sheet-footer', className)} {...props} />
38
78
  }
39
79
 
40
80
  export function SheetClose({
package/src/skeleton.tsx CHANGED
@@ -1,8 +1,22 @@
1
- import type { HTMLAttributes } from 'react'
2
- import { cn } from './cn'
1
+ import type { ElementType } from 'react'
2
+ import { cn } from './utils/cn'
3
+ import type { PolymorphicProps } from './utils/polymorphic'
3
4
 
4
- export type SkeletonProps = HTMLAttributes<HTMLDivElement>
5
+ export type SkeletonProps<T extends ElementType = 'div'> = PolymorphicProps<T>
5
6
 
6
- export function Skeleton({ className, ...props }: SkeletonProps) {
7
- return <div className={cn('sheerly-skeleton', className)} {...props} />
7
+ /**
8
+ * A pulsing placeholder. Set width/height/border-radius inline.
9
+ *
10
+ * Polymorphic: pass `as` to change the rendered tag (defaults to `div`).
11
+ *
12
+ * @example
13
+ * <Skeleton style={{ width: 200, height: 20, borderRadius: 6 }} />
14
+ */
15
+ export function Skeleton<T extends ElementType = 'div'>({
16
+ as,
17
+ className,
18
+ ...props
19
+ }: SkeletonProps<T>) {
20
+ const Tag = as ?? 'div'
21
+ return <Tag className={cn('sheerly-skeleton', className)} {...props} />
8
22
  }
package/src/slider.tsx CHANGED
@@ -1,8 +1,14 @@
1
1
  import type { InputHTMLAttributes } from 'react'
2
- import { cn } from './cn'
2
+ import { cn } from './utils/cn'
3
3
 
4
4
  export type SliderProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'type'>
5
5
 
6
+ /**
7
+ * A range `<input>`. Set `min` / `max` / `step` / `value`.
8
+ *
9
+ * @example
10
+ * <Slider min={0} max={100} defaultValue={50} />
11
+ */
6
12
  export function Slider({ className, ...props }: SliderProps) {
7
13
  return <input type="range" className={cn('sheerly-slider', className)} {...props} />
8
14
  }
package/src/spinner.tsx CHANGED
@@ -1,24 +1,37 @@
1
- import type { HTMLAttributes } from 'react'
2
- import { cn } from './cn'
1
+ import type { ElementType } from 'react'
2
+ import { cn } from './utils/cn'
3
+ import type { PolymorphicProps } from './utils/polymorphic'
3
4
 
4
- export interface SpinnerProps extends HTMLAttributes<HTMLSpanElement> {
5
- 'data-size'?: 'sm' | 'default' | 'md' | 'lg'
6
- }
5
+ export type SpinnerProps<T extends ElementType = 'span'> = PolymorphicProps<
6
+ T,
7
+ { 'data-size'?: 'sm' | 'default' | 'md' | 'lg' }
8
+ >
7
9
 
8
10
  /**
9
11
  * Loading spinner. The glyph is embedded in CSS (masked ::before), so no SVG
10
12
  * child is needed — this renders a bare <span>. It inherits the current text
11
13
  * color. Pass an <svg> child if you prefer to ship your own icon.
14
+ *
15
+ * Polymorphic: pass `as` to change the rendered tag (defaults to `span`).
16
+ *
17
+ * @example
18
+ * <Spinner data-size="lg" />
12
19
  */
13
- export function Spinner({ className, children, ...props }: SpinnerProps) {
20
+ export function Spinner<T extends ElementType = 'span'>({
21
+ as,
22
+ className,
23
+ children,
24
+ ...props
25
+ }: SpinnerProps<T>) {
26
+ const Tag = as ?? 'span'
14
27
  return (
15
- <span
28
+ <Tag
16
29
  className={cn('sheerly-spinner', className)}
17
30
  role="status"
18
31
  aria-label="Loading"
19
32
  {...props}
20
33
  >
21
34
  {children}
22
- </span>
35
+ </Tag>
23
36
  )
24
37
  }
package/src/switch.tsx CHANGED
@@ -1,11 +1,17 @@
1
1
  import type { InputHTMLAttributes } from 'react'
2
- import { cn } from './cn'
2
+ import { cn } from './utils/cn'
3
3
 
4
4
  export interface SwitchProps
5
5
  extends Omit<InputHTMLAttributes<HTMLInputElement>, 'type' | 'role'> {
6
6
  'data-size'?: 'default' | 'sm'
7
7
  }
8
8
 
9
+ /**
10
+ * A toggle switch (checkbox with `role="switch"`).
11
+ *
12
+ * @example
13
+ * <Switch defaultChecked />
14
+ */
9
15
  export function Switch({ className, ...props }: SwitchProps) {
10
16
  return (
11
17
  <input
package/src/table.css CHANGED
@@ -1,6 +1,5 @@
1
1
  /* Wrapper enabling horizontal scroll on overflow */
2
2
  .sheerly-table-container {
3
- position: relative;
4
3
  width: 100%;
5
4
  overflow-x: auto;
6
5
  }
package/src/table.tsx CHANGED
@@ -1,14 +1,30 @@
1
- import type { HTMLAttributes, TableHTMLAttributes } from 'react'
2
- import { cn } from './cn'
1
+ import type { ElementType, TableHTMLAttributes } from 'react'
2
+ import { cn } from './utils/cn'
3
+ import type { PolymorphicProps } from './utils/polymorphic'
3
4
 
4
- export type TableContainerProps = HTMLAttributes<HTMLDivElement>
5
+ export type TableContainerProps<T extends ElementType = 'div'> = PolymorphicProps<T>
5
6
 
6
- export function TableContainer({ className, ...props }: TableContainerProps) {
7
- return <div className={cn('sheerly-table-container', className)} {...props} />
7
+ export function TableContainer<T extends ElementType = 'div'>({
8
+ as,
9
+ className,
10
+ ...props
11
+ }: TableContainerProps<T>) {
12
+ const Tag = as ?? 'div'
13
+ return <Tag className={cn('sheerly-table-container', className)} {...props} />
8
14
  }
9
15
 
10
16
  export type TableProps = TableHTMLAttributes<HTMLTableElement>
11
17
 
18
+ /**
19
+ * A data table. Use semantic HTML inside (no classes on inner elements); wrap
20
+ * in a <TableContainer> for horizontal overflow scroll.
21
+ *
22
+ * @example
23
+ * <Table>
24
+ * <thead><tr><th>Name</th></tr></thead>
25
+ * <tbody><tr><td>Ada</td></tr></tbody>
26
+ * </Table>
27
+ */
12
28
  export function Table({ className, ...props }: TableProps) {
13
29
  return <table className={cn('sheerly-table', className)} {...props} />
14
30
  }
package/src/tabs.tsx CHANGED
@@ -1,18 +1,49 @@
1
- import type { ButtonHTMLAttributes, HTMLAttributes } from 'react'
2
- import { cn } from './cn'
1
+ import type { ButtonHTMLAttributes, ElementType } from 'react'
2
+ import { cn } from './utils/cn'
3
+ import type { PolymorphicProps } from './utils/polymorphic'
3
4
 
4
- export type TabsProps = HTMLAttributes<HTMLDivElement>
5
+ export type TabsProps<T extends ElementType = 'div'> = PolymorphicProps<T>
5
6
 
6
- export function Tabs({ className, ...props }: TabsProps) {
7
- return <div className={cn('sheerly-tabs', className)} {...props} />
7
+ /**
8
+ * A tabbed interface. Compose a <TabsList> of <TabsTrigger>s with matching
9
+ * <TabsContent> panels (hide inactive panels with `hidden`).
10
+ *
11
+ * Polymorphic: pass `as` to change the rendered tag (defaults to `div`).
12
+ *
13
+ * @example
14
+ * <Tabs>
15
+ * <TabsList>
16
+ * <TabsTrigger aria-selected>Account</TabsTrigger>
17
+ * <TabsTrigger>Password</TabsTrigger>
18
+ * </TabsList>
19
+ * <TabsContent>…</TabsContent>
20
+ * <TabsContent hidden>…</TabsContent>
21
+ * </Tabs>
22
+ */
23
+ export function Tabs<T extends ElementType = 'div'>({
24
+ as,
25
+ className,
26
+ ...props
27
+ }: TabsProps<T>) {
28
+ const Tag = as ?? 'div'
29
+ return <Tag className={cn('sheerly-tabs', className)} {...props} />
8
30
  }
9
31
 
10
- export interface TabsListProps extends HTMLAttributes<HTMLDivElement> {
11
- 'data-variant'?: 'line'
12
- }
32
+ export type TabsListProps<T extends ElementType = 'div'> = PolymorphicProps<
33
+ T,
34
+ { 'data-variant'?: 'line' }
35
+ >
13
36
 
14
- export function TabsList({ className, role = 'tablist', ...props }: TabsListProps) {
15
- return <div role={role} className={cn('sheerly-tabs-list', className)} {...props} />
37
+ /**
38
+ * Polymorphic: pass `as` to change the rendered tag (defaults to `div`).
39
+ */
40
+ export function TabsList<T extends ElementType = 'div'>({
41
+ as,
42
+ className,
43
+ ...props
44
+ }: TabsListProps<T>) {
45
+ const Tag = as ?? 'div'
46
+ return <Tag role="tablist" className={cn('sheerly-tabs-list', className)} {...props} />
16
47
  }
17
48
 
18
49
  export interface TabsTriggerProps extends ButtonHTMLAttributes<HTMLButtonElement> {
@@ -25,14 +56,16 @@ export function TabsTrigger({ className, role = 'tab', ...props }: TabsTriggerPr
25
56
  )
26
57
  }
27
58
 
28
- export type TabsContentProps = HTMLAttributes<HTMLDivElement>
59
+ export type TabsContentProps<T extends ElementType = 'div'> = PolymorphicProps<T>
29
60
 
30
- export function TabsContent({
61
+ /**
62
+ * Polymorphic: pass `as` to change the rendered tag (defaults to `div`).
63
+ */
64
+ export function TabsContent<T extends ElementType = 'div'>({
65
+ as,
31
66
  className,
32
- role = 'tabpanel',
33
67
  ...props
34
- }: TabsContentProps) {
35
- return (
36
- <div role={role} className={cn('sheerly-tabs-content', className)} {...props} />
37
- )
68
+ }: TabsContentProps<T>) {
69
+ const Tag = as ?? 'div'
70
+ return <Tag role="tabpanel" className={cn('sheerly-tabs-content', className)} {...props} />
38
71
  }
package/src/textarea.tsx CHANGED
@@ -1,8 +1,14 @@
1
1
  import type { TextareaHTMLAttributes } from 'react'
2
- import { cn } from './cn'
2
+ import { cn } from './utils/cn'
3
3
 
4
4
  export type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement>
5
5
 
6
+ /**
7
+ * A multiline text field. Auto-grows with content (`field-sizing: content`).
8
+ *
9
+ * @example
10
+ * <Textarea placeholder="Type your message…" />
11
+ */
6
12
  export function Textarea({ className, ...props }: TextareaProps) {
7
13
  return <textarea className={cn('sheerly-textarea', className)} {...props} />
8
14
  }
package/src/toggle.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ChangeEventHandler, LabelHTMLAttributes, ReactNode } from 'react'
2
- import { cn } from './cn'
2
+ import { cn } from './utils/cn'
3
3
 
4
4
  export interface ToggleProps
5
5
  extends Omit<LabelHTMLAttributes<HTMLLabelElement>, 'onChange'> {
@@ -17,6 +17,13 @@ export interface ToggleProps
17
17
  children?: ReactNode
18
18
  }
19
19
 
20
+ /**
21
+ * A two-state toggle button. Works uncontrolled (no JS) or controlled via
22
+ * `pressed` / `onPressedChange`.
23
+ *
24
+ * @example
25
+ * <Toggle defaultPressed data-variant="outline">Bold</Toggle>
26
+ */
20
27
  export function Toggle({
21
28
  className,
22
29
  pressed,
package/src/tooltip.tsx CHANGED
@@ -1,16 +1,35 @@
1
- import type { HTMLAttributes } from 'react'
2
- import { cn } from './cn'
1
+ import type { ElementType } from 'react'
2
+ import { cn } from './utils/cn'
3
+ import type { PolymorphicProps } from './utils/polymorphic'
3
4
 
4
- export type TooltipProps = HTMLAttributes<HTMLSpanElement>
5
+ export type TooltipProps<T extends ElementType = 'span'> = PolymorphicProps<T>
5
6
 
6
- /** Wrapper carrying the anchor. Nest the trigger + content inside. */
7
- export function Tooltip({ className, ...props }: TooltipProps) {
8
- return <span className={cn('sheerly-tooltip', className)} {...props} />
7
+ /**
8
+ * Wrapper carrying the anchor. Nest the trigger + content inside.
9
+ *
10
+ * @example
11
+ * <Tooltip>
12
+ * <Button interestfor="tt">Hover me</Button>
13
+ * <TooltipContent id="tt" popover="hint">More info</TooltipContent>
14
+ * </Tooltip>
15
+ */
16
+ export function Tooltip<T extends ElementType = 'span'>({
17
+ as,
18
+ className,
19
+ ...props
20
+ }: TooltipProps<T>) {
21
+ const Tag = as ?? 'span'
22
+ return <Tag className={cn('sheerly-tooltip', className)} {...props} />
9
23
  }
10
24
 
11
- export type TooltipContentProps = HTMLAttributes<HTMLSpanElement>
25
+ export type TooltipContentProps<T extends ElementType = 'span'> = PolymorphicProps<T>
12
26
 
13
27
  /** The floating label. Give it `popover="hint"` and an `id` matched by the trigger's `interestfor`. */
14
- export function TooltipContent({ className, ...props }: TooltipContentProps) {
15
- return <span className={cn('sheerly-tooltip-content', className)} {...props} />
28
+ export function TooltipContent<T extends ElementType = 'span'>({
29
+ as,
30
+ className,
31
+ ...props
32
+ }: TooltipContentProps<T>) {
33
+ const Tag = as ?? 'span'
34
+ return <Tag className={cn('sheerly-tooltip-content', className)} {...props} />
16
35
  }
@@ -1,13 +1,27 @@
1
- import type { HTMLAttributes } from 'react'
2
- import { cn } from './cn'
1
+ import type { ElementType } from 'react'
2
+ import { cn } from './utils/cn'
3
+ import type { PolymorphicProps } from './utils/polymorphic'
3
4
 
4
- export interface TypographyProps extends HTMLAttributes<HTMLDivElement> {}
5
+ export type TypographyProps<T extends ElementType = 'div'> = PolymorphicProps<T>
5
6
 
6
7
  /**
7
8
  * A prose wrapper. Unlike shadcn (per-element utility classes), Sheerly styles
8
9
  * every child element (h1–h4, p, a, blockquote, ul/ol, li, code, table, …) via
9
10
  * one `.sheerly-typography` class — just render semantic HTML inside it.
11
+ *
12
+ * Polymorphic: pass `as` to change the rendered tag (defaults to `div`).
13
+ *
14
+ * @example
15
+ * <Typography as="article">
16
+ * <h1>Title</h1>
17
+ * <p>Some <a href="#">prose</a> with a <code>token</code>.</p>
18
+ * </Typography>
10
19
  */
11
- export function Typography({ className, ...props }: TypographyProps) {
12
- return <div className={cn('sheerly-typography', className)} {...props} />
20
+ export function Typography<T extends ElementType = 'div'>({
21
+ as,
22
+ className,
23
+ ...props
24
+ }: TypographyProps<T>) {
25
+ const Tag = as ?? 'div'
26
+ return <Tag className={cn('sheerly-typography', className)} {...props} />
13
27
  }
@@ -0,0 +1,19 @@
1
+ import type { ComponentPropsWithoutRef, ElementType } from 'react'
2
+
3
+ /**
4
+ * Props for a polymorphic component: an optional `as` that swaps the rendered
5
+ * element, with the remaining props inferred from that element (so `href` is
6
+ * valid & checked when `as="a"`, etc.).
7
+ *
8
+ * `Extra` merges component-specific props (e.g. typed `data-*` unions) on top.
9
+ *
10
+ * No hooks, no `forwardRef` — matches Sheerly's thin, hookless wrapper style.
11
+ */
12
+ export type PolymorphicProps<
13
+ T extends ElementType,
14
+ Extra = object,
15
+ > = {
16
+ /** The element or component to render. */
17
+ as?: T
18
+ } & Extra &
19
+ Omit<ComponentPropsWithoutRef<T>, 'as' | keyof Extra>
File without changes
File without changes