@enmera/panel-kit 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +98 -2
  4. package/README.tr.md +59 -0
  5. package/dist/config.d.ts +18 -0
  6. package/dist/config.js +14 -0
  7. package/dist/empty-state.d.ts +7 -0
  8. package/dist/empty-state.js +5 -0
  9. package/dist/hooks/use-mobile.d.ts +1 -0
  10. package/dist/hooks/use-mobile.js +15 -0
  11. package/dist/section-card.d.ts +16 -0
  12. package/dist/section-card.js +13 -0
  13. package/dist/stat-cards.d.ts +15 -0
  14. package/dist/stat-cards.js +32 -0
  15. package/dist/status-badge.d.ts +29 -0
  16. package/dist/status-badge.js +27 -0
  17. package/dist/summary-strip.d.ts +18 -0
  18. package/dist/summary-strip.js +15 -0
  19. package/dist/text.d.ts +7 -0
  20. package/dist/text.js +8 -0
  21. package/dist/ui/alert-dialog.d.ts +22 -0
  22. package/dist/ui/alert-dialog.js +38 -0
  23. package/dist/ui/avatar.d.ts +10 -0
  24. package/dist/ui/avatar.js +23 -0
  25. package/dist/ui/badge.d.ts +8 -0
  26. package/dist/ui/badge.js +31 -0
  27. package/dist/ui/breadcrumb.d.ts +11 -0
  28. package/dist/ui/breadcrumb.js +25 -0
  29. package/dist/ui/button.d.ts +14 -0
  30. package/dist/ui/button.js +67 -0
  31. package/dist/ui/calendar.d.ts +24 -0
  32. package/dist/ui/calendar.js +54 -0
  33. package/dist/ui/card.d.ts +11 -0
  34. package/dist/ui/card.js +24 -0
  35. package/dist/ui/chart.d.ts +44 -0
  36. package/dist/ui/chart.js +137 -0
  37. package/dist/ui/checkbox.d.ts +3 -0
  38. package/dist/ui/checkbox.js +9 -0
  39. package/dist/ui/chip.d.ts +11 -0
  40. package/dist/ui/chip.js +10 -0
  41. package/dist/ui/code.d.ts +2 -0
  42. package/dist/ui/code.js +6 -0
  43. package/dist/ui/collapsible.d.ts +5 -0
  44. package/dist/ui/collapsible.js +12 -0
  45. package/dist/ui/combobox.d.ts +32 -0
  46. package/dist/ui/combobox.js +77 -0
  47. package/dist/ui/command.d.ts +27 -0
  48. package/dist/ui/command.js +36 -0
  49. package/dist/ui/dialog.d.ts +21 -0
  50. package/dist/ui/dialog.js +32 -0
  51. package/dist/ui/dropdown-menu.d.ts +26 -0
  52. package/dist/ui/dropdown-menu.js +48 -0
  53. package/dist/ui/field.d.ts +24 -0
  54. package/dist/ui/field.js +67 -0
  55. package/dist/ui/heading.d.ts +24 -0
  56. package/dist/ui/heading.js +24 -0
  57. package/dist/ui/icon-tile.d.ts +17 -0
  58. package/dist/ui/icon-tile.js +17 -0
  59. package/dist/ui/input-group.d.ts +19 -0
  60. package/dist/ui/input-group.js +58 -0
  61. package/dist/ui/input.d.ts +8 -0
  62. package/dist/ui/input.js +7 -0
  63. package/dist/ui/label.d.ts +3 -0
  64. package/dist/ui/label.js +12 -0
  65. package/dist/ui/meta.d.ts +13 -0
  66. package/dist/ui/meta.js +18 -0
  67. package/dist/ui/option-card.d.ts +9 -0
  68. package/dist/ui/option-card.js +10 -0
  69. package/dist/ui/pagination.d.ts +17 -0
  70. package/dist/ui/pagination.js +27 -0
  71. package/dist/ui/popover.d.ts +10 -0
  72. package/dist/ui/popover.js +19 -0
  73. package/dist/ui/radio-group.d.ts +4 -0
  74. package/dist/ui/radio-group.js +11 -0
  75. package/dist/ui/row-button.d.ts +9 -0
  76. package/dist/ui/row-button.js +16 -0
  77. package/dist/ui/scroll-area.d.ts +3 -0
  78. package/dist/ui/scroll-area.js +7 -0
  79. package/dist/ui/segmented.d.ts +22 -0
  80. package/dist/ui/segmented.js +16 -0
  81. package/dist/ui/select.d.ts +26 -0
  82. package/dist/ui/select.js +45 -0
  83. package/dist/ui/separator.d.ts +3 -0
  84. package/dist/ui/separator.js +8 -0
  85. package/dist/ui/sheet.d.ts +20 -0
  86. package/dist/ui/sheet.js +34 -0
  87. package/dist/ui/sidebar.d.ts +77 -0
  88. package/dist/ui/sidebar.js +204 -0
  89. package/dist/ui/skeleton.d.ts +2 -0
  90. package/dist/ui/skeleton.js +6 -0
  91. package/dist/ui/slider.d.ts +11 -0
  92. package/dist/ui/slider.js +13 -0
  93. package/dist/ui/sonner.d.ts +7 -0
  94. package/dist/ui/sonner.js +38 -0
  95. package/dist/ui/switch.d.ts +5 -0
  96. package/dist/ui/switch.js +8 -0
  97. package/dist/ui/table.d.ts +11 -0
  98. package/dist/ui/table.js +28 -0
  99. package/dist/ui/tabs.d.ts +15 -0
  100. package/dist/ui/tabs.js +73 -0
  101. package/dist/ui/text-button.d.ts +21 -0
  102. package/dist/ui/text-button.js +21 -0
  103. package/dist/ui/textarea.d.ts +9 -0
  104. package/dist/ui/textarea.js +7 -0
  105. package/dist/ui/tile.d.ts +27 -0
  106. package/dist/ui/tile.js +30 -0
  107. package/dist/ui/tooltip.d.ts +8 -0
  108. package/dist/ui/tooltip.js +24 -0
  109. package/dist/utils.d.ts +1 -0
  110. package/dist/utils.js +1 -0
  111. package/lang/tr.json +16 -0
  112. package/package.json +83 -4
  113. package/theme.css +17 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - `Button` `variant="destructive-ghost"`: row delete/remove icons; red text, background only on hover.
