@zentauri-ui/zentauri-components 1.4.41 → 1.4.61

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 (77) hide show
  1. package/README.md +64 -1
  2. package/cli/registry.json +3 -1
  3. package/dist/ui/search/filter-search-suggestions.d.ts +15 -0
  4. package/dist/ui/search/filter-search-suggestions.d.ts.map +1 -0
  5. package/dist/ui/search/index.d.ts +7 -0
  6. package/dist/ui/search/index.d.ts.map +1 -0
  7. package/dist/ui/search/search-bar.d.ts +6 -0
  8. package/dist/ui/search/search-bar.d.ts.map +1 -0
  9. package/dist/ui/search/search-suggestion-list.d.ts +6 -0
  10. package/dist/ui/search/search-suggestion-list.d.ts.map +1 -0
  11. package/dist/ui/search/search-suggestion-utils.d.ts +6 -0
  12. package/dist/ui/search/search-suggestion-utils.d.ts.map +1 -0
  13. package/dist/ui/search/types.d.ts +44 -0
  14. package/dist/ui/search/types.d.ts.map +1 -0
  15. package/dist/ui/search.js +199 -0
  16. package/dist/ui/search.js.map +1 -0
  17. package/dist/ui/search.mjs +194 -0
  18. package/dist/ui/search.mjs.map +1 -0
  19. package/dist/ui/typography/blockquote-base.d.ts +6 -0
  20. package/dist/ui/typography/blockquote-base.d.ts.map +1 -0
  21. package/dist/ui/typography/blockquote.d.ts +6 -0
  22. package/dist/ui/typography/blockquote.d.ts.map +1 -0
  23. package/dist/ui/typography/code-block-base.d.ts +6 -0
  24. package/dist/ui/typography/code-block-base.d.ts.map +1 -0
  25. package/dist/ui/typography/code-block.d.ts +6 -0
  26. package/dist/ui/typography/code-block.d.ts.map +1 -0
  27. package/dist/ui/typography/heading-base.d.ts +6 -0
  28. package/dist/ui/typography/heading-base.d.ts.map +1 -0
  29. package/dist/ui/typography/heading.d.ts +6 -0
  30. package/dist/ui/typography/heading.d.ts.map +1 -0
  31. package/dist/ui/typography/index.d.ts +9 -0
  32. package/dist/ui/typography/index.d.ts.map +1 -0
  33. package/dist/ui/typography/inline-code-base.d.ts +6 -0
  34. package/dist/ui/typography/inline-code-base.d.ts.map +1 -0
  35. package/dist/ui/typography/inline-code.d.ts +6 -0
  36. package/dist/ui/typography/inline-code.d.ts.map +1 -0
  37. package/dist/ui/typography/list-base.d.ts +10 -0
  38. package/dist/ui/typography/list-base.d.ts.map +1 -0
  39. package/dist/ui/typography/list.d.ts +12 -0
  40. package/dist/ui/typography/list.d.ts.map +1 -0
  41. package/dist/ui/typography/text-base.d.ts +6 -0
  42. package/dist/ui/typography/text-base.d.ts.map +1 -0
  43. package/dist/ui/typography/text.d.ts +6 -0
  44. package/dist/ui/typography/text.d.ts.map +1 -0
  45. package/dist/ui/typography/types.d.ts +56 -0
  46. package/dist/ui/typography/types.d.ts.map +1 -0
  47. package/dist/ui/typography/variants.d.ts +16 -0
  48. package/dist/ui/typography/variants.d.ts.map +1 -0
  49. package/dist/ui/typography.js +334 -0
  50. package/dist/ui/typography.js.map +1 -0
  51. package/dist/ui/typography.mjs +321 -0
  52. package/dist/ui/typography.mjs.map +1 -0
  53. package/package.json +3 -3
  54. package/src/ui/search/filter-search-suggestions.test.ts +48 -0
  55. package/src/ui/search/filter-search-suggestions.ts +43 -0
  56. package/src/ui/search/index.ts +11 -0
  57. package/src/ui/search/search-bar.tsx +83 -0
  58. package/src/ui/search/search-suggestion-list.tsx +103 -0
  59. package/src/ui/search/search-suggestion-utils.test.ts +9 -0
  60. package/src/ui/search/search-suggestion-utils.ts +8 -0
  61. package/src/ui/search/types.ts +52 -0
  62. package/src/ui/typography/blockquote-base.tsx +39 -0
  63. package/src/ui/typography/blockquote.tsx +8 -0
  64. package/src/ui/typography/code-block-base.tsx +37 -0
  65. package/src/ui/typography/code-block.tsx +8 -0
  66. package/src/ui/typography/heading-base.tsx +59 -0
  67. package/src/ui/typography/heading.tsx +8 -0
  68. package/src/ui/typography/index.ts +28 -0
  69. package/src/ui/typography/inline-code-base.tsx +27 -0
  70. package/src/ui/typography/inline-code.tsx +8 -0
  71. package/src/ui/typography/list-base.tsx +88 -0
  72. package/src/ui/typography/list.tsx +15 -0
  73. package/src/ui/typography/text-base.tsx +43 -0
  74. package/src/ui/typography/text.tsx +8 -0
  75. package/src/ui/typography/types.ts +90 -0
  76. package/src/ui/typography/typography.test.tsx +80 -0
  77. package/src/ui/typography/variants.ts +72 -0
