@tea-ui/core 0.1.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 (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +33 -0
  3. package/dist/card.d.ts +60 -0
  4. package/dist/card.js +116 -0
  5. package/dist/card.js.map +1 -0
  6. package/dist/feedback/alert.d.ts +57 -0
  7. package/dist/feedback/alert.js +104 -0
  8. package/dist/feedback/alert.js.map +1 -0
  9. package/dist/feedback/badge.d.ts +34 -0
  10. package/dist/feedback/badge.js +62 -0
  11. package/dist/feedback/badge.js.map +1 -0
  12. package/dist/feedback/index.d.ts +13 -0
  13. package/dist/feedback/index.js +62 -0
  14. package/dist/feedback/index.js.map +1 -0
  15. package/dist/feedback/progress.d.ts +25 -0
  16. package/dist/feedback/progress.js +49 -0
  17. package/dist/feedback/progress.js.map +1 -0
  18. package/dist/feedback/skeleton.d.ts +38 -0
  19. package/dist/feedback/skeleton.js +49 -0
  20. package/dist/feedback/skeleton.js.map +1 -0
  21. package/dist/feedback/spinner.d.ts +31 -0
  22. package/dist/feedback/spinner.js +55 -0
  23. package/dist/feedback/spinner.js.map +1 -0
  24. package/dist/feedback/status.d.ts +63 -0
  25. package/dist/feedback/status.js +156 -0
  26. package/dist/feedback/status.js.map +1 -0
  27. package/dist/feedback/toast.d.ts +72 -0
  28. package/dist/feedback/toast.js +211 -0
  29. package/dist/feedback/toast.js.map +1 -0
  30. package/dist/format/index.d.ts +63 -0
  31. package/dist/format/index.js +84 -0
  32. package/dist/format/index.js.map +1 -0
  33. package/dist/index.d.ts +43 -0
  34. package/dist/index.js +163 -0
  35. package/dist/index.js.map +1 -0
  36. package/dist/inputs/button-group.d.ts +70 -0
  37. package/dist/inputs/button-group.js +59 -0
  38. package/dist/inputs/button-group.js.map +1 -0
  39. package/dist/inputs/button.d.ts +52 -0
  40. package/dist/inputs/button.js +84 -0
  41. package/dist/inputs/button.js.map +1 -0
  42. package/dist/inputs/checkbox.d.ts +48 -0
  43. package/dist/inputs/checkbox.js +74 -0
  44. package/dist/inputs/checkbox.js.map +1 -0
  45. package/dist/inputs/combobox.d.ts +77 -0
  46. package/dist/inputs/combobox.js +273 -0
  47. package/dist/inputs/combobox.js.map +1 -0
  48. package/dist/inputs/field.d.ts +220 -0
  49. package/dist/inputs/field.js +183 -0
  50. package/dist/inputs/field.js.map +1 -0
  51. package/dist/inputs/icon-button.d.ts +44 -0
  52. package/dist/inputs/icon-button.js +30 -0
  53. package/dist/inputs/icon-button.js.map +1 -0
  54. package/dist/inputs/index.d.ts +22 -0
  55. package/dist/inputs/index.js +92 -0
  56. package/dist/inputs/index.js.map +1 -0
  57. package/dist/inputs/input-group.d.ts +77 -0
  58. package/dist/inputs/input-group.js +76 -0
  59. package/dist/inputs/input-group.js.map +1 -0
  60. package/dist/inputs/input.d.ts +58 -0
  61. package/dist/inputs/input.js +68 -0
  62. package/dist/inputs/input.js.map +1 -0
  63. package/dist/inputs/label.d.ts +47 -0
  64. package/dist/inputs/label.js +29 -0
  65. package/dist/inputs/label.js.map +1 -0
  66. package/dist/inputs/number-input.d.ts +62 -0
  67. package/dist/inputs/number-input.js +86 -0
  68. package/dist/inputs/number-input.js.map +1 -0
  69. package/dist/inputs/password-input.d.ts +66 -0
  70. package/dist/inputs/password-input.js +73 -0
  71. package/dist/inputs/password-input.js.map +1 -0
  72. package/dist/inputs/radio.d.ts +66 -0
  73. package/dist/inputs/radio.js +96 -0
  74. package/dist/inputs/radio.js.map +1 -0
  75. package/dist/inputs/search-input.d.ts +66 -0
  76. package/dist/inputs/search-input.js +76 -0
  77. package/dist/inputs/search-input.js.map +1 -0
  78. package/dist/inputs/select.d.ts +65 -0
  79. package/dist/inputs/select.js +139 -0
  80. package/dist/inputs/select.js.map +1 -0
  81. package/dist/inputs/slider.d.ts +67 -0
  82. package/dist/inputs/slider.js +107 -0
  83. package/dist/inputs/slider.js.map +1 -0
  84. package/dist/inputs/switch.d.ts +42 -0
  85. package/dist/inputs/switch.js +69 -0
  86. package/dist/inputs/switch.js.map +1 -0
  87. package/dist/inputs/textarea.d.ts +51 -0
  88. package/dist/inputs/textarea.js +82 -0
  89. package/dist/inputs/textarea.js.map +1 -0
  90. package/dist/inputs/toggle.d.ts +57 -0
  91. package/dist/inputs/toggle.js +91 -0
  92. package/dist/inputs/toggle.js.map +1 -0
  93. package/dist/internal/index.d.ts +5 -0
  94. package/dist/internal/index.js +19 -0
  95. package/dist/internal/index.js.map +1 -0
  96. package/dist/internal/refs.d.ts +31 -0
  97. package/dist/internal/refs.js +34 -0
  98. package/dist/internal/refs.js.map +1 -0
  99. package/dist/internal/slot.d.ts +76 -0
  100. package/dist/internal/slot.js +40 -0
  101. package/dist/internal/slot.js.map +1 -0
  102. package/dist/internal/use-controllable-state.d.ts +25 -0
  103. package/dist/internal/use-controllable-state.js +38 -0
  104. package/dist/internal/use-controllable-state.js.map +1 -0
  105. package/dist/layout/index.d.ts +131 -0
  106. package/dist/layout/index.js +212 -0
  107. package/dist/layout/index.js.map +1 -0
  108. package/dist/navigation/index.d.ts +114 -0
  109. package/dist/navigation/index.js +523 -0
  110. package/dist/navigation/index.js.map +1 -0
  111. package/dist/overlays/alert-dialog.d.ts +75 -0
  112. package/dist/overlays/alert-dialog.js +163 -0
  113. package/dist/overlays/alert-dialog.js.map +1 -0
  114. package/dist/overlays/dialog.d.ts +44 -0
  115. package/dist/overlays/dialog.js +121 -0
  116. package/dist/overlays/dialog.js.map +1 -0
  117. package/dist/overlays/drawer.d.ts +49 -0
  118. package/dist/overlays/drawer.js +125 -0
  119. package/dist/overlays/drawer.js.map +1 -0
  120. package/dist/overlays/dropdown-menu.d.ts +53 -0
  121. package/dist/overlays/dropdown-menu.js +192 -0
  122. package/dist/overlays/dropdown-menu.js.map +1 -0
  123. package/dist/overlays/index.d.ts +10 -0
  124. package/dist/overlays/index.js +169 -0
  125. package/dist/overlays/index.js.map +1 -0
  126. package/dist/overlays/popover.d.ts +58 -0
  127. package/dist/overlays/popover.js +105 -0
  128. package/dist/overlays/popover.js.map +1 -0
  129. package/dist/styles.css +2 -0
  130. package/dist/typography/index.d.ts +79 -0
  131. package/dist/typography/index.js +280 -0
  132. package/dist/typography/index.js.map +1 -0
  133. package/package.json +60 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 landnevermore
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # @tea-ui/core
2
+
3
+ The primitive layer: layout, typography, inputs, feedback, overlays, navigation.
4
+
5
+ Part of [TEA UI](https://landnevermore.github.io/TEAui/) — a design system built once and reused across
6
+ products. The whole system is documented at https://landnevermore.github.io/TEAui/docs/.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @tea-ui/core
12
+ ```
13
+
14
+ React 18.2 or 19 is expected as a peer dependency.
15
+
16
+ ## Use
17
+
18
+ ```ts
19
+ import { Button } from "@tea-ui/core";
20
+ ```
21
+
22
+ ## Styles
23
+
24
+ The token layer ships its stylesheet as a separate export, so it is only
25
+ downloaded when it is asked for:
26
+
27
+ ```ts
28
+ import "@tea-ui/core/styles.css";
29
+ ```
30
+
31
+ ## Licence
32
+
33
+ MIT. See [LICENSE](./LICENSE).
package/dist/card.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * TEA UI — Card.
5
+ *
6
+ * The single most duplicated element in the source projects: the audit counted
7
+ * **twenty hand-typed copies of a bordered, padded surface** in one product,
8
+ * varying between `p-3`, `p-4`, `p-5`, `p-6` and `p-8`, and with one file
9
+ * defining its own local `Card({ title })` that shadowed the kit concept
10
+ * entirely. This is the one implementation.
11
+ *
12
+ * Two decisions worth stating, because both are load-bearing:
13
+ *
14
+ * - **`CardTitle` renders a heading element, not a `div`.** The source
15
+ * component rendered `<div>` for its title, which silently flattened the
16
+ * heading structure of every page that used it. A screen-reader user
17
+ * navigating by heading had nothing to navigate by. `level` is therefore a
18
+ * prop with no default guess: a card on a page whose top heading is an `h1`
19
+ * almost always wants `h2`, and guessing wrong is invisible until someone
20
+ * needs the outline.
21
+ * - **The surface never overrides its own padding silently.** `CardContent`
22
+ * takes the density's `pad-card` step, so "how padded is a card" has one
23
+ * answer rather than twenty.
24
+ */
25
+ interface CardProps extends React.ComponentProps<"div"> {
26
+ /** Set `false` to drop the border — for a card nested inside another card. */
27
+ bordered?: boolean | undefined;
28
+ className?: string | undefined;
29
+ }
30
+ declare const Card: React.ForwardRefExoticComponent<Omit<CardProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
31
+ declare const CardHeader: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
32
+ declare const CardBody: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
33
+ declare const CardFooter: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
34
+ interface CardTitleProps extends React.ComponentProps<"div"> {
35
+ /** The heading level. No default: a wrong guess breaks the document outline. */
36
+ level: 1 | 2 | 3 | 4 | 5 | 6;
37
+ className?: string | undefined;
38
+ }
39
+ declare const CardTitle: React.ForwardRefExoticComponent<Omit<CardTitleProps, "ref"> & React.RefAttributes<HTMLHeadingElement>>;
40
+ declare const CardDescription: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
41
+ /**
42
+ * The audit's second-most-duplicated element: an icon + title + subtitle header
43
+ * appeared at eight call sites with the same class string. `Panel` is that
44
+ * header with a body, and it is what `Card` + `CardHeader` compose into when
45
+ * the region is a section rather than a discrete item.
46
+ */
47
+ interface PanelProps extends React.ComponentProps<"section"> {
48
+ title: string;
49
+ description?: string | undefined;
50
+ /** Icon before the title. Decorative. */
51
+ icon?: React.ReactNode | undefined;
52
+ /** Right-aligned header content, e.g. a refresh control. */
53
+ actions?: React.ReactNode | undefined;
54
+ /** The heading level of `title`. */
55
+ level?: 2 | 3 | 4 | undefined;
56
+ className?: string | undefined;
57
+ }
58
+ declare const Panel: React.ForwardRefExoticComponent<Omit<PanelProps, "ref"> & React.RefAttributes<HTMLElement>>;
59
+
60
+ export { Card, CardBody, CardDescription, CardFooter, CardHeader, type CardProps, CardTitle, type CardTitleProps, Panel, type PanelProps };
package/dist/card.js ADDED
@@ -0,0 +1,116 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "@tea-ui/utils";
4
+ import { dataSlot } from "./internal/index.js";
5
+ const Card = React.forwardRef(function Card2({ bordered = true, className, ...props }, ref) {
6
+ return /* @__PURE__ */ jsx(
7
+ "div",
8
+ {
9
+ ref,
10
+ className: cn(
11
+ "bg-surface",
12
+ bordered ? "border border-line" : "border border-transparent",
13
+ className
14
+ ),
15
+ ...dataSlot("card"),
16
+ ...props
17
+ }
18
+ );
19
+ });
20
+ const CardHeader = React.forwardRef(
21
+ function CardHeader2({ className, ...props }, ref) {
22
+ return /* @__PURE__ */ jsx(
23
+ "div",
24
+ {
25
+ ref,
26
+ className: cn("flex flex-col gap-1 border-b border-line pad-card pb-3", className),
27
+ ...dataSlot("card", "header"),
28
+ ...props
29
+ }
30
+ );
31
+ }
32
+ );
33
+ const CardBody = React.forwardRef(
34
+ function CardBody2({ className, ...props }, ref) {
35
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("pad-card", className), ...dataSlot("card", "body"), ...props });
36
+ }
37
+ );
38
+ const CardFooter = React.forwardRef(
39
+ function CardFooter2({ className, ...props }, ref) {
40
+ return /* @__PURE__ */ jsx(
41
+ "div",
42
+ {
43
+ ref,
44
+ className: cn("flex flex-wrap items-center gap-2 border-t border-line pad-card pt-3", className),
45
+ ...dataSlot("card", "footer"),
46
+ ...props
47
+ }
48
+ );
49
+ }
50
+ );
51
+ const CARD_TITLE_SIZE = {
52
+ 1: "text-section",
53
+ 2: "text-title",
54
+ 3: "text-lead",
55
+ 4: "text-ui",
56
+ 5: "text-ui",
57
+ 6: "text-label"
58
+ };
59
+ const CardTitle = React.forwardRef(function CardTitle2({ level, className, ...props }, ref) {
60
+ const Tag = `h${level}`;
61
+ return /* @__PURE__ */ jsx(
62
+ Tag,
63
+ {
64
+ ref,
65
+ className: cn("font-semibold text-fg", CARD_TITLE_SIZE[level], className),
66
+ ...dataSlot("card", "title"),
67
+ ...props
68
+ }
69
+ );
70
+ });
71
+ const CardDescription = React.forwardRef(
72
+ function CardDescription2({ className, ...props }, ref) {
73
+ return /* @__PURE__ */ jsx(
74
+ "p",
75
+ {
76
+ ref,
77
+ className: cn("text-micro text-fg-muted", className),
78
+ ...dataSlot("card", "description"),
79
+ ...props
80
+ }
81
+ );
82
+ }
83
+ );
84
+ const Panel = React.forwardRef(function Panel2({ title, description, icon, actions, level = 2, className, children, ...props }, ref) {
85
+ const Heading = `h${level}`;
86
+ return /* @__PURE__ */ jsxs("section", { ref, className: cn("border border-line bg-surface", className), ...dataSlot("panel"), ...props, children: [
87
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3 border-b border-line pad-card", children: [
88
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-start gap-2", children: [
89
+ icon ? /* @__PURE__ */ jsx(
90
+ "span",
91
+ {
92
+ "aria-hidden": "true",
93
+ className: "flex size-7 shrink-0 items-center justify-center bg-surface-3 text-fg-muted",
94
+ children: icon
95
+ }
96
+ ) : null,
97
+ /* @__PURE__ */ jsxs("div", { className: "min-w-0", children: [
98
+ /* @__PURE__ */ jsx(Heading, { className: "text-ui font-semibold leading-tight text-fg", children: title }),
99
+ description ? /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-label leading-tight text-fg-muted", children: description }) : null
100
+ ] })
101
+ ] }),
102
+ actions ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions }) : null
103
+ ] }),
104
+ /* @__PURE__ */ jsx("div", { className: "pad-card", children })
105
+ ] });
106
+ });
107
+ export {
108
+ Card,
109
+ CardBody,
110
+ CardDescription,
111
+ CardFooter,
112
+ CardHeader,
113
+ CardTitle,
114
+ Panel
115
+ };
116
+ //# sourceMappingURL=card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/card.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { cn } from \"@tea-ui/utils\";\n\nimport { dataSlot } from \"./internal\";\n\n/**\n * TEA UI — Card.\n *\n * The single most duplicated element in the source projects: the audit counted\n * **twenty hand-typed copies of a bordered, padded surface** in one product,\n * varying between `p-3`, `p-4`, `p-5`, `p-6` and `p-8`, and with one file\n * defining its own local `Card({ title })` that shadowed the kit concept\n * entirely. This is the one implementation.\n *\n * Two decisions worth stating, because both are load-bearing:\n *\n * - **`CardTitle` renders a heading element, not a `div`.** The source\n * component rendered `<div>` for its title, which silently flattened the\n * heading structure of every page that used it. A screen-reader user\n * navigating by heading had nothing to navigate by. `level` is therefore a\n * prop with no default guess: a card on a page whose top heading is an `h1`\n * almost always wants `h2`, and guessing wrong is invisible until someone\n * needs the outline.\n * - **The surface never overrides its own padding silently.** `CardContent`\n * takes the density's `pad-card` step, so \"how padded is a card\" has one\n * answer rather than twenty.\n */\nexport interface CardProps extends React.ComponentProps<\"div\"> {\n /** Set `false` to drop the border — for a card nested inside another card. */\n bordered?: boolean | undefined;\n className?: string | undefined;\n}\n\nexport const Card = React.forwardRef<HTMLDivElement, CardProps>(function Card(\n { bordered = true, className, ...props },\n ref,\n) {\n return (\n <div\n ref={ref}\n className={cn(\n \"bg-surface\",\n bordered ? \"border border-line\" : \"border border-transparent\",\n className,\n )}\n {...dataSlot(\"card\")}\n {...props}\n />\n );\n});\n\nexport const CardHeader = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n function CardHeader({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n className={cn(\"flex flex-col gap-1 border-b border-line pad-card pb-3\", className)}\n {...dataSlot(\"card\", \"header\")}\n {...props}\n />\n );\n },\n);\n\nexport const CardBody = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n function CardBody({ className, ...props }, ref) {\n return <div ref={ref} className={cn(\"pad-card\", className)} {...dataSlot(\"card\", \"body\")} {...props} />;\n },\n);\n\nexport const CardFooter = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n function CardFooter({ className, ...props }, ref) {\n return (\n <div\n ref={ref}\n className={cn(\"flex flex-wrap items-center gap-2 border-t border-line pad-card pt-3\", className)}\n {...dataSlot(\"card\", \"footer\")}\n {...props}\n />\n );\n },\n);\n\nexport interface CardTitleProps extends React.ComponentProps<\"div\"> {\n /** The heading level. No default: a wrong guess breaks the document outline. */\n level: 1 | 2 | 3 | 4 | 5 | 6;\n className?: string | undefined;\n}\n\nconst CARD_TITLE_SIZE: Record<CardTitleProps[\"level\"], string> = {\n 1: \"text-section\",\n 2: \"text-title\",\n 3: \"text-lead\",\n 4: \"text-ui\",\n 5: \"text-ui\",\n 6: \"text-label\",\n};\n\nexport const CardTitle = React.forwardRef<HTMLHeadingElement, CardTitleProps>(function CardTitle(\n { level, className, ...props },\n ref,\n) {\n const Tag = `h${level}` as \"h2\";\n return (\n <Tag\n ref={ref}\n className={cn(\"font-semibold text-fg\", CARD_TITLE_SIZE[level], className)}\n {...dataSlot(\"card\", \"title\")}\n {...props}\n />\n );\n});\n\nexport const CardDescription = React.forwardRef<HTMLParagraphElement, React.ComponentProps<\"p\">>(\n function CardDescription({ className, ...props }, ref) {\n return (\n <p\n ref={ref}\n className={cn(\"text-micro text-fg-muted\", className)}\n {...dataSlot(\"card\", \"description\")}\n {...props}\n />\n );\n },\n);\n\n/* -------------------------------------------------------------------------- */\n/* Panel: a titled region inside a page */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The audit's second-most-duplicated element: an icon + title + subtitle header\n * appeared at eight call sites with the same class string. `Panel` is that\n * header with a body, and it is what `Card` + `CardHeader` compose into when\n * the region is a section rather than a discrete item.\n */\nexport interface PanelProps extends React.ComponentProps<\"section\"> {\n title: string;\n description?: string | undefined;\n /** Icon before the title. Decorative. */\n icon?: React.ReactNode | undefined;\n /** Right-aligned header content, e.g. a refresh control. */\n actions?: React.ReactNode | undefined;\n /** The heading level of `title`. */\n level?: 2 | 3 | 4 | undefined;\n className?: string | undefined;\n}\n\nexport const Panel = React.forwardRef<HTMLElement, PanelProps>(function Panel(\n { title, description, icon, actions, level = 2, className, children, ...props },\n ref,\n) {\n const Heading = `h${level}` as \"h2\";\n return (\n <section ref={ref} className={cn(\"border border-line bg-surface\", className)} {...dataSlot(\"panel\")} {...props}>\n <div className=\"flex flex-wrap items-start justify-between gap-3 border-b border-line pad-card\">\n <div className=\"flex min-w-0 items-start gap-2\">\n {icon ? (\n <span\n aria-hidden=\"true\"\n className=\"flex size-7 shrink-0 items-center justify-center bg-surface-3 text-fg-muted\"\n >\n {icon}\n </span>\n ) : null}\n <div className=\"min-w-0\">\n <Heading className=\"text-ui font-semibold leading-tight text-fg\">{title}</Heading>\n {description ? (\n <p className=\"mt-0.5 text-label leading-tight text-fg-muted\">{description}</p>\n ) : null}\n </div>\n </div>\n {actions ? <div className=\"flex shrink-0 items-center gap-2\">{actions}</div> : null}\n </div>\n <div className=\"pad-card\">{children}</div>\n </section>\n );\n});\n"],"mappings":"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","names":["Card","CardHeader","CardBody","CardFooter","CardTitle","CardDescription","Panel"]}
@@ -0,0 +1,57 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import * as React from 'react';
3
+ import { VariantProps } from '@tea-ui/utils';
4
+
5
+ /**
6
+ * TEA UI — Alert and Callout.
7
+ *
8
+ * These are **siblings, not aliases**, and the distinction is the whole point:
9
+ *
10
+ * - **`Alert` interrupts.** It owns an ARIA live region, so a screen reader
11
+ * announces it as it appears. Use it when the user must know *now* — an
12
+ * operation failed, a service is down, a destructive action is confirmed.
13
+ * - **`Callout` does not interrupt.** It is static page content: a note in a
14
+ * panel, a hint under a field, an aside in an article. It is present when the
15
+ * user arrives and is never announced after the fact.
16
+ *
17
+ * The audit found nine copy-pasted error banners in one product and none in a
18
+ * component; the class string was identical in all nine, `role="alert"` was
19
+ * present in only two, the text colour drifted between two reds, and the
20
+ * padding drifted between three values. `Alert` makes that divergence
21
+ * impossible.
22
+ */
23
+ declare const alertVariants: (props?: ({
24
+ tone?: "positive" | "info" | "caution" | "critical" | "neutral" | null | undefined;
25
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
26
+ interface AlertProps extends Omit<React.ComponentProps<"div">, "title">, VariantProps<typeof alertVariants> {
27
+ /** Icon shown before the content. Keep it decorative. */
28
+ icon?: React.ReactNode | undefined;
29
+ /** Render a dismiss button. The label comes from `COPY.a11y.close`. */
30
+ onDismiss?: (() => void) | undefined;
31
+ /**
32
+ * Override the live-region role. Defaults to `alert` for interrupting tones
33
+ * and `status` for the rest, which is the correct pairing in both directions.
34
+ */
35
+ role?: "alert" | "status" | undefined;
36
+ className?: string | undefined;
37
+ }
38
+ declare const Alert: React.ForwardRefExoticComponent<Omit<AlertProps, "ref"> & React.RefAttributes<HTMLDivElement>>;
39
+ declare const AlertTitle: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
40
+ declare const AlertDescription: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "ref"> & React.RefAttributes<HTMLParagraphElement>>;
41
+ /** Where the primary recovery action goes. Cancel must stay the easy path. */
42
+ declare const AlertAction: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
43
+ declare const calloutVariants: (props?: ({
44
+ tone?: "positive" | "info" | "caution" | "critical" | "neutral" | null | undefined;
45
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
46
+ interface CalloutProps extends React.ComponentProps<"aside">, VariantProps<typeof calloutVariants> {
47
+ /** The heading. Omit for a plain note. */
48
+ title?: string | undefined;
49
+ className?: string | undefined;
50
+ }
51
+ /**
52
+ * A static, non-interrupting note. Never has a live region, because it was
53
+ * present before the user read it and nothing about it changes afterwards.
54
+ */
55
+ declare const Callout: React.ForwardRefExoticComponent<Omit<CalloutProps, "ref"> & React.RefAttributes<HTMLElement>>;
56
+
57
+ export { Alert, AlertAction, AlertDescription, type AlertProps, AlertTitle, Callout, type CalloutProps, alertVariants, calloutVariants };
@@ -0,0 +1,104 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { X } from "@tea-ui/icons";
4
+ import { COPY } from "@tea-ui/ux-standards";
5
+ import { cn, cva } from "@tea-ui/utils";
6
+ import { dataSlot, stateAttributes } from "../internal/index.js";
7
+ const alertVariants = cva(
8
+ [
9
+ "flex items-start gap-3 border p-3 text-ui",
10
+ "[&>svg]:mt-0.5 [&>svg]:shrink-0"
11
+ ],
12
+ {
13
+ variants: {
14
+ tone: {
15
+ positive: "border-positive-border bg-positive-subtle text-positive",
16
+ info: "border-info-border bg-info-subtle text-info",
17
+ caution: "border-caution-border bg-caution-subtle text-caution",
18
+ critical: "border-critical-border bg-critical-subtle text-critical",
19
+ neutral: "border-line bg-surface-2 text-fg-muted"
20
+ }
21
+ },
22
+ defaultVariants: { tone: "neutral" }
23
+ }
24
+ );
25
+ const INTERRUPTS = {
26
+ positive: false,
27
+ info: false,
28
+ caution: true,
29
+ critical: true,
30
+ neutral: false
31
+ };
32
+ const Alert = React.forwardRef(function Alert2({ className, tone = "neutral", icon, onDismiss, role, children, ...props }, ref) {
33
+ const resolvedTone = tone ?? "neutral";
34
+ const resolvedRole = role ?? (INTERRUPTS[resolvedTone] ? "alert" : "status");
35
+ return /* @__PURE__ */ jsxs(
36
+ "div",
37
+ {
38
+ ref,
39
+ role: resolvedRole,
40
+ className: cn(alertVariants({ tone: resolvedTone }), className),
41
+ ...dataSlot("alert"),
42
+ ...stateAttributes({ invalid: resolvedTone === "critical" }),
43
+ ...props,
44
+ children: [
45
+ icon ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: icon }) : null,
46
+ /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1 text-fg", children }),
47
+ onDismiss ? /* @__PURE__ */ jsx(
48
+ "button",
49
+ {
50
+ type: "button",
51
+ onClick: onDismiss,
52
+ "aria-label": COPY.a11y.close,
53
+ className: "shrink-0 text-fg-muted transition-colors hover:text-fg",
54
+ ...dataSlot("alert", "dismiss"),
55
+ children: /* @__PURE__ */ jsx(X, { size: 16, "aria-hidden": "true" })
56
+ }
57
+ ) : null
58
+ ]
59
+ }
60
+ );
61
+ });
62
+ const AlertTitle = React.forwardRef(
63
+ function AlertTitle2({ className, ...props }, ref) {
64
+ return /* @__PURE__ */ jsx("p", { ref, className: cn("font-semibold text-fg", className), ...dataSlot("alert", "title"), ...props });
65
+ }
66
+ );
67
+ const AlertDescription = React.forwardRef(
68
+ function AlertDescription2({ className, ...props }, ref) {
69
+ return /* @__PURE__ */ jsx("p", { ref, className: cn("text-micro text-fg-muted", className), ...dataSlot("alert", "description"), ...props });
70
+ }
71
+ );
72
+ const AlertAction = React.forwardRef(
73
+ function AlertAction2({ className, ...props }, ref) {
74
+ return /* @__PURE__ */ jsx("div", { ref, className: cn("mt-2 flex flex-wrap items-center gap-2", className), ...dataSlot("alert", "action"), ...props });
75
+ }
76
+ );
77
+ const calloutVariants = cva("border-l-2 py-1 ps-3 text-ui", {
78
+ variants: {
79
+ tone: {
80
+ positive: "border-positive text-fg-muted",
81
+ info: "border-info text-fg-muted",
82
+ caution: "border-caution text-fg-muted",
83
+ critical: "border-critical text-fg-muted",
84
+ neutral: "border-line-strong text-fg-muted"
85
+ }
86
+ },
87
+ defaultVariants: { tone: "neutral" }
88
+ });
89
+ const Callout = React.forwardRef(function Callout2({ className, tone = "neutral", title, children, ...props }, ref) {
90
+ return /* @__PURE__ */ jsxs("aside", { ref, className: cn(calloutVariants({ tone }), className), ...dataSlot("callout"), ...props, children: [
91
+ title ? /* @__PURE__ */ jsx("p", { className: "mb-1 text-micro font-semibold uppercase tracking-widest text-fg", children: title }) : null,
92
+ children
93
+ ] });
94
+ });
95
+ export {
96
+ Alert,
97
+ AlertAction,
98
+ AlertDescription,
99
+ AlertTitle,
100
+ Callout,
101
+ alertVariants,
102
+ calloutVariants
103
+ };
104
+ //# sourceMappingURL=alert.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/feedback/alert.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { X } from \"@tea-ui/icons\";\nimport type { Tone } from \"@tea-ui/tokens\";\nimport { COPY } from \"@tea-ui/ux-standards\";\nimport { cn, cva, type VariantProps } from \"@tea-ui/utils\";\n\nimport { dataSlot, stateAttributes } from \"../internal\";\n\n/**\n * TEA UI — Alert and Callout.\n *\n * These are **siblings, not aliases**, and the distinction is the whole point:\n *\n * - **`Alert` interrupts.** It owns an ARIA live region, so a screen reader\n * announces it as it appears. Use it when the user must know *now* — an\n * operation failed, a service is down, a destructive action is confirmed.\n * - **`Callout` does not interrupt.** It is static page content: a note in a\n * panel, a hint under a field, an aside in an article. It is present when the\n * user arrives and is never announced after the fact.\n *\n * The audit found nine copy-pasted error banners in one product and none in a\n * component; the class string was identical in all nine, `role=\"alert\"` was\n * present in only two, the text colour drifted between two reds, and the\n * padding drifted between three values. `Alert` makes that divergence\n * impossible.\n */\n\nexport const alertVariants = cva(\n [\n \"flex items-start gap-3 border p-3 text-ui\",\n \"[&>svg]:mt-0.5 [&>svg]:shrink-0\",\n ],\n {\n variants: {\n tone: {\n positive: \"border-positive-border bg-positive-subtle text-positive\",\n info: \"border-info-border bg-info-subtle text-info\",\n caution: \"border-caution-border bg-caution-subtle text-caution\",\n critical: \"border-critical-border bg-critical-subtle text-critical\",\n neutral: \"border-line bg-surface-2 text-fg-muted\",\n },\n },\n defaultVariants: { tone: \"neutral\" },\n },\n);\n\n/** A tone interrupts when it means \"the thing you asked for did not happen\". */\nconst INTERRUPTS: Record<Tone, boolean> = {\n positive: false,\n info: false,\n caution: true,\n critical: true,\n neutral: false,\n};\n\nexport interface AlertProps\n extends Omit<React.ComponentProps<\"div\">, \"title\">,\n VariantProps<typeof alertVariants> {\n /** Icon shown before the content. Keep it decorative. */\n icon?: React.ReactNode | undefined;\n /** Render a dismiss button. The label comes from `COPY.a11y.close`. */\n onDismiss?: (() => void) | undefined;\n /**\n * Override the live-region role. Defaults to `alert` for interrupting tones\n * and `status` for the rest, which is the correct pairing in both directions.\n */\n role?: \"alert\" | \"status\" | undefined;\n className?: string | undefined;\n}\n\nexport const Alert = React.forwardRef<HTMLDivElement, AlertProps>(function Alert(\n { className, tone = \"neutral\", icon, onDismiss, role, children, ...props },\n ref,\n) {\n const resolvedTone = tone ?? \"neutral\";\n const resolvedRole = role ?? (INTERRUPTS[resolvedTone] ? \"alert\" : \"status\");\n return (\n <div\n ref={ref}\n role={resolvedRole}\n className={cn(alertVariants({ tone: resolvedTone }), className)}\n {...dataSlot(\"alert\")}\n {...stateAttributes({ invalid: resolvedTone === \"critical\" })}\n {...props}\n >\n {icon ? <span aria-hidden=\"true\">{icon}</span> : null}\n <div className=\"min-w-0 flex-1 text-fg\">{children}</div>\n {onDismiss ? (\n <button\n type=\"button\"\n onClick={onDismiss}\n aria-label={COPY.a11y.close}\n className=\"shrink-0 text-fg-muted transition-colors hover:text-fg\"\n {...dataSlot(\"alert\", \"dismiss\")}\n >\n <X size={16} aria-hidden=\"true\" />\n </button>\n ) : null}\n </div>\n );\n});\n\nexport const AlertTitle = React.forwardRef<HTMLParagraphElement, React.ComponentProps<\"p\">>(\n function AlertTitle({ className, ...props }, ref) {\n return <p ref={ref} className={cn(\"font-semibold text-fg\", className)} {...dataSlot(\"alert\", \"title\")} {...props} />;\n },\n);\n\nexport const AlertDescription = React.forwardRef<HTMLParagraphElement, React.ComponentProps<\"p\">>(\n function AlertDescription({ className, ...props }, ref) {\n return <p ref={ref} className={cn(\"text-micro text-fg-muted\", className)} {...dataSlot(\"alert\", \"description\")} {...props} />;\n },\n);\n\n/** Where the primary recovery action goes. Cancel must stay the easy path. */\nexport const AlertAction = React.forwardRef<HTMLDivElement, React.ComponentProps<\"div\">>(\n function AlertAction({ className, ...props }, ref) {\n return <div ref={ref} className={cn(\"mt-2 flex flex-wrap items-center gap-2\", className)} {...dataSlot(\"alert\", \"action\")} {...props} />;\n },\n);\n\n/* -------------------------------------------------------------------------- */\n\nexport const calloutVariants = cva(\"border-l-2 py-1 ps-3 text-ui\", {\n variants: {\n tone: {\n positive: \"border-positive text-fg-muted\",\n info: \"border-info text-fg-muted\",\n caution: \"border-caution text-fg-muted\",\n critical: \"border-critical text-fg-muted\",\n neutral: \"border-line-strong text-fg-muted\",\n },\n },\n defaultVariants: { tone: \"neutral\" },\n});\n\nexport interface CalloutProps extends React.ComponentProps<\"aside\">, VariantProps<typeof calloutVariants> {\n /** The heading. Omit for a plain note. */\n title?: string | undefined;\n className?: string | undefined;\n}\n\n/**\n * A static, non-interrupting note. Never has a live region, because it was\n * present before the user read it and nothing about it changes afterwards.\n */\nexport const Callout = React.forwardRef<HTMLElement, CalloutProps>(function Callout(\n { className, tone = \"neutral\", title, children, ...props },\n ref,\n) {\n return (\n <aside ref={ref} className={cn(calloutVariants({ tone }), className)} {...dataSlot(\"callout\")} {...props}>\n {title ? <p className=\"mb-1 text-micro font-semibold uppercase tracking-widest text-fg\">{title}</p> : null}\n {children}\n </aside>\n );\n});\n"],"mappings":"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","names":["Alert","AlertTitle","AlertDescription","AlertAction","Callout"]}
@@ -0,0 +1,34 @@
1
+ import * as class_variance_authority_types from 'class-variance-authority/types';
2
+ import * as React from 'react';
3
+ import { Tone } from '@tea-ui/tokens';
4
+ import { VariantProps } from '@tea-ui/utils';
5
+
6
+ /**
7
+ * TEA UI — Badge.
8
+ *
9
+ * A short, static label. Deliberately not a status: for that, use `StatusBadge`
10
+ * from `status.tsx`, which reads the shared status registry. Two renderers for
11
+ * two different jobs is the point — a source project had *seven* ad-hoc status
12
+ * renderers, none of which agreed.
13
+ *
14
+ * Two audit defects are fixed here:
15
+ * - **Element.** The source project's Badge rendered a `<div>` and was placed
16
+ * inside `<p>` elements across three pages. That is invalid HTML, and
17
+ * assistive technology handles it unpredictably. A Badge renders a `<span>`.
18
+ * - **Geometry.** It renders `rounded-none`. In this design language a pill is
19
+ * a status, and using it decoratively destroys that meaning.
20
+ */
21
+ declare const badgeVariants: (props?: ({
22
+ variant?: "solid" | "subtle" | "outline" | null | undefined;
23
+ tone?: "positive" | "info" | "caution" | "critical" | "neutral" | null | undefined;
24
+ } & class_variance_authority_types.ClassProp) | undefined) => string;
25
+ interface BadgeProps extends Omit<React.ComponentProps<"span">, "color">, VariantProps<typeof badgeVariants> {
26
+ /** Render the consumer's child element instead of a `<span>`. */
27
+ asChild?: boolean | undefined;
28
+ className?: string | undefined;
29
+ /** Convenience passthrough so a tone can be derived from a status. */
30
+ tone?: Tone | undefined;
31
+ }
32
+ declare const Badge: React.ForwardRefExoticComponent<Omit<BadgeProps, "ref"> & React.RefAttributes<HTMLSpanElement>>;
33
+
34
+ export { Badge, type BadgeProps, badgeVariants };
@@ -0,0 +1,62 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { Slot } from "radix-ui";
4
+ import { cn, cva } from "@tea-ui/utils";
5
+ import { dataSlot } from "../internal/index.js";
6
+ const badgeVariants = cva(
7
+ [
8
+ "inline-flex items-center gap-1 border px-2 py-0.5 text-micro font-medium leading-none",
9
+ "whitespace-nowrap"
10
+ ],
11
+ {
12
+ variants: {
13
+ variant: {
14
+ subtle: "border-transparent",
15
+ solid: "border-transparent",
16
+ outline: "bg-transparent"
17
+ },
18
+ tone: {
19
+ positive: "",
20
+ info: "",
21
+ caution: "",
22
+ critical: "",
23
+ neutral: ""
24
+ }
25
+ },
26
+ compoundVariants: [
27
+ { variant: "subtle", tone: "positive", class: "bg-positive-subtle text-positive border-positive-border" },
28
+ { variant: "subtle", tone: "info", class: "bg-info-subtle text-info border-info-border" },
29
+ { variant: "subtle", tone: "caution", class: "bg-caution-subtle text-caution border-caution-border" },
30
+ { variant: "subtle", tone: "critical", class: "bg-critical-subtle text-critical border-critical-border" },
31
+ { variant: "subtle", tone: "neutral", class: "bg-neutral-subtle text-fg-muted border-neutral-border" },
32
+ { variant: "solid", tone: "positive", class: "bg-positive text-positive-fg" },
33
+ { variant: "solid", tone: "info", class: "bg-info text-info-fg" },
34
+ { variant: "solid", tone: "caution", class: "bg-caution text-caution-fg" },
35
+ { variant: "solid", tone: "critical", class: "bg-critical text-critical-fg" },
36
+ { variant: "solid", tone: "neutral", class: "bg-neutral text-neutral-fg" },
37
+ { variant: "outline", tone: "positive", class: "border-positive text-positive" },
38
+ { variant: "outline", tone: "info", class: "border-info text-info" },
39
+ { variant: "outline", tone: "caution", class: "border-caution text-caution" },
40
+ { variant: "outline", tone: "critical", class: "border-critical text-critical" },
41
+ { variant: "outline", tone: "neutral", class: "border-line-strong text-fg-muted" }
42
+ ],
43
+ defaultVariants: { variant: "subtle", tone: "neutral" }
44
+ }
45
+ );
46
+ const Badge = React.forwardRef(function Badge2({ className, variant, tone, asChild = false, ...props }, ref) {
47
+ const Component = asChild ? Slot.Root : "span";
48
+ return /* @__PURE__ */ jsx(
49
+ Component,
50
+ {
51
+ ref,
52
+ className: cn(badgeVariants({ variant, tone, className })),
53
+ ...dataSlot("badge"),
54
+ ...props
55
+ }
56
+ );
57
+ });
58
+ export {
59
+ Badge,
60
+ badgeVariants
61
+ };
62
+ //# sourceMappingURL=badge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/feedback/badge.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Slot } from \"radix-ui\";\nimport type { Tone } from \"@tea-ui/tokens\";\nimport { cn, cva, type VariantProps } from \"@tea-ui/utils\";\n\nimport { dataSlot } from \"../internal\";\n\n/**\n * TEA UI — Badge.\n *\n * A short, static label. Deliberately not a status: for that, use `StatusBadge`\n * from `status.tsx`, which reads the shared status registry. Two renderers for\n * two different jobs is the point — a source project had *seven* ad-hoc status\n * renderers, none of which agreed.\n *\n * Two audit defects are fixed here:\n * - **Element.** The source project's Badge rendered a `<div>` and was placed\n * inside `<p>` elements across three pages. That is invalid HTML, and\n * assistive technology handles it unpredictably. A Badge renders a `<span>`.\n * - **Geometry.** It renders `rounded-none`. In this design language a pill is\n * a status, and using it decoratively destroys that meaning.\n */\nexport const badgeVariants = cva(\n [\n \"inline-flex items-center gap-1 border px-2 py-0.5 text-micro font-medium leading-none\",\n \"whitespace-nowrap\",\n ],\n {\n variants: {\n variant: {\n subtle: \"border-transparent\",\n solid: \"border-transparent\",\n outline: \"bg-transparent\",\n },\n tone: {\n positive: \"\",\n info: \"\",\n caution: \"\",\n critical: \"\",\n neutral: \"\",\n },\n },\n compoundVariants: [\n { variant: \"subtle\", tone: \"positive\", class: \"bg-positive-subtle text-positive border-positive-border\" },\n { variant: \"subtle\", tone: \"info\", class: \"bg-info-subtle text-info border-info-border\" },\n { variant: \"subtle\", tone: \"caution\", class: \"bg-caution-subtle text-caution border-caution-border\" },\n { variant: \"subtle\", tone: \"critical\", class: \"bg-critical-subtle text-critical border-critical-border\" },\n { variant: \"subtle\", tone: \"neutral\", class: \"bg-neutral-subtle text-fg-muted border-neutral-border\" },\n\n { variant: \"solid\", tone: \"positive\", class: \"bg-positive text-positive-fg\" },\n { variant: \"solid\", tone: \"info\", class: \"bg-info text-info-fg\" },\n { variant: \"solid\", tone: \"caution\", class: \"bg-caution text-caution-fg\" },\n { variant: \"solid\", tone: \"critical\", class: \"bg-critical text-critical-fg\" },\n { variant: \"solid\", tone: \"neutral\", class: \"bg-neutral text-neutral-fg\" },\n\n { variant: \"outline\", tone: \"positive\", class: \"border-positive text-positive\" },\n { variant: \"outline\", tone: \"info\", class: \"border-info text-info\" },\n { variant: \"outline\", tone: \"caution\", class: \"border-caution text-caution\" },\n { variant: \"outline\", tone: \"critical\", class: \"border-critical text-critical\" },\n { variant: \"outline\", tone: \"neutral\", class: \"border-line-strong text-fg-muted\" },\n ],\n defaultVariants: { variant: \"subtle\", tone: \"neutral\" },\n },\n);\n\nexport interface BadgeProps\n extends Omit<React.ComponentProps<\"span\">, \"color\">,\n VariantProps<typeof badgeVariants> {\n /** Render the consumer's child element instead of a `<span>`. */\n asChild?: boolean | undefined;\n className?: string | undefined;\n /** Convenience passthrough so a tone can be derived from a status. */\n tone?: Tone | undefined;\n}\n\nexport const Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(function Badge(\n { className, variant, tone, asChild = false, ...props },\n ref,\n) {\n const Component = asChild ? Slot.Root : \"span\";\n return (\n <Component\n ref={ref}\n className={cn(badgeVariants({ variant, tone, className }))}\n {...dataSlot(\"badge\")}\n {...props}\n />\n );\n});\n"],"mappings":"AAiFI;AAjFJ,YAAY,WAAW;AACvB,SAAS,YAAY;AAErB,SAAS,IAAI,WAA8B;AAE3C,SAAS,gBAAgB;AAiBlB,MAAM,gBAAgB;AAAA,EAC3B;AAAA,IACE;AAAA,IACA;AAAA,EACF;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,SAAS;AAAA,MACX;AAAA,MACA,MAAM;AAAA,QACJ,UAAU;AAAA,QACV,MAAM;AAAA,QACN,SAAS;AAAA,QACT,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,kBAAkB;AAAA,MAChB,EAAE,SAAS,UAAU,MAAM,YAAY,OAAO,0DAA0D;AAAA,MACxG,EAAE,SAAS,UAAU,MAAM,QAAQ,OAAO,8CAA8C;AAAA,MACxF,EAAE,SAAS,UAAU,MAAM,WAAW,OAAO,uDAAuD;AAAA,MACpG,EAAE,SAAS,UAAU,MAAM,YAAY,OAAO,0DAA0D;AAAA,MACxG,EAAE,SAAS,UAAU,MAAM,WAAW,OAAO,wDAAwD;AAAA,MAErG,EAAE,SAAS,SAAS,MAAM,YAAY,OAAO,+BAA+B;AAAA,MAC5E,EAAE,SAAS,SAAS,MAAM,QAAQ,OAAO,uBAAuB;AAAA,MAChE,EAAE,SAAS,SAAS,MAAM,WAAW,OAAO,6BAA6B;AAAA,MACzE,EAAE,SAAS,SAAS,MAAM,YAAY,OAAO,+BAA+B;AAAA,MAC5E,EAAE,SAAS,SAAS,MAAM,WAAW,OAAO,6BAA6B;AAAA,MAEzE,EAAE,SAAS,WAAW,MAAM,YAAY,OAAO,gCAAgC;AAAA,MAC/E,EAAE,SAAS,WAAW,MAAM,QAAQ,OAAO,wBAAwB;AAAA,MACnE,EAAE,SAAS,WAAW,MAAM,WAAW,OAAO,8BAA8B;AAAA,MAC5E,EAAE,SAAS,WAAW,MAAM,YAAY,OAAO,gCAAgC;AAAA,MAC/E,EAAE,SAAS,WAAW,MAAM,WAAW,OAAO,mCAAmC;AAAA,IACnF;AAAA,IACA,iBAAiB,EAAE,SAAS,UAAU,MAAM,UAAU;AAAA,EACxD;AACF;AAYO,MAAM,QAAQ,MAAM,WAAwC,SAASA,OAC1E,EAAE,WAAW,SAAS,MAAM,UAAU,OAAO,GAAG,MAAM,GACtD,KACA;AACA,QAAM,YAAY,UAAU,KAAK,OAAO;AACxC,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,GAAG,cAAc,EAAE,SAAS,MAAM,UAAU,CAAC,CAAC;AAAA,MACxD,GAAG,SAAS,OAAO;AAAA,MACnB,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;","names":["Badge"]}
@@ -0,0 +1,13 @@
1
+ export { Spinner, SpinnerProps, SpinnerSize } from './spinner.js';
2
+ export { Skeleton, SkeletonProps, SkeletonText, SkeletonTextProps, skeletonVariants } from './skeleton.js';
3
+ export { Progress, ProgressProps } from './progress.js';
4
+ export { Badge, BadgeProps, badgeVariants } from './badge.js';
5
+ export { StatusBadge, StatusBadgeProps, StatusBaseProps, StatusDomainKey, StatusDot, StatusDotProps, StatusSelect, StatusSelectProps, StatusText, StatusTextProps } from './status.js';
6
+ export { Alert, AlertAction, AlertDescription, AlertProps, AlertTitle, Callout, CalloutProps, alertVariants, calloutVariants } from './alert.js';
7
+ export { TOAST_LIMIT, TeaToast, ToastClose, ToastDescription, ToastInput, ToastRoot, ToastSurfaceProps, ToastTitle, Toaster, UseToastResult, toast, useToast } from './toast.js';
8
+ import 'react';
9
+ import 'class-variance-authority/types';
10
+ import '@tea-ui/utils';
11
+ import 'radix-ui';
12
+ import '@tea-ui/tokens';
13
+ import '@tea-ui/ux-standards';
@@ -0,0 +1,62 @@
1
+ import { Spinner } from "./spinner.js";
2
+ import {
3
+ Skeleton,
4
+ SkeletonText,
5
+ skeletonVariants
6
+ } from "./skeleton.js";
7
+ import { Progress } from "./progress.js";
8
+ import { Badge, badgeVariants } from "./badge.js";
9
+ import {
10
+ StatusDot,
11
+ StatusBadge,
12
+ StatusText,
13
+ StatusSelect
14
+ } from "./status.js";
15
+ import {
16
+ Alert,
17
+ AlertAction,
18
+ AlertDescription,
19
+ AlertTitle,
20
+ Callout,
21
+ alertVariants,
22
+ calloutVariants
23
+ } from "./alert.js";
24
+ import {
25
+ ToastClose,
26
+ ToastDescription,
27
+ ToastRoot,
28
+ ToastTitle,
29
+ Toaster,
30
+ toast,
31
+ useToast,
32
+ TOAST_LIMIT
33
+ } from "./toast.js";
34
+ export {
35
+ Alert,
36
+ AlertAction,
37
+ AlertDescription,
38
+ AlertTitle,
39
+ Badge,
40
+ Callout,
41
+ Progress,
42
+ Skeleton,
43
+ SkeletonText,
44
+ Spinner,
45
+ StatusBadge,
46
+ StatusDot,
47
+ StatusSelect,
48
+ StatusText,
49
+ TOAST_LIMIT,
50
+ ToastClose,
51
+ ToastDescription,
52
+ ToastRoot,
53
+ ToastTitle,
54
+ Toaster,
55
+ alertVariants,
56
+ badgeVariants,
57
+ calloutVariants,
58
+ skeletonVariants,
59
+ toast,
60
+ useToast
61
+ };
62
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/feedback/index.ts"],"sourcesContent":["/**\n * TEA UI — feedback surface.\n *\n * Loading, progress, status and interruption. Per the feedback standard, every\n * asynchronous surface in a TEA product is in one of seventeen named states,\n * and the affordance for each is decided rather than chosen per call site.\n */\nexport { Spinner, type SpinnerProps, type SpinnerSize } from \"./spinner\";\nexport {\n Skeleton,\n SkeletonText,\n skeletonVariants,\n type SkeletonProps,\n type SkeletonTextProps,\n} from \"./skeleton\";\nexport { Progress, type ProgressProps } from \"./progress\";\nexport { Badge, badgeVariants, type BadgeProps } from \"./badge\";\nexport {\n StatusDot,\n StatusBadge,\n StatusText,\n StatusSelect,\n type StatusBaseProps,\n type StatusBadgeProps,\n type StatusDotProps,\n type StatusSelectProps,\n type StatusTextProps,\n type StatusDomainKey,\n} from \"./status\";\nexport {\n Alert,\n AlertAction,\n AlertDescription,\n AlertTitle,\n Callout,\n alertVariants,\n calloutVariants,\n type AlertProps,\n type CalloutProps,\n} from \"./alert\";\nexport {\n ToastClose,\n ToastDescription,\n ToastRoot,\n ToastTitle,\n Toaster,\n toast,\n useToast,\n TOAST_LIMIT,\n type TeaToast,\n type ToastInput,\n type ToastSurfaceProps,\n type UseToastResult,\n} from \"./toast\";\n"],"mappings":"AAOA,SAAS,eAAoD;AAC7D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP,SAAS,gBAAoC;AAC7C,SAAS,OAAO,qBAAsC;AACtD;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAOK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AACP;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAKK;","names":[]}