6
+ - `TextButton` / `TextLink` `tone="danger"`.
7
+ - `Heading` `size="xs"` for dense tool panels.
8
+ - `Input` `size="xs"` and `mono`; `Textarea` `size="sm"` and `mono` (codes, keys, JSON).
9
+
10
+ ## 0.1.0
11
+
12
+ - First release: the shared components of the Searvia panel, with `configurePanelKit` for translation, locale and
13
+ number/date formatting, `theme.css` for Tailwind CSS v4 and Turkish texts in `lang/tr.json`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Enmera
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 CHANGED
@@ -1,3 +1,99 @@
1
- # Temporary Holding Version
1
+ # @enmera/panel-kit
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Shared components for admin panels built with React 19, [react-aria](https://react-spectrum.adobe.com/react-aria/) and
4
+ Tailwind CSS v4. One look for every button, input, badge, box and heading, so the same thing looks the same on every
5
+ screen and in every product that uses the kit.
6
+
7
+ [Türkçe](README.tr.md)
8
+
9
+ It grew out of two production panels ([Searvia](https://searvia.com) and Enmera Commerce). Its rules are checked by
10
+ [@enmera/ai-design-check](https://github.com/enmerasoftware/ai-design-check): pages pick a component, a tone and a size;
11
+ they do not write the look themselves.
12
+
13
+ ## Install
14
+
15
+ ```bash
16
+ npm install @enmera/panel-kit react-aria-components class-variance-authority cn lucide-react
17
+ # optional, for charts, toasts and themed toasts:
18
+ npm install recharts sonner next-themes
19
+ ```
20
+
21
+ In your main CSS file, after Tailwind:
22
+
23
+ ```css
24
+ @import "tailwindcss";
25
+ @import "@enmera/panel-kit/theme.css";
26
+ ```
27
+
28
+ `theme.css` makes Tailwind scan the kit's classes and gives defaults to the few tokens it uses beyond the usual shadcn
29
+ ones (`--color-ink`, `--color-brand-link`, `--color-on-brand`, `--color-on-brand-ink`, `--text-2xs`, `--font-display`).
30
+ Your own values win. Colours come from your theme (`--primary`, `--muted`, `--card`, `--sidebar` …), so each product
31
+ keeps its own palette.
32
+
33
+ Once at start-up, connect your translation, locale and number/date formatting:
34
+
35
+ ```ts
36
+ import { configurePanelKit } from '@enmera/panel-kit/config';
37
+
38
+ configurePanelKit({ t, locale: () => 'tr-TR', formatNumber, formatDate });
39
+ ```
40
+
41
+ Without it the kit uses its English text and the browser's locale. Keys are the English text itself; Turkish is in
42
+ `@enmera/panel-kit/lang/tr.json` — merge it into your dictionary.
43
+
44
+ ## Use
45
+
46
+ ```tsx
47
+ import { Button, LinkButton } from '@enmera/panel-kit/ui/button';
48
+ import { StatusBadge } from '@enmera/panel-kit/status-badge';
49
+ import { Tile } from '@enmera/panel-kit/ui/tile';
50
+ import { Heading } from '@enmera/panel-kit/ui/heading';
51
+
52
+ <Tile tone="warning" className="flex items-center gap-3">
53
+ <StatusBadge tone="warning">Pending</StatusBadge>
54
+ <Heading as="h3" size="sm">Payment method needs attention</Heading>
55
+ <LinkButton href="/billing" size="sm" variant="outline">Open billing</LinkButton>
56
+ </Tile>
57
+ ```
58
+
59
+ The rule: **look from props, placement from `className`.** Colour, radius, border, ring and shadow belong to the
60
+ component; pages add width, margin and grid position. Boxes and rows (Tile, SectionCard, RowButton, ListRow …) also
61
+ take their padding, gap and inner layout from the caller. If a tone or size is missing, add it to the component, not a
62
+ class at the call site.
63
+
64
+ | What | Component | Options |
65
+ |---|---|---|
66
+ | Button, link button | `ui/button`: `Button`, `LinkButton` | default, outline, secondary, ghost, inverse, light, on-brand, on-brand-soft, floating, warning, caution, destructive, destructive-ghost, link · xs, sm, default, lg, icon sizes |
67
+ | Text button and link | `ui/text-button`: `TextButton`, `TextLink` | primary, muted, brand, warning, danger · xs, sm |
68
+ | Clickable row | `ui/row-button`: `RowButton` (`isSelected`), `RowLink` | padding from the caller |
69
+ | Selectable card | `ui/option-card`: `OptionCard` (`isSelected`) | |
70
+ | Main choice, filter pill | `ui/segmented`: `Segmented`; `ui/chip`: `Chip` | |
71
+ | Badge | `status-badge`: `StatusBadge` | success, danger, warning, info, purple, neutral, primary, accent, overlay · sm, default |
72
+ | Box, section | `ui/tile`: `Tile`, `TooltipBox`; `section-card`: `SectionCard` | default, primary, muted, success, warning, danger, info · sm, default, lg, flush · `interactive`; SectionCard `highlighted`, `flush` |
73
+ | Heading | `ui/heading`: `Heading` | mega, hero, display, section, title, subtitle, card, small, base, sm, xs |
74
+ | Icon background | `ui/icon-tile`: `IconTile` | beside text, not above a heading |
75
+ | Small parts | `ui/code`: `Code`; `ui/meta`: `MetaRow`, `List`, `ListRow` | |
76
+ | Forms and overlays | `ui/input`, `ui/input-group`, `ui/select`, `ui/combobox`, `ui/textarea`, `ui/checkbox`, `ui/radio-group`, `ui/switch`, `ui/slider`, `ui/field`, `ui/dialog`, `ui/alert-dialog`, `ui/sheet`, `ui/popover`, `ui/dropdown-menu`, `ui/tooltip`, `ui/command` | |
77
+ | Layout and data | `ui/sidebar`, `ui/tabs`, `ui/table`, `ui/pagination`, `ui/breadcrumb`, `ui/card`, `ui/chart`, `ui/calendar`, `stat-cards`, `summary-strip`, `empty-state` | |
78
+ | Case | `text`: `lowerText`, `upperText` (locale rules), `upperCode`, `lowerCode` (codes) | never `toUpperCase()` |
79
+
80
+ ## With ai-design-check
81
+
82
+ ```json
83
+ {
84
+ "looks": { "badge": "StatusBadge", "card": "Tile or SectionCard", "heading": "Heading", "link": "LinkButton" },
85
+ "sharedComponents": ["Button", "LinkButton", "StatusBadge", "Input", "Select", "Textarea", "Tile", "SectionCard", "Chip", "Segmented", "TextButton", "TextLink", "RowButton", "RowLink", "Code", "MetaRow", "List"]
86
+ }
87
+ ```
88
+
89
+ `npx @enmera/ai-design-check inventory` counts how many looks each kind of element has; the kit is how that number
90
+ goes down.
91
+
92
+ ## Versions
93
+
94
+ Semantic versioning. A change to a component's look is a minor version and is listed in [CHANGELOG.md](CHANGELOG.md);
95
+ removing a prop or variant is a major version.
96
+
97
+ ## License
98
+
99
+ MIT
package/README.tr.md ADDED
@@ -0,0 +1,59 @@
1
+ # @enmera/panel-kit
2
+
3
+ React 19, [react-aria](https://react-spectrum.adobe.com/react-aria/) ve Tailwind CSS v4 ile yapılan yönetim panelleri
4
+ için ortak bileşenler. Her düğme, giriş alanı, rozet, kutu ve başlık için tek görünüm: aynı şey her ekranda ve kiti
5
+ kullanan her üründe aynı görünür.
6
+
7
+ [English](README.md)
8
+
9
+ İki canlı panelden ([Searvia](https://searvia.com) ve Enmera Commerce) çıktı. Kuralları
10
+ [@enmera/ai-design-check](https://github.com/enmerasoftware/ai-design-check) denetler: sayfa bileşen, ton ve boyut
11
+ seçer; görünümü kendisi yazmaz.
12
+
13
+ ## Kurulum
14
+
15
+ ```bash
16
+ npm install @enmera/panel-kit react-aria-components class-variance-authority cn lucide-react
17
+ # isteğe bağlı (grafik, bildirim, temalı bildirim):
18
+ npm install recharts sonner next-themes
19
+ ```
20
+
21
+ Ana CSS dosyasında, Tailwind'den sonra:
22
+
23
+ ```css
24
+ @import "tailwindcss";
25
+ @import "@enmera/panel-kit/theme.css";
26
+ ```
27
+
28
+ `theme.css` Tailwind'e kitin sınıflarını taratır ve shadcn belirteçleri dışında kullandığı birkaç belirtece varsayılan
29
+ verir (`--color-ink`, `--color-brand-link`, `--color-on-brand`, `--color-on-brand-ink`, `--text-2xs`, `--font-display`).
30
+ Projenin kendi değeri geçerlidir. Renkler projenin temasından gelir (`--primary`, `--muted`, `--card`, `--sidebar` …);
31
+ her ürün kendi paletini korur.
32
+
33
+ Açılışta bir kez çeviri, dil ve sayı/tarih biçimi bağlanır:
34
+
35
+ ```ts
36
+ import { configurePanelKit } from '@enmera/panel-kit/config';
37
+
38
+ configurePanelKit({ t, locale: () => 'tr-TR', formatNumber, formatDate });
39
+ ```
40
+
41
+ Bağlanmazsa İngilizce metin ve tarayıcının dili kullanılır. Anahtarlar İngilizce metnin kendisidir; Türkçesi
42
+ `@enmera/panel-kit/lang/tr.json` dosyasında, projenin sözlüğüne eklenir.
43
+
44
+ ## Kullanım
45
+
46
+ Kural: **görünüm prop'tan, yerleşim `className`'den.** Renk, köşe, çerçeve, halka ve gölge bileşenindir; sayfa genişlik,
47
+ boşluk ve ızgara konumu ekler. Kutular ve satırlar (Tile, SectionCard, RowButton, ListRow …) iç boşluğu ve iç yerleşimi
48
+ de çağırandan alır. Uygun ton ya da boyut yoksa çağrı yerine sınıf değil, bileşene ton ya da boyut eklenir.
49
+
50
+ Bileşen listesi ve seçenekler için [README.md](README.md#use).
51
+
52
+ ## Sürümler
53
+
54
+ Anlamsal sürümleme. Bir bileşenin görünümünü değiştiren değişiklik ara sürümdür ve [CHANGELOG.md](CHANGELOG.md)'de
55
+ yazılır; prop ya da görünüm kaldırmak ana sürümdür.
56
+
57
+ ## Lisans
58
+
59
+ MIT
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Paketin projeye bağlandığı tek yer: çeviri, dil ve biçimlendirme projeden gelir.
3
+ * Proje açılışta bir kez `configurePanelKit({ t, locale, formatNumber, formatDate })` çağırır; çağırmazsa İngilizce metin
4
+ * ve tarayıcı dili kullanılır. Bileşenlerdeki metin anahtarları İngilizce kaynak metnin kendisidir (`lang/tr.json`).
5
+ */
6
+ export type Translate = (key: string, replacements?: Record<string, string | number>) => string;
7
+ type Config = {
8
+ t: Translate;
9
+ locale: () => string;
10
+ formatNumber: (value: number) => string;
11
+ formatDate: (value: string) => string;
12
+ };
13
+ export declare function configurePanelKit(options: Partial<Config>): void;
14
+ export declare const t: Translate;
15
+ export declare const intlLocale: () => string;
16
+ export declare const formatNumber: (value: number) => string;
17
+ export declare const formatDate: (value: string) => string;
18
+ export {};
package/dist/config.js ADDED
@@ -0,0 +1,14 @@
1
+ const fill = (key, replacements = {}) => key.replace(/:([A-Za-z_]\w*)/g, (match, name) => (name in replacements ? String(replacements[name]) : match));
2
+ let config = {
3
+ t: fill,
4
+ locale: () => 'en-US',
5
+ formatNumber: (value) => new Intl.NumberFormat(config.locale()).format(value),
6
+ formatDate: (value) => new Date(value).toLocaleDateString(config.locale()),
7
+ };
8
+ export function configurePanelKit(options) {
9
+ config = { ...config, ...options };
10
+ }
11
+ export const t = (key, replacements) => config.t(key, replacements);
12
+ export const intlLocale = () => config.locale();
13
+ export const formatNumber = (value) => config.formatNumber(value);
14
+ export const formatDate = (value) => config.formatDate(value);
@@ -0,0 +1,7 @@
1
+ import type { ReactNode } from 'react';
2
+ /** Boş durum: ikon, başlık, açıklama ve isteğe bağlı eylem. */
3
+ export declare function EmptyState({ title, description, action }: {
4
+ title: string;
5
+ description?: ReactNode;
6
+ action?: ReactNode;
7
+ }): import("react").JSX.Element;
@@ -0,0 +1,5 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /** Boş durum: ikon, başlık, açıklama ve isteğe bağlı eylem. */
3
+ export function EmptyState({ title, description, action }) {
4
+ return (_jsxs("div", { className: "flex flex-col items-center gap-2 px-4 py-10 text-center", children: [_jsx("p", { className: "text-sm font-semibold", children: title }), description && _jsx("p", { className: "max-w-md text-xs text-muted-foreground", children: description }), action && _jsx("div", { className: "mt-3", children: action })] }));
5
+ }
@@ -0,0 +1 @@
1
+ export declare function useIsMobile(): boolean;
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ const MOBILE_BREAKPOINT = 768;
3
+ export function useIsMobile() {
4
+ const [isMobile, setIsMobile] = React.useState(undefined);
5
+ React.useEffect(() => {
6
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
7
+ const onChange = () => {
8
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
9
+ };
10
+ mql.addEventListener("change", onChange);
11
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
12
+ return () => mql.removeEventListener("change", onChange);
13
+ }, []);
14
+ return !!isMobile;
15
+ }
@@ -0,0 +1,16 @@
1
+ import { type ReactNode } from 'react';
2
+ /**
3
+ * Bölüm kartı: başlık, açıklama, sağda seçenekler.
4
+ * `flush` gövdeyi kenar boşluksuz bırakır (liste, ızgara, tablo için).
5
+ */
6
+ export declare function SectionCard({ title, description, actions, flush, highlighted, className, contentClassName, children, }: {
7
+ title?: ReactNode;
8
+ description?: ReactNode;
9
+ actions?: ReactNode;
10
+ flush?: boolean;
11
+ /** Öne çıkan kart (önerilen plan): marka halkası. */
12
+ highlighted?: boolean;
13
+ className?: string;
14
+ contentClassName?: string;
15
+ children: ReactNode;
16
+ }): import("react").JSX.Element;
@@ -0,0 +1,13 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Children } from 'react';
3
+ import { cn } from './utils.js';
4
+ /**
5
+ * Bölüm kartı: başlık, açıklama, sağda seçenekler.
6
+ * `flush` gövdeyi kenar boşluksuz bırakır (liste, ızgara, tablo için).
7
+ */
8
+ export function SectionCard({ title, description, actions, flush = false, highlighted = false, className, contentClassName, children, }) {
9
+ return (_jsxs("section", { className: cn('flex flex-col overflow-hidden rounded-3xl bg-card text-card-foreground shadow-sm ring-1 ring-foreground/5 dark:ring-foreground/10', highlighted && 'ring-2 ring-primary/40 dark:ring-primary/40', className), children: [(title || actions) && (_jsxs("header", { className: cn('flex items-start gap-3 px-4 py-3 sm:px-6 sm:py-4', hasContent(children) && 'border-b'), children: [_jsxs("div", { className: "min-w-0 flex-1", children: [title && _jsx("h2", { className: "text-sm font-semibold sm:text-base", children: title }), description && _jsx("p", { className: "mt-0.5 text-xs text-muted-foreground sm:text-sm", children: description })] }), actions && _jsx("div", { className: "flex shrink-0 items-center gap-2", children: actions })] })), hasContent(children) && _jsx("div", { className: cn('flex-1', !flush && 'p-4 sm:p-6', contentClassName), children: children })] }));
10
+ }
11
+ function hasContent(children) {
12
+ return Children.toArray(children).length > 0;
13
+ }
@@ -0,0 +1,15 @@
1
+ import { type LucideIcon } from 'lucide-react';
2
+ import type { ReactNode } from 'react';
3
+ /** İstatistik kartları (controller'lar aynı diziyi gönderir). */
4
+ export type StatCard = {
5
+ label: string;
6
+ value: ReactNode;
7
+ hint?: ReactNode;
8
+ color?: 'indigo' | 'green' | 'amber' | 'purple' | 'red' | 'blue' | 'gray';
9
+ /** Kayıtlı ad (bag, check…) ya da doğrudan bir Lucide ikonu. */
10
+ icon?: 'bag' | 'check' | 'clock' | 'calendar' | 'x' | 'users' | LucideIcon;
11
+ };
12
+ /** Liste ekranlarının üstündeki özet kartları. */
13
+ export declare function StatCards({ items }: {
14
+ items: StatCard[];
15
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,32 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { CalendarIcon, CircleCheckIcon, CircleXIcon, ClockIcon, ShoppingBagIcon, UsersIcon } from 'lucide-react';
3
+ import { cn } from './utils.js';
4
+ const tones = {
5
+ indigo: 'bg-indigo-500/10 text-indigo-600 dark:text-indigo-400',
6
+ green: 'bg-emerald-500/10 text-emerald-600 dark:text-emerald-400',
7
+ amber: 'bg-amber-500/10 text-amber-600 dark:text-amber-400',
8
+ purple: 'bg-purple-500/10 text-purple-600 dark:text-purple-400',
9
+ red: 'bg-red-500/10 text-red-600 dark:text-red-400',
10
+ blue: 'bg-sky-500/10 text-sky-600 dark:text-sky-400',
11
+ gray: 'bg-muted text-muted-foreground',
12
+ };
13
+ const icons = {
14
+ bag: ShoppingBagIcon,
15
+ check: CircleCheckIcon,
16
+ clock: ClockIcon,
17
+ calendar: CalendarIcon,
18
+ x: CircleXIcon,
19
+ users: UsersIcon,
20
+ };
21
+ // Sınıf adı birleştirilerek üretilmez — Tailwind taraması tam adı görmeli.
22
+ const grid = { 1: 'xl:grid-cols-1', 2: 'xl:grid-cols-2', 3: 'xl:grid-cols-3', 4: 'xl:grid-cols-4', 5: 'xl:grid-cols-5', 6: 'xl:grid-cols-6' };
23
+ /** Liste ekranlarının üstündeki özet kartları. */
24
+ export function StatCards({ items }) {
25
+ if (items.length === 0) {
26
+ return null;
27
+ }
28
+ return (_jsx("div", { className: cn('grid grid-cols-1 gap-4 sm:grid-cols-2', grid[Math.min(items.length, 6)] ?? 'xl:grid-cols-5'), children: items.map((card) => {
29
+ const Icon = card.icon === undefined || typeof card.icon === 'string' ? icons[card.icon ?? 'bag'] : card.icon;
30
+ return (_jsxs("div", { className: "flex items-center gap-4 rounded-3xl bg-card p-4 shadow-sm ring-1 ring-foreground/5 dark:ring-foreground/10", children: [_jsx("span", { className: cn('flex size-11 shrink-0 items-center justify-center rounded-full', tones[card.color ?? 'gray']), children: _jsx(Icon, { className: "size-5" }) }), _jsxs("div", { className: "min-w-0", children: [_jsx("p", { className: "truncate text-xs text-muted-foreground", children: card.label }), _jsx("p", { className: "text-2xl font-semibold tabular-nums", children: card.value }), card.hint && _jsx("p", { className: "mt-0.5 truncate text-xs text-muted-foreground", children: card.hint })] })] }, card.label));
31
+ }) }));
32
+ }
@@ -0,0 +1,29 @@
1
+ import type { ReactNode } from 'react';
2
+ declare const tones: {
3
+ readonly success: 'bg-emerald-500/10 text-emerald-700 ring-emerald-600/20 dark:text-emerald-400';
4
+ readonly danger: 'bg-red-500/10 text-red-700 ring-red-600/20 dark:text-red-400';
5
+ readonly warning: 'bg-amber-500/10 text-amber-700 ring-amber-600/20 dark:text-amber-400';
6
+ readonly info: 'bg-sky-500/10 text-sky-700 ring-sky-600/20 dark:text-sky-400';
7
+ readonly purple: 'bg-purple-500/10 text-purple-700 ring-purple-600/20 dark:text-purple-400';
8
+ readonly neutral: 'bg-muted text-muted-foreground ring-foreground/10';
9
+ readonly primary: 'bg-primary/10 text-brand-link ring-primary/20 dark:text-primary';
10
+ readonly accent: 'bg-primary text-primary-foreground ring-transparent';
11
+ readonly overlay: 'bg-black/60 text-white ring-transparent';
12
+ };
13
+ declare const sizes: {
14
+ readonly sm: 'h-5 px-2 text-2xs';
15
+ readonly default: 'h-6 px-2.5 text-xs';
16
+ };
17
+ export type StatusTone = keyof typeof tones;
18
+ /**
19
+ * Ürünün tek rozeti — panelde ve tanıtım sitesinde aynı renk dili (yeşil iyi, kırmızı sorun, marka yeni…).
20
+ * `sm` sayaç ve tablo içi etiketler içindir; renk ve boyut dışarıdan verilmez.
21
+ */
22
+ export declare function StatusBadge({ tone, size, children, className, title }: {
23
+ tone?: StatusTone;
24
+ size?: keyof typeof sizes;
25
+ children: ReactNode;
26
+ className?: string;
27
+ title?: string;
28
+ }): import("react").JSX.Element;
29
+ export {};
@@ -0,0 +1,27 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from './utils.js';
3
+ const tones = {
4
+ success: 'bg-emerald-500/10 text-emerald-700 ring-emerald-600/20 dark:text-emerald-400',
5
+ danger: 'bg-red-500/10 text-red-700 ring-red-600/20 dark:text-red-400',
6
+ warning: 'bg-amber-500/10 text-amber-700 ring-amber-600/20 dark:text-amber-400',
7
+ info: 'bg-sky-500/10 text-sky-700 ring-sky-600/20 dark:text-sky-400',
8
+ purple: 'bg-purple-500/10 text-purple-700 ring-purple-600/20 dark:text-purple-400',
9
+ neutral: 'bg-muted text-muted-foreground ring-foreground/10',
10
+ // Marka vurgusu: "Yeni", "Önerilen", seçili sayısı.
11
+ primary: 'bg-primary/10 text-brand-link ring-primary/20 dark:text-primary',
12
+ // Dolu sayaç (okunmamış, menü rozeti).
13
+ accent: 'bg-primary text-primary-foreground ring-transparent',
14
+ // Görselin üstündeki etiket (süre, sıra).
15
+ overlay: 'bg-black/60 text-white ring-transparent',
16
+ };
17
+ const sizes = {
18
+ sm: 'h-5 px-2 text-2xs',
19
+ default: 'h-6 px-2.5 text-xs',
20
+ };
21
+ /**
22
+ * Ürünün tek rozeti — panelde ve tanıtım sitesinde aynı renk dili (yeşil iyi, kırmızı sorun, marka yeni…).
23
+ * `sm` sayaç ve tablo içi etiketler içindir; renk ve boyut dışarıdan verilmez.
24
+ */
25
+ export function StatusBadge({ tone = 'neutral', size = 'default', children, className, title }) {
26
+ return (_jsx("span", { title: title, className: cn('inline-flex shrink-0 items-center gap-1 rounded-full font-medium whitespace-nowrap tabular-nums ring-1 ring-inset [&_svg]:size-3 [&_svg]:shrink-0', sizes[size], tones[tone], className), children: children }));
27
+ }
@@ -0,0 +1,18 @@
1
+ /** Para birimi başına tutarlar (controller `money()` ile biçimlenmiş metin gönderir). */
2
+ export type CurrencyAmounts = Array<{
3
+ currency: string;
4
+ label: string;
5
+ }>;
6
+ /**
7
+ * Liste üstü özet şeridi: her kutuda etiket, bir ya da
8
+ * daha çok değer (ilk değer büyük, diğer para birimleri küçük) ve isteğe bağlı not.
9
+ */
10
+ export type SummaryItem = {
11
+ label: string;
12
+ values: string[];
13
+ hint?: string | null;
14
+ tone?: 'default' | 'danger' | 'success' | 'warning' | 'muted';
15
+ };
16
+ export declare function SummaryStrip({ items }: {
17
+ items: SummaryItem[];
18
+ }): import("react").JSX.Element | null;
@@ -0,0 +1,15 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from './utils.js';
3
+ const summaryTones = {
4
+ default: 'text-foreground',
5
+ danger: 'text-red-600 dark:text-red-400',
6
+ success: 'text-emerald-600 dark:text-emerald-400',
7
+ warning: 'text-amber-600 dark:text-amber-400',
8
+ muted: 'text-muted-foreground',
9
+ };
10
+ const summaryGrid = { 1: 'lg:grid-cols-1', 2: 'lg:grid-cols-2', 3: 'lg:grid-cols-3', 4: 'lg:grid-cols-4', 5: 'lg:grid-cols-5', 6: 'lg:grid-cols-6' };
11
+ export function SummaryStrip({ items }) {
12
+ if (items.length === 0)
13
+ return null;
14
+ return (_jsx("div", { className: cn('grid grid-cols-2 gap-4', summaryGrid[Math.min(items.length, 6)]), children: items.map((item) => (_jsxs("div", { className: "flex min-w-0 flex-col gap-1 rounded-3xl bg-card p-4 shadow-sm ring-1 ring-foreground/5 sm:p-5 dark:ring-foreground/10", children: [_jsx("p", { className: "truncate text-xs text-muted-foreground", children: item.label }), item.values.length === 0 ? (_jsx("p", { className: "text-2xl font-semibold text-muted-foreground/50", children: "\u2014" })) : (item.values.map((value, index) => (_jsx("p", { className: cn('font-semibold tabular-nums', index === 0 ? 'text-2xl' : 'text-sm', summaryTones[item.tone ?? 'default']), children: value }, index)))), item.hint && _jsx("p", { className: "text-2xs text-muted-foreground", children: item.hint })] }, item.label))) }));
15
+ }
package/dist/text.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ /** Arama ve karşılaştırma için küçük harf, arayüz dilinin kuralıyla (Türkçede "I" → "ı", "İ" → "i"). */
2
+ export declare const lowerText: (text: string) => string;
3
+ /** Görünen metnin büyük harfi (baş harf, kısaltma), arayüz dilinin kuralıyla. */
4
+ export declare const upperText: (text: string) => string;
5
+ /** Ülke, dil, para ve kupon kodu gibi Latin harfli kodlar: dilden bağımsız ("id" Türkçede "İD" olmasın). */
6
+ export declare const upperCode: (code: string) => string;
7
+ export declare const lowerCode: (code: string) => string;
package/dist/text.js ADDED
@@ -0,0 +1,8 @@
1
+ import { intlLocale } from './config.js';
2
+ /** Arama ve karşılaştırma için küçük harf, arayüz dilinin kuralıyla (Türkçede "I" → "ı", "İ" → "i"). */
3
+ export const lowerText = (text) => text.toLocaleLowerCase(intlLocale());
4
+ /** Görünen metnin büyük harfi (baş harf, kısaltma), arayüz dilinin kuralıyla. */
5
+ export const upperText = (text) => text.toLocaleUpperCase(intlLocale());
6
+ /** Ülke, dil, para ve kupon kodu gibi Latin harfli kodlar: dilden bağımsız ("id" Türkçede "İD" olmasın). */
7
+ export const upperCode = (code) => code.toLocaleUpperCase('en-US');
8
+ export const lowerCode = (code) => code.toLocaleLowerCase('en-US');
@@ -0,0 +1,22 @@
1
+ import * as React from "react";
2
+ import { Heading, Modal as ModalPrimitive, type DialogTriggerProps as AlertDialogTriggerPrimitiveProps, type ModalOverlayProps as ModalOverlayPrimitiveProps } from "react-aria-components";
3
+ import { Button } from "./button.js";
4
+ declare function AlertDialogTrigger({ ...props }: AlertDialogTriggerPrimitiveProps): React.JSX.Element;
5
+ declare function AlertDialogOverlay({ className, children, ...props }: Omit<ModalOverlayPrimitiveProps, "className" | "children"> & {
6
+ className?: string;
7
+ children: React.ReactNode;
8
+ }): React.JSX.Element;
9
+ declare function AlertDialog({ className, size, children, ...props }: Omit<ModalOverlayPrimitiveProps, "className" | "children"> & Pick<React.ComponentProps<typeof ModalPrimitive>, "isDismissable"> & {
10
+ className?: string;
11
+ size?: "default" | "sm";
12
+ children: React.ReactNode;
13
+ }): React.JSX.Element;
14
+ declare function AlertDialogContent({ className, size, children, ...props }: React.ComponentProps<typeof AlertDialog>): React.JSX.Element;
15
+ declare function AlertDialogHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
16
+ declare function AlertDialogFooter({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
17
+ declare function AlertDialogMedia({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
18
+ declare function AlertDialogTitle({ className, ...props }: Omit<React.ComponentProps<typeof Heading>, "slot">): React.JSX.Element;
19
+ declare function AlertDialogDescription({ className, ...props }: Omit<React.ComponentProps<"div">, "slot">): React.JSX.Element;
20
+ declare function AlertDialogAction({ className, ...props }: React.ComponentProps<typeof Button>): React.JSX.Element;
21
+ declare function AlertDialogCancel({ className, variant, size, ...props }: React.ComponentProps<typeof Button>): React.JSX.Element;
22
+ export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, };
@@ -0,0 +1,38 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "../utils.js";
3
+ import { Dialog as AlertDialogPrimitive, DialogTrigger as AlertDialogTriggerPrimitive, Heading, ModalOverlay as ModalOverlayPrimitive, Modal as ModalPrimitive, } from "react-aria-components";
4
+ import { Button } from "./button.js";
5
+ function AlertDialogTrigger({ ...props }) {
6
+ return (_jsx(AlertDialogTriggerPrimitive, { "data-slot": "alert-dialog-trigger", ...props }));
7
+ }
8
+ function AlertDialogOverlay({ className, children, ...props }) {
9
+ return (_jsx(ModalOverlayPrimitive, { "data-slot": "alert-dialog-overlay", className: cn("fixed inset-0 isolate z-50 bg-black/30 duration-100 data-entering:animate-in data-entering:fade-in-0 data-exiting:animate-out data-exiting:fade-out-0 supports-backdrop-filter:backdrop-blur-sm", className), ...props, children: children }));
10
+ }
11
+ function AlertDialog({ className, size = "default", children, ...props }) {
12
+ return (_jsx(AlertDialogOverlay, { ...props, children: _jsx(ModalPrimitive, { "data-slot": "alert-dialog-content", "data-size": size, className: cn("group/alert-dialog-content fixed top-1/2 left-1/2 z-50 grid w-full -translate-x-1/2 -translate-y-1/2 gap-6 rounded-4xl bg-popover p-6 text-popover-foreground shadow-xl ring-1 ring-foreground/5 duration-100 outline-none data-entering:animate-in data-entering:fade-in-0 data-entering:zoom-in-95 data-exiting:animate-out data-exiting:fade-out-0 data-exiting:zoom-out-95 data-[size=default]:max-w-xs data-[size=sm]:max-w-xs data-[size=default]:sm:max-w-md dark:ring-foreground/10", className), children: _jsx(AlertDialogPrimitive, { "data-slot": "alert-dialog", role: "alertdialog", className: "[display:inherit] [gap:inherit] outline-none", children: children }) }) }));
13
+ }
14
+ function AlertDialogContent({ className, size = "default", children, ...props }) {
15
+ return (_jsx(AlertDialog, { className: className, size: size, ...props, children: children }));
16
+ }
17
+ function AlertDialogHeader({ className, ...props }) {
18
+ return (_jsx("div", { "data-slot": "alert-dialog-header", className: cn("grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className), ...props }));
19
+ }
20
+ function AlertDialogFooter({ className, ...props }) {
21
+ return (_jsx("div", { "data-slot": "alert-dialog-footer", className: cn("flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end", className), ...props }));
22
+ }
23
+ function AlertDialogMedia({ className, ...props }) {
24
+ return (_jsx("div", { "data-slot": "alert-dialog-media", className: cn("mb-2 inline-flex size-16 items-center justify-center rounded-full bg-muted sm:group-data-[size=default]/alert-dialog-content:row-span-2 *:[svg:not([class*='size-'])]:size-8", className), ...props }));
25
+ }
26
+ function AlertDialogTitle({ className, ...props }) {
27
+ return (_jsx(Heading, { slot: "title", "data-slot": "alert-dialog-title", className: cn("font-heading text-lg font-medium sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className), ...props }));
28
+ }
29
+ function AlertDialogDescription({ className, ...props }) {
30
+ return (_jsx("div", { "data-slot": "alert-dialog-description", className: cn("text-sm text-balance text-muted-foreground md:text-pretty *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground", className), ...props }));
31
+ }
32
+ function AlertDialogAction({ className, ...props }) {
33
+ return (_jsx(Button, { slot: "close", "data-slot": "alert-dialog-action", className: cn(className), ...props }));
34
+ }
35
+ function AlertDialogCancel({ className, variant = "outline", size = "default", ...props }) {
36
+ return (_jsx(Button, { slot: "close", "data-slot": "alert-dialog-cancel", className: cn(className), variant: variant, size: size, ...props }));
37
+ }
38
+ export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogTitle, AlertDialogTrigger, };
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ declare function Avatar({ className, size, ...props }: React.ComponentProps<"div"> & {
3
+ size?: "default" | "sm" | "lg";
4
+ }): React.JSX.Element;
5
+ declare function AvatarImage({ className, ...props }: React.ComponentProps<"img">): React.JSX.Element;
6
+ declare function AvatarFallback({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
7
+ declare function AvatarBadge({ className, ...props }: React.ComponentProps<"span">): React.JSX.Element;
8
+ declare function AvatarGroup({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
9
+ declare function AvatarGroupCount({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
10
+ export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarBadge, };
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import * as React from "react";
3
+ import { cn } from "../utils.js";
4
+ function Avatar({ className, size = "default", ...props }) {
5
+ return (_jsx("div", { "data-slot": "avatar", "data-size": size, className: cn("group/avatar relative flex size-8 shrink-0 rounded-full select-none after:absolute after:inset-0 after:rounded-full after:border after:border-border after:mix-blend-darken data-[size=lg]:size-10 data-[size=sm]:size-6 dark:after:mix-blend-lighten", className), ...props }));
6
+ }
7
+ function AvatarImage({ className, ...props }) {
8
+ const [state, setState] = React.useState(props.src ? "loading" : "error");
9
+ return (_jsx("img", { "data-slot": "avatar-image", alt: props.alt || "", "data-state": state, onLoad: () => setState("loaded"), onError: () => setState("error"), className: cn("peer aspect-square size-full rounded-full object-cover data-[state=error]:hidden", className), ...props }));
10
+ }
11
+ function AvatarFallback({ className, ...props }) {
12
+ return (_jsx("div", { "data-slot": "avatar-fallback", className: cn("flex size-full items-center justify-center rounded-full bg-muted text-sm text-muted-foreground group-data-[size=sm]/avatar:text-xs peer-data-[state=error]:flex peer-[*]:hidden", className), ...props }));
13
+ }
14
+ function AvatarBadge({ className, ...props }) {
15
+ return (_jsx("span", { "data-slot": "avatar-badge", className: cn("absolute right-0 bottom-0 z-10 inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground bg-blend-color ring-2 ring-background select-none", "group-data-[size=sm]/avatar:size-2 group-data-[size=sm]/avatar:[&>svg]:hidden", "group-data-[size=default]/avatar:size-2.5 group-data-[size=default]/avatar:[&>svg]:size-2", "group-data-[size=lg]/avatar:size-3 group-data-[size=lg]/avatar:[&>svg]:size-2", className), ...props }));
16
+ }
17
+ function AvatarGroup({ className, ...props }) {
18
+ return (_jsx("div", { "data-slot": "avatar-group", className: cn("group/avatar-group flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:ring-background", className), ...props }));
19
+ }
20
+ function AvatarGroupCount({ className, ...props }) {
21
+ return (_jsx("div", { "data-slot": "avatar-group-count", className: cn("relative flex size-8 shrink-0 items-center justify-center rounded-full bg-muted text-sm text-muted-foreground ring-2 ring-background group-has-data-[size=lg]/avatar-group:size-10 group-has-data-[size=sm]/avatar-group:size-6 [&>svg]:size-4 group-has-data-[size=lg]/avatar-group:[&>svg]:size-5 group-has-data-[size=sm]/avatar-group:[&>svg]:size-3", className), ...props }));
22
+ }
23
+ export { Avatar, AvatarImage, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarBadge, };
@@ -0,0 +1,8 @@
1
+ import { type VariantProps } from "class-variance-authority";
2
+ declare const badgeVariants: (props?: ({
3
+ variant?: "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | null | undefined;
4
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
5
+ declare function Badge({ className, variant, render, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
6
+ render?: (props: React.HTMLAttributes<HTMLElement>) => React.ReactNode;
7
+ }): string | number | bigint | boolean | import("react").JSX.Element | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | Iterable<import("react").ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
8
+ export { Badge, badgeVariants };
@@ -0,0 +1,31 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cva } from "class-variance-authority";
3
+ import { cn } from "../utils.js";
4
+ const badgeVariants = cva("group/badge inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden rounded-3xl border border-transparent px-2 py-0.5 text-xs font-medium whitespace-nowrap transition-[color,background-color,border-color,box-shadow,opacity,transform,translate] focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-invalid:border-destructive aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 [&>svg]:pointer-events-none [&>svg]:size-3!", {
5
+ variants: {
6
+ variant: {
7
+ default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80",
8
+ secondary: "bg-secondary text-secondary-foreground [a]:hover:bg-secondary/80",
9
+ destructive: "bg-destructive/10 text-destructive focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:focus-visible:ring-destructive/40 [a]:hover:bg-destructive/20",
10
+ outline: "border-border text-foreground [a]:hover:bg-muted [a]:hover:text-muted-foreground",
11
+ ghost: "hover:bg-muted hover:text-muted-foreground dark:hover:bg-muted/50",
12
+ link: "text-primary underline-offset-4 hover:underline",
13
+ },
14
+ },
15
+ defaultVariants: {
16
+ variant: "default",
17
+ },
18
+ });
19
+ function Badge({ className, variant = "default", render, ...props }) {
20
+ if (render) {
21
+ const renderProps = {
22
+ "data-slot": "badge",
23
+ "data-variant": variant,
24
+ className: cn(badgeVariants({ variant }), className),
25
+ ...props,
26
+ };
27
+ return render(renderProps);
28
+ }
29
+ return (_jsx("span", { "data-slot": "badge", "data-variant": variant, className: cn(badgeVariants({ variant }), className), ...props }));
30
+ }
31
+ export { Badge, badgeVariants };