@@ -0,0 +1,103 @@
1
+ "use client";
2
+
3
+ import { Fragment } from "react";
4
+
5
+ import { cn } from "../../lib/utils";
6
+ import { searchSuggestionOptionDomId } from "./search-suggestion-utils";
7
+
8
+ import type { SearchSuggestionListProps } from "./types";
9
+
10
+ const rowClassName =
11
+ "flex w-full flex-col gap-0.5 rounded-lg px-3 py-2.5 text-left text-sm transition-colors hover:bg-white/5 focus-visible:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-cyan-400/50";
12
+
13
+ export function SearchSuggestionList({
14
+ items,
15
+ onSelect,
16
+ activeId,
17
+ onActiveIdChange,
18
+ listboxId,
19
+ className,
20
+ listClassName,
21
+ emptyLabel,
22
+ }: SearchSuggestionListProps) {
23
+ if (items.length === 0) {
24
+ return (
25
+ <div
26
+ data-slot="search-suggestion-list-empty"
27
+ className={cn("px-1 py-6 text-center text-sm text-slate-500", className)}
28
+ >
29
+ {emptyLabel ?? "No matches."}
30
+ </div>
31
+ );
32
+ }
33
+
34
+ const useListbox = Boolean(listboxId);
35
+
36
+ const rows: Array<{
37
+ item: (typeof items)[number];
38
+ showGroup: boolean;
39
+ }> = [];
40
+ let lastGroupSeen: string | undefined;
41
+ for (const item of items) {
42
+ const showGroup = Boolean(item.group && item.group !== lastGroupSeen);
43
+ if (item.group) {
44
+ lastGroupSeen = item.group;
45
+ }
46
+ rows.push({ item, showGroup });
47
+ }
48
+
49
+ return (
50
+ <nav
51
+ data-slot="search-suggestion-list"
52
+ aria-label="Search results"
53
+ className={cn("flex max-h-[min(50vh,360px)] flex-col gap-1 overflow-y-auto pr-1", className)}
54
+ >
55
+ <div
56
+ {...(useListbox
57
+ ? {
58
+ id: listboxId,
59
+ role: "listbox" as const,
60
+ }
61
+ : {})}
62
+ className={cn("flex flex-col gap-0.5", listClassName)}
63
+ >
64
+ {rows.map(({ item, showGroup }) => {
65
+ const isActive = activeId === item.id;
66
+ const optionDomId =
67
+ useListbox && listboxId ? searchSuggestionOptionDomId(listboxId, item.id) : undefined;
68
+ return (
69
+ <Fragment key={item.id}>
70
+ {showGroup ? (
71
+ <div
72
+ role="presentation"
73
+ className="sticky top-0 z-1 bg-slate-950/95 px-2 pb-1 pt-2 text-xs font-semibold uppercase tracking-wide text-slate-500 backdrop-blur-sm"
74
+ >
75
+ {item.group}
76
+ </div>
77
+ ) : null}
78
+ <button
79
+ type="button"
80
+ id={optionDomId}
81
+ role={useListbox ? "option" : undefined}
82
+ aria-selected={useListbox ? isActive : undefined}
83
+ data-active={isActive ? "" : undefined}
84
+ className={cn(rowClassName, isActive ? "bg-white/5" : null)}
85
+ onMouseEnter={() => onActiveIdChange?.(item.id)}
86
+ onFocus={() => onActiveIdChange?.(item.id)}
87
+ onClick={() => onSelect(item.id)}
88
+ >
89
+ <span className="font-medium text-slate-100">{item.label}</span>
90
+ {item.description ? (
91
+ <span className="truncate text-xs text-slate-500">{item.description}</span>
92
+ ) : null}
93
+ </button>
94
+ </Fragment>
95
+ );
96
+ })}
97
+ </div>
98
+ </nav>
99
+ );
100
+ }
101
+
102
+ SearchSuggestionList.displayName = "SearchSuggestionList";
103
+
@@ -0,0 +1,9 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import { searchSuggestionOptionDomId } from "./search-suggestion-utils";
4
+
5
+ describe("searchSuggestionOptionDomId", () => {
6
+ it("prefixes listbox id and sanitizes item id", () => {
7
+ expect(searchSuggestionOptionDomId(":lb:", "/a/b")).toBe(":lb:_opt__a_b");
8
+ });
9
+ });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Builds a stable DOM id for a listbox option so `aria-activedescendant` on the combobox
3
+ * input can reference it. Safe for href-like `itemId` strings.
4
+ */
5
+ export function searchSuggestionOptionDomId(listboxId: string, itemId: string): string {
6
+ const safe = itemId.replace(/[^a-zA-Z0-9_-]/g, "_");
7
+ return `${listboxId}_opt_${safe}`;
8
+ }
@@ -0,0 +1,52 @@
1
+ import type { InputHTMLAttributes, ReactNode, Ref } from "react";
2
+
3
+ import type { VariantProps } from "class-variance-authority";
4
+
5
+ import type { inputVariants } from "../inputs/variants";
6
+
7
+ export type SearchBarProps = Omit<
8
+ InputHTMLAttributes<HTMLInputElement>,
9
+ "size" | "children" | "role"
10
+ > & {
11
+ value: string;
12
+ onValueChange?: (value: string) => void;
13
+ leadingSlot?: ReactNode;
14
+ inputClassName?: string;
15
+ appearance?: VariantProps<typeof inputVariants>["appearance"];
16
+ inputSize?: VariantProps<typeof inputVariants>["size"];
17
+ ring?: VariantProps<typeof inputVariants>["ring"];
18
+ /** When set, the input exposes combobox semantics wired to a `role="listbox"` with this id. */
19
+ comboboxListboxId?: string;
20
+ /** Element id of the active option (from `searchSuggestionOptionDomId`) for `aria-activedescendant`. */
21
+ comboboxActiveOptionId?: string;
22
+ /** Whether the suggestion list is visibly expanded (controls `aria-expanded`). */
23
+ comboboxExpanded?: boolean;
24
+ ref?: Ref<HTMLInputElement>;
25
+ };
26
+
27
+ export type SearchSuggestionItem = {
28
+ id: string;
29
+ label: string;
30
+ description?: string;
31
+ group?: string;
32
+ };
33
+
34
+ export type SearchSuggestionListProps = {
35
+ items: readonly SearchSuggestionItem[];
36
+ onSelect: (id: string) => void;
37
+ activeId?: string;
38
+ onActiveIdChange?: (id: string | undefined) => void;
39
+ /** Pass the same id as `comboboxListboxId` on `SearchBar` for ARIA wiring. */
40
+ listboxId?: string;
41
+ className?: string;
42
+ listClassName?: string;
43
+ emptyLabel?: ReactNode;
44
+ };
45
+
46
+ export type SearchFilterable = {
47
+ id: string;
48
+ label: string;
49
+ description?: string;
50
+ keywords?: readonly string[];
51
+ href?: string;
52
+ };
@@ -0,0 +1,39 @@
1
+ import { forwardRef } from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ import type { BlockquoteProps } from "./types";
6
+ import { typographyToneVariants } from "./variants";
7
+
8
+ export const BlockquoteBase = (props: BlockquoteProps) => {
9
+ const {
10
+ tone,
11
+ attribution,
12
+ className,
13
+ children,
14
+ ref,
15
+ ...rest
16
+ } = props;
17
+
18
+ return (
19
+ <blockquote
20
+ ref={ref}
21
+ data-slot="typography-blockquote"
22
+ className={cn(
23
+ typographyToneVariants({ tone }),
24
+ "border-l-4 py-1 pl-4 italic",
25
+ className,
26
+ )}
27
+ {...rest}
28
+ >
29
+ <div className="space-y-2 leading-relaxed">{children}</div>
30
+ {attribution ? (
31
+ <footer className="mt-3 text-sm not-italic">
32
+ <cite>{attribution}</cite>
33
+ </footer>
34
+ ) : null}
35
+ </blockquote>
36
+ );
37
+ };
38
+
39
+ BlockquoteBase.displayName = "Blockquote";
@@ -0,0 +1,8 @@
1
+ import { BlockquoteBase } from "./blockquote-base";
2
+ import type { BlockquoteProps } from "./types";
3
+
4
+ export const Blockquote = (props: BlockquoteProps) => {
5
+ return <BlockquoteBase {...props} />;
6
+ };
7
+
8
+ Blockquote.displayName = "Blockquote";
@@ -0,0 +1,37 @@
1
+ import { forwardRef } from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ import type { CodeBlockProps } from "./types";
6
+ import { typographyToneVariants } from "./variants";
7
+
8
+ export const CodeBlockBase = (props: CodeBlockProps) => {
9
+ const {
10
+ tone,
11
+ language,
12
+ className,
13
+ children,
14
+ ref,
15
+ ...rest
16
+ } = props;
17
+
18
+ const ariaLabel = language ? `Code sample (${language})` : "Code sample";
19
+
20
+ return (
21
+ <pre
22
+ ref={ref}
23
+ data-slot="typography-code-block"
24
+ aria-label={ariaLabel}
25
+ className={cn(
26
+ typographyToneVariants({ tone }),
27
+ "overflow-x-auto rounded-xl border border-white/10 bg-slate-950/80 p-4 text-sm leading-relaxed shadow-inner shadow-slate-950/40",
28
+ className,
29
+ )}
30
+ {...rest}
31
+ >
32
+ <code className="font-mono text-[0.95em] whitespace-pre-wrap wrap-break-word">{children}</code>
33
+ </pre>
34
+ );
35
+ };
36
+
37
+ CodeBlockBase.displayName = "CodeBlock";
@@ -0,0 +1,8 @@
1
+ import { CodeBlockBase } from "./code-block-base";
2
+ import type { CodeBlockProps } from "./types";
3
+
4
+ export const CodeBlock = (props: CodeBlockProps) => {
5
+ return <CodeBlockBase {...props} />;
6
+ };
7
+
8
+ CodeBlock.displayName = "CodeBlock";
@@ -0,0 +1,59 @@
1
+ import { forwardRef } from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ import type { HeadingProps } from "./types";
6
+ import {
7
+ headingLevelVariants,
8
+ typographyToneVariants,
9
+ } from "./variants";
10
+
11
+ const HEADING_TAGS = {
12
+ 1: "h1",
13
+ 2: "h2",
14
+ 3: "h3",
15
+ 4: "h4",
16
+ 5: "h5",
17
+ 6: "h6",
18
+ } as const;
19
+
20
+ export const HeadingBase = (props: HeadingProps) => {
21
+ const {
22
+ level,
23
+ displayLevel,
24
+ tone,
25
+ bold,
26
+ italic,
27
+ underline,
28
+ strikethrough,
29
+ ref,
30
+ className,
31
+ children,
32
+ ...rest
33
+ } = props;
34
+
35
+ const Tag = HEADING_TAGS[level];
36
+ const scale = displayLevel ?? level;
37
+
38
+ return (
39
+ <Tag
40
+ ref={ref}
41
+ data-slot="typography-heading"
42
+ data-level={level}
43
+ className={cn(
44
+ typographyToneVariants({ tone }),
45
+ headingLevelVariants({ level: scale }),
46
+ bold && "font-bold",
47
+ italic && "italic",
48
+ underline && "underline underline-offset-4",
49
+ strikethrough && "line-through",
50
+ className,
51
+ )}
52
+ {...rest}
53
+ >
54
+ {children}
55
+ </Tag>
56
+ );
57
+ };
58
+
59
+ HeadingBase.displayName = "Heading";
@@ -0,0 +1,8 @@
1
+ import { HeadingBase } from "./heading-base";
2
+ import type { HeadingProps } from "./types";
3
+
4
+ export const Heading = (props: HeadingProps) => {
5
+ return <HeadingBase {...props} />;
6
+ };
7
+
8
+ Heading.displayName = "Heading";
@@ -0,0 +1,28 @@
1
+ export { Heading } from "./heading";
2
+ export { Text } from "./text";
3
+ export { List, ListItem } from "./list";
4
+ export { Blockquote } from "./blockquote";
5
+ export { InlineCode } from "./inline-code";
6
+ export { CodeBlock } from "./code-block";
7
+
8
+ export type {
9
+ BlockquoteProps,
10
+ CodeBlockProps,
11
+ HeadingLevel,
12
+ HeadingProps,
13
+ InlineCodeProps,
14
+ ListItemProps,
15
+ ListProps,
16
+ TextElement,
17
+ TextProps,
18
+ TypographyTone,
19
+ UnorderedMarker,
20
+ } from "./types";
21
+
22
+ export {
23
+ headingLevelVariants,
24
+ orderedListVariants,
25
+ textSizeVariants,
26
+ typographyToneVariants,
27
+ unorderedListMarkerVariants,
28
+ } from "./variants";
@@ -0,0 +1,27 @@
1
+ import { forwardRef } from "react";
2
+
3
+ import { cn } from "../../lib/utils";
4
+
5
+ import type { InlineCodeProps } from "./types";
6
+ import { typographyToneVariants } from "./variants";
7
+
8
+ export const InlineCodeBase = (props: InlineCodeProps) => {
9
+ const { tone, className, children, ref, ...rest } = props;
10
+
11
+ return (
12
+ <code
13
+ ref={ref}
14
+ data-slot="typography-inline-code"
15
+ className={cn(
16
+ typographyToneVariants({ tone }),
17
+ "rounded-md border border-white/10 bg-white/6 px-1.5 py-0.5 font-mono text-[0.925em] font-normal",
18
+ className,
19
+ )}
20
+ {...rest}
21
+ >
22
+ {children}
23
+ </code>
24
+ );
25
+ };
26
+
27
+ InlineCodeBase.displayName = "InlineCode";
@@ -0,0 +1,8 @@
1
+ import { InlineCodeBase } from "./inline-code-base";
2
+ import type { InlineCodeProps } from "./types";
3
+
4
+ export const InlineCode = (props: InlineCodeProps) => {
5
+ return <InlineCodeBase {...props} />;
6
+ };
7
+
8
+ InlineCode.displayName = "InlineCode";
@@ -0,0 +1,88 @@
1
+ import { cn } from "../../lib/utils";
2
+
3
+ import type { ListProps, ListItemProps } from "./types";
4
+ import {
5
+ orderedListVariants,
6
+ typographyToneVariants,
7
+ unorderedListMarkerVariants,
8
+ } from "./variants";
9
+
10
+ export function ListBase(props: ListProps) {
11
+ if ("ordered" in props && props.ordered === true) {
12
+ const {
13
+ tone,
14
+ className,
15
+ children,
16
+ ref,
17
+ ordered,
18
+ marker,
19
+ ...rest
20
+ } = props;
21
+
22
+ void ordered;
23
+ void marker;
24
+
25
+ return (
26
+ <ol
27
+ ref={ref}
28
+ data-slot="typography-list"
29
+ data-list-type="ordered"
30
+ className={cn(
31
+ typographyToneVariants({ tone }),
32
+ orderedListVariants(),
33
+ className,
34
+ )}
35
+ {...rest}
36
+ >
37
+ {children}
38
+ </ol>
39
+ );
40
+ }
41
+
42
+ const {
43
+ marker = "disc",
44
+ tone,
45
+ className,
46
+ children,
47
+ ref,
48
+ ordered,
49
+ ...rest
50
+ } = props;
51
+
52
+ void ordered;
53
+
54
+ return (
55
+ <ul
56
+ ref={ref}
57
+ data-slot="typography-list"
58
+ data-list-type="unordered"
59
+ className={cn(
60
+ typographyToneVariants({ tone }),
61
+ unorderedListMarkerVariants({ marker }),
62
+ className,
63
+ )}
64
+ {...rest}
65
+ >
66
+ {children}
67
+ </ul>
68
+ );
69
+ }
70
+
71
+ ListBase.displayName = "List";
72
+
73
+ export function ListItemBase(props: ListItemProps) {
74
+ const { className, children, ref, ...rest } = props;
75
+
76
+ return (
77
+ <li
78
+ ref={ref}
79
+ data-slot="typography-list-item"
80
+ className={cn("leading-relaxed", className)}
81
+ {...rest}
82
+ >
83
+ {children}
84
+ </li>
85
+ );
86
+ }
87
+
88
+ ListItemBase.displayName = "ListItem";
@@ -0,0 +1,15 @@
1
+ import type { ListProps } from "./types";
2
+
3
+ import { ListBase, ListItemBase } from "./list-base";
4
+
5
+ export const ListItem = ListItemBase;
6
+
7
+ function ListRoot(props: ListProps) {
8
+ return <ListBase {...props} />;
9
+ }
10
+
11
+ export const List = Object.assign(ListRoot, {
12
+ Item: ListItem,
13
+ });
14
+
15
+ ListRoot.displayName = "List";
@@ -0,0 +1,43 @@
1
+ import { cn } from "../../lib/utils";
2
+
3
+ import type { TextProps } from "./types";
4
+ import { textSizeVariants, typographyToneVariants } from "./variants";
5
+
6
+ export const TextBase = (props: TextProps) => {
7
+ const {
8
+ as = "p",
9
+ size = "base",
10
+ tone,
11
+ bold,
12
+ italic,
13
+ underline,
14
+ strikethrough,
15
+ highlight,
16
+ className,
17
+ children,
18
+ ...rest
19
+ } = props;
20
+
21
+ const Component = as;
22
+
23
+ return (
24
+ <Component
25
+ data-slot="typography-text"
26
+ className={cn(
27
+ typographyToneVariants({ tone }),
28
+ textSizeVariants({ size }),
29
+ bold && "font-semibold",
30
+ italic && "italic",
31
+ underline && "underline underline-offset-2",
32
+ strikethrough && "line-through",
33
+ highlight && "rounded bg-amber-400/15 px-0.5",
34
+ className,
35
+ )}
36
+ {...rest}
37
+ >
38
+ {children}
39
+ </Component>
40
+ );
41
+ };
42
+
43
+ TextBase.displayName = "Text";
@@ -0,0 +1,8 @@
1
+ import { TextBase } from "./text-base";
2
+ import type { TextProps } from "./types";
3
+
4
+ export const Text = (props: TextProps) => {
5
+ return <TextBase {...props} />;
6
+ };
7
+
8
+ Text.displayName = "Text";
@@ -0,0 +1,90 @@
1
+ import type { VariantProps } from "class-variance-authority";
2
+ import type {
3
+ ComponentProps,
4
+ HTMLAttributes,
5
+ RefObject,
6
+ } from "react";
7
+
8
+ import type {
9
+ textSizeVariants,
10
+ typographyToneVariants,
11
+ unorderedListMarkerVariants,
12
+ } from "./variants";
13
+
14
+ export type TypographyTone = NonNullable<
15
+ VariantProps<typeof typographyToneVariants>["tone"]
16
+ >;
17
+
18
+ export type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
19
+
20
+ export type HeadingProps = Omit<
21
+ ComponentProps<"h1">,
22
+ "color"
23
+ > & {
24
+ level: HeadingLevel;
25
+ /** Visual scale; defaults to `level`. */
26
+ displayLevel?: HeadingLevel;
27
+ tone?: TypographyTone;
28
+ bold?: boolean;
29
+ italic?: boolean;
30
+ underline?: boolean;
31
+ strikethrough?: boolean;
32
+ ref?: RefObject<HTMLHeadingElement>;
33
+ };
34
+
35
+ export type TextElement = "p" | "span" | "div" | "label";
36
+
37
+ export type TextProps = Omit<HTMLAttributes<HTMLElement>, "color"> & {
38
+ as?: TextElement;
39
+ size?: NonNullable<VariantProps<typeof textSizeVariants>["size"]>;
40
+ tone?: TypographyTone;
41
+ bold?: boolean;
42
+ italic?: boolean;
43
+ underline?: boolean;
44
+ strikethrough?: boolean;
45
+ highlight?: boolean;
46
+ };
47
+
48
+ export type UnorderedMarker = NonNullable<
49
+ VariantProps<typeof unorderedListMarkerVariants>["marker"]
50
+ >;
51
+
52
+ export type ListProps =
53
+ | (Omit<ComponentProps<"ul">, "color"> & {
54
+ ordered?: false;
55
+ marker?: UnorderedMarker;
56
+ tone?: TypographyTone;
57
+ })
58
+ | (Omit<ComponentProps<"ol">, "color"> & {
59
+ ordered: true;
60
+ marker?: undefined;
61
+ tone?: TypographyTone;
62
+ });
63
+
64
+ export type ListItemProps = ComponentProps<"li"> & {
65
+ ref?: RefObject<HTMLLIElement>;
66
+ };
67
+
68
+ export type BlockquoteProps = ComponentProps<"blockquote"> & {
69
+ tone?: TypographyTone;
70
+ /** Attribution label shown in a footer (distinct from the HTML `cite` URL attribute). */
71
+ attribution?: string;
72
+ ref?: RefObject<HTMLQuoteElement>;
73
+ };
74
+
75
+ export type InlineCodeProps = Omit<
76
+ ComponentProps<"code">,
77
+ "color"
78
+ > & {
79
+ tone?: TypographyTone;
80
+ };
81
+
82
+ export type CodeBlockProps = Omit<
83
+ ComponentProps<"pre">,
84
+ "color"
85
+ > & {
86
+ tone?: TypographyTone;
87
+ /** Hint for stacked highlighting stacks / aria-labels. */
88
+ language?: string;
89
+ ref?: RefObject<HTMLPreElement>;
90
+ };