tamga-ui 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 (207) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/dist/blocks/count-row.d.ts +29 -0
  4. package/dist/blocks/count-row.d.ts.map +1 -0
  5. package/dist/blocks/count-row.js +19 -0
  6. package/dist/blocks/filter-bar.d.ts +123 -0
  7. package/dist/blocks/filter-bar.d.ts.map +1 -0
  8. package/dist/blocks/filter-bar.js +74 -0
  9. package/dist/blocks/index.d.ts +24 -0
  10. package/dist/blocks/index.d.ts.map +1 -0
  11. package/dist/blocks/index.js +23 -0
  12. package/dist/blocks/save-bar.d.ts +31 -0
  13. package/dist/blocks/save-bar.d.ts.map +1 -0
  14. package/dist/blocks/save-bar.js +21 -0
  15. package/dist/components/a11y.d.ts +21 -0
  16. package/dist/components/a11y.d.ts.map +1 -0
  17. package/dist/components/a11y.js +159 -0
  18. package/dist/components/advanced-input.d.ts +115 -0
  19. package/dist/components/advanced-input.d.ts.map +1 -0
  20. package/dist/components/advanced-input.js +189 -0
  21. package/dist/components/avatar.d.ts +63 -0
  22. package/dist/components/avatar.d.ts.map +1 -0
  23. package/dist/components/avatar.js +54 -0
  24. package/dist/components/badge.d.ts +37 -0
  25. package/dist/components/badge.d.ts.map +1 -0
  26. package/dist/components/badge.js +29 -0
  27. package/dist/components/bar.d.ts +32 -0
  28. package/dist/components/bar.d.ts.map +1 -0
  29. package/dist/components/bar.js +33 -0
  30. package/dist/components/button.d.ts +45 -0
  31. package/dist/components/button.d.ts.map +1 -0
  32. package/dist/components/button.js +56 -0
  33. package/dist/components/chart.d.ts +43 -0
  34. package/dist/components/chart.d.ts.map +1 -0
  35. package/dist/components/chart.js +41 -0
  36. package/dist/components/checkbox.d.ts +13 -0
  37. package/dist/components/checkbox.d.ts.map +1 -0
  38. package/dist/components/checkbox.js +16 -0
  39. package/dist/components/chrome.d.ts +87 -0
  40. package/dist/components/chrome.d.ts.map +1 -0
  41. package/dist/components/chrome.js +107 -0
  42. package/dist/components/combobox.d.ts +31 -0
  43. package/dist/components/combobox.d.ts.map +1 -0
  44. package/dist/components/combobox.js +62 -0
  45. package/dist/components/control-base.d.ts +7 -0
  46. package/dist/components/control-base.d.ts.map +1 -0
  47. package/dist/components/control-base.js +6 -0
  48. package/dist/components/data-table.d.ts +68 -0
  49. package/dist/components/data-table.d.ts.map +1 -0
  50. package/dist/components/data-table.js +50 -0
  51. package/dist/components/date-picker.d.ts +52 -0
  52. package/dist/components/date-picker.d.ts.map +1 -0
  53. package/dist/components/date-picker.js +73 -0
  54. package/dist/components/disclosure.d.ts +31 -0
  55. package/dist/components/disclosure.d.ts.map +1 -0
  56. package/dist/components/disclosure.js +32 -0
  57. package/dist/components/display.d.ts +188 -0
  58. package/dist/components/display.d.ts.map +1 -0
  59. package/dist/components/display.js +190 -0
  60. package/dist/components/empty-state.d.ts +150 -0
  61. package/dist/components/empty-state.d.ts.map +1 -0
  62. package/dist/components/empty-state.js +113 -0
  63. package/dist/components/error-state.d.ts +38 -0
  64. package/dist/components/error-state.d.ts.map +1 -0
  65. package/dist/components/error-state.js +16 -0
  66. package/dist/components/file-upload.d.ts +34 -0
  67. package/dist/components/file-upload.d.ts.map +1 -0
  68. package/dist/components/file-upload.js +34 -0
  69. package/dist/components/gauge.d.ts +47 -0
  70. package/dist/components/gauge.d.ts.map +1 -0
  71. package/dist/components/gauge.js +65 -0
  72. package/dist/components/icon.d.ts +32 -0
  73. package/dist/components/icon.d.ts.map +1 -0
  74. package/dist/components/icon.js +20 -0
  75. package/dist/components/icons.d.ts +19 -0
  76. package/dist/components/icons.d.ts.map +1 -0
  77. package/dist/components/icons.js +39 -0
  78. package/dist/components/input.d.ts +35 -0
  79. package/dist/components/input.d.ts.map +1 -0
  80. package/dist/components/input.js +41 -0
  81. package/dist/components/layout.d.ts +133 -0
  82. package/dist/components/layout.d.ts.map +1 -0
  83. package/dist/components/layout.js +132 -0
  84. package/dist/components/link.d.ts +22 -0
  85. package/dist/components/link.d.ts.map +1 -0
  86. package/dist/components/link.js +2 -0
  87. package/dist/components/live-scope.d.ts +15 -0
  88. package/dist/components/live-scope.d.ts.map +1 -0
  89. package/dist/components/live-scope.js +67 -0
  90. package/dist/components/log-view.d.ts +34 -0
  91. package/dist/components/log-view.d.ts.map +1 -0
  92. package/dist/components/log-view.js +30 -0
  93. package/dist/components/number-input.d.ts +26 -0
  94. package/dist/components/number-input.d.ts.map +1 -0
  95. package/dist/components/number-input.js +57 -0
  96. package/dist/components/overlay.d.ts +257 -0
  97. package/dist/components/overlay.d.ts.map +1 -0
  98. package/dist/components/overlay.js +276 -0
  99. package/dist/components/pagination.d.ts +38 -0
  100. package/dist/components/pagination.d.ts.map +1 -0
  101. package/dist/components/pagination.js +46 -0
  102. package/dist/components/pie.d.ts +40 -0
  103. package/dist/components/pie.d.ts.map +1 -0
  104. package/dist/components/pie.js +74 -0
  105. package/dist/components/primitives.d.ts +96 -0
  106. package/dist/components/primitives.d.ts.map +1 -0
  107. package/dist/components/primitives.js +81 -0
  108. package/dist/components/progress.d.ts +29 -0
  109. package/dist/components/progress.d.ts.map +1 -0
  110. package/dist/components/progress.js +16 -0
  111. package/dist/components/radio-group.d.ts +17 -0
  112. package/dist/components/radio-group.d.ts.map +1 -0
  113. package/dist/components/radio-group.js +23 -0
  114. package/dist/components/rail-link.d.ts +24 -0
  115. package/dist/components/rail-link.d.ts.map +1 -0
  116. package/dist/components/rail-link.js +24 -0
  117. package/dist/components/rich-text.d.ts +51 -0
  118. package/dist/components/rich-text.d.ts.map +1 -0
  119. package/dist/components/rich-text.js +147 -0
  120. package/dist/components/section.d.ts +15 -0
  121. package/dist/components/section.d.ts.map +1 -0
  122. package/dist/components/section.js +8 -0
  123. package/dist/components/segmented.d.ts +13 -0
  124. package/dist/components/segmented.d.ts.map +1 -0
  125. package/dist/components/segmented.js +12 -0
  126. package/dist/components/skeleton.d.ts +69 -0
  127. package/dist/components/skeleton.d.ts.map +1 -0
  128. package/dist/components/skeleton.js +67 -0
  129. package/dist/components/slider.d.ts +18 -0
  130. package/dist/components/slider.d.ts.map +1 -0
  131. package/dist/components/slider.js +15 -0
  132. package/dist/components/sparkline.d.ts +17 -0
  133. package/dist/components/sparkline.d.ts.map +1 -0
  134. package/dist/components/sparkline.js +19 -0
  135. package/dist/components/spinner.d.ts +15 -0
  136. package/dist/components/spinner.d.ts.map +1 -0
  137. package/dist/components/spinner.js +22 -0
  138. package/dist/components/stacked-bar.d.ts +21 -0
  139. package/dist/components/stacked-bar.d.ts.map +1 -0
  140. package/dist/components/stacked-bar.js +41 -0
  141. package/dist/components/surface.d.ts +76 -0
  142. package/dist/components/surface.d.ts.map +1 -0
  143. package/dist/components/surface.js +49 -0
  144. package/dist/components/switch.d.ts +12 -0
  145. package/dist/components/switch.d.ts.map +1 -0
  146. package/dist/components/switch.js +13 -0
  147. package/dist/components/tabs.d.ts +47 -0
  148. package/dist/components/tabs.d.ts.map +1 -0
  149. package/dist/components/tabs.js +12 -0
  150. package/dist/components/timeline-strip.d.ts +19 -0
  151. package/dist/components/timeline-strip.d.ts.map +1 -0
  152. package/dist/components/timeline-strip.js +14 -0
  153. package/dist/components/tone.d.ts +58 -0
  154. package/dist/components/tone.d.ts.map +1 -0
  155. package/dist/components/tone.js +70 -0
  156. package/dist/components/tree-select.d.ts +26 -0
  157. package/dist/components/tree-select.d.ts.map +1 -0
  158. package/dist/components/tree-select.js +59 -0
  159. package/dist/index.d.ts +54 -0
  160. package/dist/index.d.ts.map +1 -0
  161. package/dist/index.js +70 -0
  162. package/dist/kit.css +2248 -0
  163. package/dist/lib/cn.d.ts +10 -0
  164. package/dist/lib/cn.d.ts.map +1 -0
  165. package/dist/lib/cn.js +12 -0
  166. package/dist/lib/color.d.ts +68 -0
  167. package/dist/lib/color.d.ts.map +1 -0
  168. package/dist/lib/color.js +134 -0
  169. package/dist/lib/palette.d.ts +84 -0
  170. package/dist/lib/palette.d.ts.map +1 -0
  171. package/dist/lib/palette.js +193 -0
  172. package/dist/lib/scroll-lock.d.ts +19 -0
  173. package/dist/lib/scroll-lock.d.ts.map +1 -0
  174. package/dist/lib/scroll-lock.js +33 -0
  175. package/dist/patterns/app-shell.d.ts +36 -0
  176. package/dist/patterns/app-shell.d.ts.map +1 -0
  177. package/dist/patterns/app-shell.js +14 -0
  178. package/dist/patterns/auth-template.d.ts +36 -0
  179. package/dist/patterns/auth-template.d.ts.map +1 -0
  180. package/dist/patterns/auth-template.js +40 -0
  181. package/dist/patterns/detail-template.d.ts +52 -0
  182. package/dist/patterns/detail-template.d.ts.map +1 -0
  183. package/dist/patterns/detail-template.js +11 -0
  184. package/dist/patterns/index.d.ts +18 -0
  185. package/dist/patterns/index.d.ts.map +1 -0
  186. package/dist/patterns/index.js +17 -0
  187. package/dist/patterns/list-template.d.ts +32 -0
  188. package/dist/patterns/list-template.d.ts.map +1 -0
  189. package/dist/patterns/list-template.js +8 -0
  190. package/dist/patterns/overview-template.d.ts +26 -0
  191. package/dist/patterns/overview-template.d.ts.map +1 -0
  192. package/dist/patterns/overview-template.js +8 -0
  193. package/dist/patterns/public-template.d.ts +28 -0
  194. package/dist/patterns/public-template.d.ts.map +1 -0
  195. package/dist/patterns/public-template.js +7 -0
  196. package/dist/patterns/settings-template.d.ts +50 -0
  197. package/dist/patterns/settings-template.d.ts.map +1 -0
  198. package/dist/patterns/settings-template.js +33 -0
  199. package/dist/patterns/shared.d.ts +40 -0
  200. package/dist/patterns/shared.d.ts.map +1 -0
  201. package/dist/patterns/shared.js +29 -0
  202. package/dist/patterns/wizard-template.d.ts +28 -0
  203. package/dist/patterns/wizard-template.d.ts.map +1 -0
  204. package/dist/patterns/wizard-template.js +15 -0
  205. package/dist/styles.css +5 -0
  206. package/dist/theme.css +812 -0
  207. package/package.json +87 -0
@@ -0,0 +1,276 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useCallback, useEffect, useRef, useState } from "react";
4
+ import { toneOf } from "./tone.js";
5
+ import { Icon } from "./icon.js";
6
+ import { cn } from "../lib/cn.js";
7
+ import { Close } from "./icons.js";
8
+ import { SkeletonOptions, SkeletonPanel } from "./skeleton.js";
9
+ import { Button } from "./button.js";
10
+ import { useFocusTrap, useListKeys } from "./a11y.js";
11
+ import { MiniButton } from "./button.js";
12
+ import { useScrollLock } from "../lib/scroll-lock.js";
13
+ /* ------------------------------------------------------------------ *
14
+ * The overlay plane. Everything here sits at 6px — past the 4px the
15
+ * page can reach — which is the whole "this is floating" signal.
16
+ * Only Dialog and Sheet add a scrim. Tooltip is the one exception:
17
+ * it is a label, not a surface you act on, so it never lifts.
18
+ * ------------------------------------------------------------------ */
19
+ function useDismiss(open, close) {
20
+ const box = useRef(null);
21
+ useEffect(() => {
22
+ if (!open)
23
+ return;
24
+ const away = (e) => {
25
+ if (box.current && !box.current.contains(e.target))
26
+ close();
27
+ };
28
+ const esc = (e) => e.key === "Escape" && close();
29
+ document.addEventListener("mousedown", away);
30
+ document.addEventListener("keydown", esc);
31
+ return () => {
32
+ document.removeEventListener("mousedown", away);
33
+ document.removeEventListener("keydown", esc);
34
+ };
35
+ }, [open, close]);
36
+ return box;
37
+ }
38
+ export function DropdownMenu({ trigger, items, align = "start", width = 200, loading = false, loadingRows = 4, openOnHover = false, }) {
39
+ const [open, setOpen] = useState(false);
40
+ const box = useDismiss(open, () => setOpen(false));
41
+ const close = useCallback(() => setOpen(false), []);
42
+ const panel = useRef(null);
43
+ useListKeys({ open: open && !loading, containerRef: panel, onClose: close });
44
+ /* KAPANIŞ GECİKMELİ, ANINDA DEĞİL. Tetikleyici ile panel arasında birkaç
45
+ piksellik bir boşluk var ve işaretçi oradan geçerken `pointerleave`
46
+ tetikleniyor: menü tam üstüne gidilirken kapanıyordu. 120ms, o boşluğu
47
+ geçmeye yeten ve "takılı kaldı" hissi vermeyen aralık. */
48
+ const kapatmaSayaci = useRef(null);
49
+ const gecikmeliKapat = useCallback(() => {
50
+ if (!openOnHover)
51
+ return;
52
+ kapatmaSayaci.current = window.setTimeout(() => setOpen(false), 120);
53
+ }, [openOnHover]);
54
+ const kapatmayiIptal = useCallback(() => {
55
+ if (kapatmaSayaci.current !== null) {
56
+ window.clearTimeout(kapatmaSayaci.current);
57
+ kapatmaSayaci.current = null;
58
+ }
59
+ }, []);
60
+ useEffect(() => () => kapatmayiIptal(), [kapatmayiIptal]);
61
+ return (_jsxs("div", { ref: box, className: "relative inline-flex", onPointerEnter: openOnHover
62
+ ? (e) => {
63
+ /* YALNIZ FARE. Dokunmatik bir ekranda `pointerenter` dokunmayla
64
+ birlikte geliyor ve hemen ardından gelen `click` menüyü kapatıyor:
65
+ kullanıcı dokunuyor, menü açılıp anında kapanıyor. */
66
+ if (e.pointerType !== "mouse")
67
+ return;
68
+ kapatmayiIptal();
69
+ setOpen(true);
70
+ }
71
+ : undefined, onPointerLeave: openOnHover ? gecikmeliKapat : undefined, children: [_jsx("span", { onClick: () => setOpen((o) => !o), children: trigger }), open && (_jsxs("div", { ref: panel, role: "menu", className: "tamga-overlay absolute top-[var(--overlay-below)] z-40 overflow-hidden py-1", style: { width, [align === "end" ? "right" : "left"]: 0 }, "aria-busy": loading || undefined, children: [loading && _jsx(SkeletonOptions, { rows: loadingRows }), !loading && items.map((item, i) => {
72
+ if (item.kind === "separator") {
73
+ return _jsx("span", { className: "my-1 block border-t border-line" }, i);
74
+ }
75
+ if (item.kind === "label") {
76
+ return (_jsx("span", { className: "tamga-label block px-4 py-2", children: item.label }, i));
77
+ }
78
+ return (_jsxs("button", { role: item.checked === undefined ? "menuitem" : "menuitemradio", "aria-checked": item.checked, "data-selected": item.checked || undefined, "data-tamga-option": true, className: "tamga-option", disabled: item.disabled, style: {
79
+ color: item.state ? toneOf(item.state).fg : undefined,
80
+ opacity: item.disabled ? 0.45 : undefined,
81
+ cursor: item.disabled ? "not-allowed" : undefined,
82
+ }, onClick: () => {
83
+ item.onSelect?.();
84
+ setOpen(false);
85
+ }, children: [item.icon, item.label] }, i));
86
+ })] }))] }));
87
+ }
88
+ /* --------------------------- popover --------------------------- */
89
+ export function Popover({ trigger, title, children, footer, width = 288, align = "start", loading = false, loadingBlock, closeLabel, }) {
90
+ const [open, setOpen] = useState(false);
91
+ const box = useDismiss(open, () => setOpen(false));
92
+ return (_jsxs("div", { ref: box, className: "relative inline-flex", children: [_jsx("span", { onClick: () => setOpen((o) => !o), children: trigger }), open && (_jsxs("div", { className: "tamga-overlay absolute top-[var(--overlay-below)] z-40", style: { width, [align === "end" ? "right" : "left"]: 0 }, "aria-busy": loading || undefined, children: [title ? (_jsxs("div", { className: "tamga-head tamga-gutter tamga-section", children: [_jsx("h4", { className: "text-control font-semibold", children: title }), _jsx(MiniButton, { className: "ml-auto", "aria-label": closeLabel, onClick: () => setOpen(false), children: _jsx(Icon, { icon: Close, size: "xs" }) })] })) : null, _jsx("div", { className: "tamga-gutter py-4 text-small leading-relaxed", children: loading ? _jsx(SkeletonPanel, { lines: 3, block: loadingBlock }) : children }), footer ? (_jsx("div", { className: "tamga-gutter flex justify-end gap-2 border-t border-line py-3", children: footer })) : null] }))] }));
93
+ }
94
+ /* --------------------------- tooltip --------------------------- */
95
+ const placements = {
96
+ top: "bottom-[var(--overlay-above)] left-1/2 -translate-x-1/2",
97
+ bottom: "top-[var(--overlay-below)] left-1/2 -translate-x-1/2",
98
+ left: "right-[var(--overlay-below)] top-1/2 -translate-y-1/2",
99
+ right: "left-[var(--overlay-below)] top-1/2 -translate-y-1/2",
100
+ };
101
+ /* A hard triangle cut with clip-path — no rotated square, no border to line up.
102
+ Solid ink, square corners, same as the bubble it belongs to.
103
+
104
+ The BOX turns with the arrow. It used to be 12×6 for all four placements, so the sideways ones
105
+ were a 12-long spike where the vertical ones were a 12-wide wedge — the same clip-path in a box
106
+ that had not been rotated with it. Every arrow is now a 12 base and a 6 rise, whichever way it
107
+ points. */
108
+ const arrows = {
109
+ top: {
110
+ left: "50%", top: "100%", marginLeft: -6, width: 12, height: 6,
111
+ clipPath: "polygon(0 0, 100% 0, 50% 100%)",
112
+ },
113
+ bottom: {
114
+ left: "50%", bottom: "100%", marginLeft: -6, width: 12, height: 6,
115
+ clipPath: "polygon(50% 0, 0 100%, 100% 100%)",
116
+ },
117
+ left: {
118
+ top: "50%", left: "100%", marginTop: -6, width: 6, height: 12,
119
+ clipPath: "polygon(0 0, 100% 50%, 0 100%)",
120
+ },
121
+ right: {
122
+ top: "50%", right: "100%", marginTop: -6, width: 6, height: 12,
123
+ clipPath: "polygon(100% 0, 0 50%, 100% 100%)",
124
+ },
125
+ };
126
+ /**
127
+ * KABARCIK `fixed`, `absolute` DEĞİL.
128
+ *
129
+ * Ölçülen hata: dar bir kenar çubuğunda ipucu hiç görünmüyordu. Sebep
130
+ * `overflow`du — menü kaydırılabilir olduğu için (`overflow-y: auto`, ki yatayı
131
+ * da `auto` yapıyor) ipucu doğuyor, çiziliyor ve kabın dışında kaldığı için
132
+ * tamamen kırpılıyordu. Bu, kitin üç kez karşılaştığı aynı tuzağın üçüncü yüzü
133
+ * (kart, ray, şimdi ipucu).
134
+ *
135
+ * Z-index çözmüyor: hiçbir yığın sırası bir `overflow` kırpmasını aşamaz.
136
+ * Çözüm kabarcığı akıştan çıkarmak. `fixed` bir eleman en yakın kaydırma
137
+ * kabına değil GÖRÜNTÜ ALANINA göre yerleşiyor, yani hiçbir kap onu kesemiyor.
138
+ *
139
+ * KONUM HOVER'DA ÖLÇÜLÜYOR, çünkü `fixed` bir elemanın CSS ile tetikleyiciye
140
+ * hizalanmasının yolu yok. Ölçüm yalnız ipucu açılırken yapılıyor: kapalıyken
141
+ * hiçbir maliyeti yok.
142
+ */
143
+ export function Tooltip({ label, placement = "bottom", children, }) {
144
+ const sarmal = useRef(null);
145
+ const [konum, setKonum] = useState(null);
146
+ const olc = useCallback(() => {
147
+ const el = sarmal.current;
148
+ if (!el)
149
+ return;
150
+ const r = el.getBoundingClientRect();
151
+ const bosluk = 8;
152
+ const yerler = {
153
+ top: { left: r.left + r.width / 2, top: r.top - bosluk },
154
+ bottom: { left: r.left + r.width / 2, top: r.bottom + bosluk },
155
+ left: { left: r.left - bosluk, top: r.top + r.height / 2 },
156
+ right: { left: r.right + bosluk, top: r.top + r.height / 2 },
157
+ };
158
+ setKonum(yerler[placement]);
159
+ }, [placement]);
160
+ const kapat = useCallback(() => setKonum(null), []);
161
+ /* Kaydırma ya da yeniden boyutlanma ipucunun altından tetikleyiciyi çekiyor;
162
+ o an kapanması, yanlış yerde durmasından iyi. */
163
+ useEffect(() => {
164
+ if (!konum)
165
+ return;
166
+ window.addEventListener("scroll", kapat, true);
167
+ window.addEventListener("resize", kapat);
168
+ return () => {
169
+ window.removeEventListener("scroll", kapat, true);
170
+ window.removeEventListener("resize", kapat);
171
+ };
172
+ }, [konum, kapat]);
173
+ const kaydirma = {
174
+ top: "translate(-50%, -100%)",
175
+ bottom: "translate(-50%, 0)",
176
+ left: "translate(-100%, -50%)",
177
+ right: "translate(0, -50%)",
178
+ };
179
+ return (_jsxs("span", { ref: sarmal, className: "relative inline-flex", onPointerEnter: olc, onPointerLeave: kapat, onFocusCapture: olc, onBlurCapture: kapat, children: [children, konum && (_jsxs("span", { role: "tooltip", className: "pointer-events-none fixed z-40 whitespace-nowrap px-2 py-1 text-small", style: {
180
+ left: konum.left,
181
+ top: konum.top,
182
+ transform: kaydirma[placement],
183
+ background: "var(--color-ink)",
184
+ color: "var(--color-page)",
185
+ borderRadius: "var(--radius-ctl)",
186
+ }, children: [label, _jsx("span", { "aria-hidden": true, className: "absolute block", style: { background: "var(--color-ink)", ...arrows[placement] } })] }))] }));
187
+ }
188
+ export function Toast({ tone = "neutral", title, description, action, onDismiss, dismissLabel, }) {
189
+ const mark = tone === "neutral" ? "var(--color-ink)" : toneOf(tone).mark;
190
+ return (_jsxs("div", { role: "status", className: "tamga-toast tamga-overlay flex w-80 items-start gap-4 p-4", style: { animation: "tamga-toast-in var(--duration-base) var(--ease-standard) both" }, children: [_jsx("span", { className: "mt-1 size-2.5 shrink-0", style: { background: mark } }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-body font-medium text-ink", children: title }), description ? (_jsx("p", { className: "mt-1 text-small leading-relaxed text-ink-faint", children: description })) : null, action ? _jsx("div", { className: "mt-3", children: action }) : null] }), onDismiss ? (_jsx(MiniButton, { onClick: onDismiss, "aria-label": dismissLabel, children: _jsx(Icon, { icon: Close, size: "xs" }) })) : null] }));
191
+ }
192
+ /**
193
+ * Where toasts land. Top-right is the default: it is the one corner that
194
+ * never covers a table's actions column or a form's footer buttons.
195
+ */
196
+ const corners = {
197
+ "top-right": "top-6 right-6 items-end",
198
+ "top-left": "top-6 left-6 items-start",
199
+ "bottom-right": "bottom-6 right-6 items-end",
200
+ "bottom-left": "bottom-6 left-6 items-start",
201
+ };
202
+ export function ToastViewport({ position = "top-right", children, }) {
203
+ return (_jsx("div", { className: `pointer-events-none fixed z-50 flex flex-col gap-2 ${corners[position]}`, children: _jsx("div", { className: "pointer-events-auto flex flex-col gap-2", children: children }) }));
204
+ }
205
+ /* ---------------------------- dialog --------------------------- */
206
+ /**
207
+ * The modal shell. Hooks cannot run behind an early return, so the trap lives
208
+ * here and the surface below stays a plain component.
209
+ */
210
+ /**
211
+ * Diyalog genişliği. Bir VARYANT, ayrı bir bileşen değil (kitin kuralı: adı
212
+ * bölünen şey bileşen, ayarlanan şey prop).
213
+ *
214
+ * `wide` bir ÖNİZLEME için var: bir bloğu ya da tam bir ekran şablonunu 448
215
+ * pikselde göstermek, gösterdiğini gizlemek olur. `md` hâlâ varsayılan, çünkü
216
+ * bir diyaloğun asıl işi bir KARAR sormak ve geniş bir karar kutusu, kararı
217
+ * daha kolay yapmıyor.
218
+ *
219
+ * `full` BİR ÇALIŞMA YÜZEYİ için: bir görsel düzenleyici, bir tuval, bir harita
220
+ * seçici. Bunlar bir karar kutusu değil bir EKRAN, ve `wide` bile onlara az
221
+ * geliyor — kalan kenar boşluğu tuvalden çalınan alan. Bu boyutta panelin
222
+ * kenarı, yarıçapı ve kaydırma gölgesi de kalkıyor: yükseltilecek bir zemin
223
+ * kalmadığında yükselme işareti de anlamsız. Nadir olması gerekiyor; bir formu
224
+ * tam ekran açmak, formu daha kolay doldurmuyor.
225
+ */
226
+ const DIALOG_GENISLIK = {
227
+ md: "max-w-md",
228
+ lg: "max-w-3xl",
229
+ wide: "max-w-(--dialog-wide)",
230
+ full: "max-w-none",
231
+ };
232
+ function DialogShell({ open, onClose, loading, label, size = "md", children, }) {
233
+ const panel = useFocusTrap(open);
234
+ /* Aynı kaçak `Dialog`da da vardı: odak hapsediliyor ama arkadaki sayfa
235
+ kayıyordu. Kullanıcı etkileşemediği bir şeyi kaydırabiliyordu. */
236
+ useScrollLock(open);
237
+ useEffect(() => {
238
+ if (!open)
239
+ return;
240
+ const esc = (e) => e.key === "Escape" && onClose();
241
+ document.addEventListener("keydown", esc);
242
+ return () => document.removeEventListener("keydown", esc);
243
+ }, [open, onClose]);
244
+ if (!open)
245
+ return null;
246
+ /* Tam ekranda dış kenar boşluğu YOK: 24 piksel, bir tuvalden çalınan 24
247
+ pikseldir. Panel de yüzeyi kaplıyor ve dikey bir akış oluyor, ki gövde
248
+ kendi içinde kaysın ve başlık ile ayak yerinde kalsın. */
249
+ const tam = size === "full";
250
+ return (_jsxs("div", { className: cn("fixed inset-0 z-50 flex items-center justify-center", tam ? "p-0" : "p-6"), role: "dialog", "aria-modal": true, "aria-label": label, children: [_jsx("div", { className: "tamga-scrim absolute inset-0", "aria-hidden": true, onClick: onClose }), _jsx("div", { ref: panel, className: cn("tamga-overlay relative z-10 w-full", tam && "tamga-overlay-full", DIALOG_GENISLIK[size]), "aria-busy": loading || undefined, children: children })] }));
251
+ }
252
+ /**
253
+ * Yıkıcı bir eylemin önündeki kapı.
254
+ *
255
+ * NEDEN AYRI BİR BİLEŞEN. `Dialog` zaten var ve bu onun üstüne kurulu; ama
256
+ * "emin misin" diyaloğu her seferinde elle kurulduğunda üç şey kayıyor ve
257
+ * üçü de güvenlikle ilgili:
258
+ *
259
+ * 1. ONAY DÜĞMESİ FİİLİ TAŞIR, "Tamam"ı değil. Bir kullanıcı diyaloğun
260
+ * metnini okumadan düğmeye basar; okuduğu tek şey düğmenin üstündeki
261
+ * kelimedir. "Tamam" hiçbir şey söylemez, "Sil" söyler.
262
+ * 2. ODAK VAZGEÇ'TE AÇILIR. Yıkıcı bir diyalogda odağın onay düğmesinde
263
+ * olması, Enter'a basan birinin kaydı silmesi demek. Güvenli olan
264
+ * varsayılan olmalı.
265
+ * 3. GERİ ALINAMAZLIK YAZILIR. Gövde metni ne olacağını değil NEYİN GERİ
266
+ * GELMEYECEĞİNİ söyler; kullanıcının kararı buna bağlı.
267
+ *
268
+ * KELİMELER ÇAĞIRANIN. Kit hiçbir dil bilmiyor: başlık, gövde ve iki düğmenin
269
+ * etiketi dışarıdan geliyor.
270
+ */
271
+ export function ConfirmDialog({ open, onClose, onConfirm, title, children, confirmLabel, cancelLabel, closeLabel, tone = "danger", busy = false, confirmDisabled = false, }) {
272
+ return (_jsx(Dialog, { open: open, onClose: onClose, title: title, closeLabel: closeLabel, footer: _jsxs(_Fragment, { children: [_jsx(Button, { type: "button", onClick: onClose, disabled: busy, "data-autofocus": true, children: cancelLabel }), _jsx(Button, { variant: tone, onClick: onConfirm, disabled: busy || confirmDisabled, children: confirmLabel })] }), children: children }));
273
+ }
274
+ export function Dialog({ open, onClose, title, children, footer, loading = false, closeLabel, size = "md", }) {
275
+ return (_jsxs(DialogShell, { open: open, onClose: onClose, loading: loading, label: title, size: size, children: [_jsxs("div", { className: "tamga-head tamga-gutter tamga-section", children: [_jsx("h3", { className: "text-subhead font-semibold", children: title }), _jsx(MiniButton, { onClick: onClose, "aria-label": closeLabel, className: "ml-auto", children: _jsx(Icon, { icon: Close, size: "xs" }) })] }), _jsx("div", { className: cn("tamga-gutter py-6 text-body leading-relaxed", size === "full" && "min-h-0 flex-1 overflow-y-auto"), children: loading ? _jsx(SkeletonPanel, { lines: 4 }) : children }), footer ? (_jsx("div", { className: "tamga-gutter flex justify-end gap-2 border-t border-line py-4", children: footer })) : null] }));
276
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Pagination.
3
+ *
4
+ * Gerekçe: docs/gerekce/02-veri-ve-liste.md
5
+ */
6
+ /** Gösterilecek numaraları hesaplar. `null` = kısaltma. */
7
+ export declare function pageWindow(page: number, pages: number, span?: number): (number | null)[];
8
+ export declare function Pagination({ page, pageSize, total, onChange, labels, span, className, }: {
9
+ /** Starts at 1. TR: 1'den başlar. */
10
+ page: number;
11
+ pageSize: number;
12
+ /**
13
+ * Total records. Unknown, the numbers are hidden. TR: Toplam kayıt. Bilinmiyorsa numaralar
14
+ * gizlenir.
15
+ */
16
+ total?: number;
17
+ onChange?: (next: number) => void;
18
+ /**
19
+ * How many numbers show on each side of the active page. The window is `2·span + 5`: seven
20
+ * numbers at the default 1, nine at 2. TR: Aktif sayfanın her iki yanında kaç numara
21
+ * görünsün. Pencere genişliği `2·span + 5`: varsayılan 1 ile yedi, 2 ile dokuz numara.
22
+ */
23
+ span?: number;
24
+ /**
25
+ * Every visible string. The kit pulls no translations. `summary` is a function: languages
26
+ * place numbers differently ("1-25 / 240" · "1–25 of 240"), so the caller builds the
27
+ * template. TR: Görünen her metin. Kit çeviri çekmez. `summary` bir fonksiyon: dillerin sayı
28
+ * yerleşimi farklı ("1-25 / 240" · "1–25 of 240"), şablonu çağıran kurar.
29
+ */
30
+ labels: {
31
+ previous: string;
32
+ next: string;
33
+ page: (n: number) => string;
34
+ summary?: (from: number, to: number, total: number) => string;
35
+ };
36
+ className?: string;
37
+ }): import("react").JSX.Element;
38
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/components/pagination.tsx"],"names":[],"mappings":"AAMA;;;;GAIG;AAEH,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,SAAI,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAiBnF;AAED,wBAAgB,UAAU,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,QAAQ,EACR,MAAM,EACN,IAAQ,EACR,SAAS,GACV,EAAE;IACD,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;OAKG;IACH,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;QAC5B,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;KAC/D,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BA8DA"}
@@ -0,0 +1,46 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { cn } from "../lib/cn.js";
4
+ import { Icon } from "./icon.js";
5
+ import { CaretLeft, CaretRight } from "./icons.js";
6
+ /**
7
+ * Pagination.
8
+ *
9
+ * Gerekçe: docs/gerekce/02-veri-ve-liste.md
10
+ */
11
+ /** Gösterilecek numaraları hesaplar. `null` = kısaltma. */
12
+ export function pageWindow(page, pages, span = 1) {
13
+ /* Kısaltmasız sığan sayfa adedi `span`den TÜRETİLİYOR, sabit 7 değil:
14
+ pencere ilk + [kısaltma] + (2·span+1) + [kısaltma] + son, yani 2·span+5.
15
+ Sabit 7 yazılıydı ve `span` büyütüldüğünde sekiz sayfalık bir liste
16
+ gereksiz yere kısaltılıyordu. */
17
+ const sigan = span * 2 + 5;
18
+ if (pages <= sigan)
19
+ return Array.from({ length: pages }, (_, i) => i + 1);
20
+ const out = [1];
21
+ const from = Math.max(2, page - span);
22
+ const to = Math.min(pages - 1, page + span);
23
+ if (from > 2)
24
+ out.push(null);
25
+ for (let i = from; i <= to; i++)
26
+ out.push(i);
27
+ if (to < pages - 1)
28
+ out.push(null);
29
+ out.push(pages);
30
+ return out;
31
+ }
32
+ export function Pagination({ page, pageSize, total, onChange, labels, span = 1, className, }) {
33
+ const pages = total !== undefined ? Math.max(1, Math.ceil(total / pageSize)) : undefined;
34
+ const canPrev = page > 1;
35
+ const canNext = pages === undefined ? true : page < pages;
36
+ const from = (page - 1) * pageSize + 1;
37
+ const to = total !== undefined ? Math.min(page * pageSize, total) : page * pageSize;
38
+ return (_jsxs("nav", { className: cn("flex flex-wrap items-center gap-3", className), "aria-label": labels.page(page), children: [total !== undefined && labels.summary ? (_jsx("span", { className: "tamga-label tabular-nums", children: labels.summary(from, to, total) })) : null, _jsxs("span", { className: "ml-auto flex items-center gap-1.5", children: [_jsx("button", { type: "button", className: "tamga-icon-btn shrink-0", "aria-label": labels.previous, disabled: !canPrev, onClick: () => canPrev && onChange?.(page - 1), children: _jsx(Icon, { icon: CaretLeft, size: "sm" }) }), pages !== undefined
39
+ ? pageWindow(page, pages, span).map((n, i) => n === null ? (_jsx("span", { className: "px-1 text-small text-ink-faint", "aria-hidden": true, children: "\u2026" }, `gap-${i}`)) : (_jsx("button", { type: "button",
40
+ /* Seçili sayfa DOLGU almaz: "buradasın" bir eylem değildir
41
+ (Yasa 2). Gerekçesi `.tamga-page`'in üstünde — bu satır
42
+ bir zamanlar `.tamga-option` diyordu ve yorumun tersini
43
+ yapıyordu. */
44
+ className: "tamga-page tabular-nums", "aria-current": n === page ? "page" : undefined, "aria-label": labels.page(n), onClick: () => onChange?.(n), children: n }, n)))
45
+ : null, _jsx("button", { type: "button", className: "tamga-icon-btn shrink-0", "aria-label": labels.next, disabled: !canNext, onClick: () => canNext && onChange?.(page + 1), children: _jsx(Icon, { icon: CaretRight, size: "sm" }) })] })] }));
46
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Pasta / halka grafik — PARÇA-BÜTÜN, ve yalnız o.
3
+ *
4
+ * Gerekçe: docs/gerekce/03-grafik-ve-olcum.md
5
+ */
6
+ export type PieSlice = {
7
+ label: string;
8
+ value: number;
9
+ };
10
+ export declare function PieChart({ slices, total, totalLabel, formatValue, inner, size, className, }: {
11
+ /**
12
+ * Five slices at most: more does not read, and a chart that does not read is wrong
13
+ * information. TR: En çok beş dilim: fazlası okunmuyor, ve okunmayan bir grafik yanlış
14
+ * bilgidir.
15
+ */
16
+ slices: readonly PieSlice[];
17
+ /**
18
+ * The denominator. Left out, the sum of the slices; but it MUST be givable, because the
19
+ * slices do not always cover the whole: if a query leaves out customers with no gender, the
20
+ * percentages are percentages of that smaller set, and only the caller knows it. TR: Payda.
21
+ * Verilmezse dilimlerin toplamı; ama VERİLEBİLMESİ şart, çünkü dilimler her zaman bütünü
22
+ * kapsamıyor: bir sorgu cinsiyeti boş olan müşterileri dışarıda bırakıyorsa yüzdeler o eksik
23
+ * kümenin yüzdesidir ve bunu ancak çağıran bilir.
24
+ */
25
+ total?: number;
26
+ /**
27
+ * The name of the total in the middle of the ring: "members", "orders". TR: Halkanın
28
+ * ortasındaki toplamın adı: "üye", "sipariş".
29
+ */
30
+ totalLabel?: string;
31
+ formatValue?: (v: number) => string;
32
+ /**
33
+ * 0 a full pie, between 0 and 1 the ring's thickness. TR: 0 tam pasta, 0 ile 1 arası halka
34
+ * kalınlığı.
35
+ */
36
+ inner?: number;
37
+ size?: number;
38
+ className?: string;
39
+ }): import("react").JSX.Element;
40
+ //# sourceMappingURL=pie.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pie.d.ts","sourceRoot":"","sources":["../../src/components/pie.tsx"],"names":[],"mappings":"AAKA;;;;GAIG;AAEH,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAUF,wBAAgB,QAAQ,CAAC,EACvB,MAAM,EACN,KAAK,EACL,UAAU,EACV,WAAoB,EACpB,KAAY,EACZ,IAAU,EACV,SAAS,GACV,EAAE;IACD;;;;OAIG;IACH,MAAM,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC5B;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAwJA"}
@@ -0,0 +1,74 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId, useState } from "react";
4
+ import { cn } from "../lib/cn.js";
5
+ const R = 100;
6
+ /** Kutup koordinatından kartezyene; 0° saat 12 yönü. */
7
+ function nokta(aci, yaricap) {
8
+ const rad = ((aci - 90) * Math.PI) / 180;
9
+ return [R + yaricap * Math.cos(rad), R + yaricap * Math.sin(rad)];
10
+ }
11
+ export function PieChart({ slices, total, totalLabel, formatValue = String, inner = 0.58, size = 200, className, }) {
12
+ const id = useId();
13
+ /* Üzerinde durulan dilimin indeksi. Grafik ile legend AYNI durumu paylaşıyor:
14
+ legend satırına gelmek dilimi, dilime gelmek legend satırını vurguluyor.
15
+ İkisi ayrı olsaydı kullanıcı hangi satırın hangi dilim olduğunu yine gözle
16
+ eşleştirmek zorunda kalırdı, ki bu tam da legend'ın çözdüğü sorun. */
17
+ const [uzerinde, setUzerinde] = useState(null);
18
+ const toplam = total ?? slices.reduce((n, s) => n + s.value, 0);
19
+ const ic = R * inner;
20
+ let aci = 0;
21
+ const parcalar = slices.map((s, i) => {
22
+ const pay = toplam > 0 ? s.value / toplam : 0;
23
+ const bas = aci;
24
+ const son = aci + pay * 360;
25
+ aci = son;
26
+ return { ...s, pay, bas, son, renk: `var(--color-chart-${(i % 5) + 1})` };
27
+ });
28
+ return (_jsxs("div", { className: cn("flex flex-wrap items-center gap-6", className), children: [_jsxs("svg", {
29
+ /* `viewBox` dilimin dışarı taşan halini de kapsıyor: üzerine gelinen
30
+ dilim 6 birim dışarı kayıyor, ve kutu büyümezse kırpılıyor. */
31
+ viewBox: `-8 -8 ${R * 2 + 16} ${R * 2 + 16}`, width: size, height: size, className: "shrink-0 overflow-visible", role: "img", "aria-labelledby": id, onMouseLeave: () => setUzerinde(null), children: [_jsx("title", { id: id, children: parcalar
32
+ .map((p) => `${p.label}: ${formatValue(p.value)} (%${(p.pay * 100).toFixed(1)})`)
33
+ .join(", ") }), parcalar.map((p, i) => {
34
+ if (p.pay <= 0)
35
+ return null;
36
+ /* TEK DİLİM %100 İSE YAY ÇİZİLEMEZ: başlangıç ve bitiş noktası
37
+ çakışır ve `A` komutu hiçbir şey çizmez. Tam daire ayrı bir yol. */
38
+ if (p.pay >= 0.999) {
39
+ return (_jsxs("g", { children: [_jsx("circle", { cx: R, cy: R, r: R, fill: p.renk }), ic > 0 && _jsx("circle", { cx: R, cy: R, r: ic, fill: "var(--color-shell)" })] }, p.label));
40
+ }
41
+ const [x1, y1] = nokta(p.bas, R);
42
+ const [x2, y2] = nokta(p.son, R);
43
+ const [x3, y3] = nokta(p.son, ic);
44
+ const [x4, y4] = nokta(p.bas, ic);
45
+ const buyuk = p.son - p.bas > 180 ? 1 : 0;
46
+ const d = ic > 0
47
+ ? `M ${x1} ${y1} A ${R} ${R} 0 ${buyuk} 1 ${x2} ${y2} L ${x3} ${y3} A ${ic} ${ic} 0 ${buyuk} 0 ${x4} ${y4} Z`
48
+ : `M ${R} ${R} L ${x1} ${y1} A ${R} ${R} 0 ${buyuk} 1 ${x2} ${y2} Z`;
49
+ /* ÜZERİNE GELİNEN DİLİM DIŞARI KAYIYOR, büyümüyor.
50
+ Büyütmek dilimin AÇISINI değiştirmiyor ama gözde öyle bir izlenim
51
+ bırakıyor: bir oran grafiğinde en son isteyeceğin şey. Merkezden
52
+ dışarı kaydırmak açıyı da yarıçapı da koruyor. */
53
+ const orta = (p.bas + p.son) / 2;
54
+ const [kx, ky] = nokta(orta, 6);
55
+ const secili = uzerinde === i;
56
+ return (_jsx("path", { d: d, fill: p.renk,
57
+ /* Dilimler arasındaki ince ayraç zemin renginde: iki komşu
58
+ dilim aynı tonda olsa bile sınır görünüyor. */
59
+ stroke: "var(--color-shell)", strokeWidth: 2, style: {
60
+ transform: secili ? `translate(${kx - R}px, ${ky - R}px)` : undefined,
61
+ /* Öteki dilimler soluyor: vurgulanan şey parlamıyor, çevresi
62
+ çekiliyor. Rengi açmak paleti bozardı. */
63
+ opacity: uzerinde === null || secili ? 1 : 0.45,
64
+ transition: "opacity var(--duration-press) var(--ease-standard), transform var(--duration-press) var(--ease-standard)",
65
+ }, onMouseEnter: () => setUzerinde(i) }, p.label));
66
+ }), ic > 0 && toplam > 0 && (_jsxs(_Fragment, { children: [_jsx("text", { x: R, y: R - 4, textAnchor: "middle", className: "fill-[var(--color-ink)] font-semibold", style: { fontSize: 26 }, children: uzerinde === null
67
+ ? formatValue(toplam)
68
+ : formatValue(parcalar[uzerinde]?.value ?? 0) }), _jsx("text", { x: R, y: R + 20, textAnchor: "middle", className: "fill-[var(--color-ink-faint)]", style: { fontSize: 14 }, children: uzerinde === null
69
+ ? (totalLabel ?? "")
70
+ : `${parcalar[uzerinde]?.label} · %${((parcalar[uzerinde]?.pay ?? 0) * 100).toFixed(1)}` })] }))] }), _jsx("dl", { className: "min-w-0 flex-1 flex-col gap-2", children: parcalar.map((p, i) => (_jsxs("div", { className: "flex cursor-default items-baseline gap-2.5 rounded-(--radius-mark) px-1.5 py-1 transition-[background] duration-(--duration-press)", style: {
71
+ background: uzerinde === i ? "var(--color-hover)" : undefined,
72
+ opacity: uzerinde === null || uzerinde === i ? 1 : 0.5,
73
+ }, onMouseEnter: () => setUzerinde(i), onMouseLeave: () => setUzerinde(null), children: [_jsx("span", { "aria-hidden": true, className: "size-2.5 shrink-0 translate-y-px rounded-(--radius-mark)", style: { background: p.renk } }), _jsx("dt", { className: "min-w-0 flex-1 truncate text-ink", children: p.label }), _jsxs("dd", { className: "shrink-0 tabular-nums text-ink", children: [formatValue(p.value), _jsxs("span", { className: "ml-1.5 text-ink-faint", children: ["%", (p.pay * 100).toFixed(1)] })] })] }, p.label))) })] }));
74
+ }
@@ -0,0 +1,96 @@
1
+ import type { Tone } from "./tone.js";
2
+ export { Spinner } from "./spinner.js";
3
+ export declare function Separator({ vertical }: {
4
+ vertical?: boolean;
5
+ }): import("react").JSX.Element;
6
+ /** Running is not a deviation, so the live mark stays neutral — the pulse carries it. */
7
+ export declare function Beacon({ live, label, severity, }: {
8
+ live?: boolean;
9
+ label?: string;
10
+ /**
11
+ * a bare beacon outranks nothing in particular; give it a rank to compete TR: çıplak bir
12
+ * işaret hiçbir şeye üstün gelmez; yarışması için ona bir sıra verin
13
+ */
14
+ severity?: number | null;
15
+ }): import("react").JSX.Element;
16
+ export declare function Alert({ state, title, children, action, }: {
17
+ state?: Tone;
18
+ title: string;
19
+ children?: React.ReactNode;
20
+ action?: React.ReactNode;
21
+ }): import("react").JSX.Element;
22
+ export declare function Breadcrumb({ items, label, }: {
23
+ items: {
24
+ label: string;
25
+ href?: string;
26
+ }[];
27
+ /**
28
+ * The landmark's accessible name; see the note on Spinner. TR: Landmark'ın erişilebilir adı;
29
+ * Spinner'daki nota bakın.
30
+ */
31
+ label: string;
32
+ }): import("react").JSX.Element;
33
+ export declare function Field({ label, description, error, children, htmlFor, }: {
34
+ label: string;
35
+ description?: string;
36
+ error?: string;
37
+ children: React.ReactNode;
38
+ htmlFor?: string;
39
+ }): import("react").JSX.Element;
40
+ /** A plain select: the same overlay as the searchable one, without the search. */
41
+ export declare function Select({ options, value, onChange, placeholder, loading, loadingRows, className, }: {
42
+ options: string[];
43
+ value?: string;
44
+ onChange?: (v: string) => void;
45
+ /**
46
+ * Visible when nothing is chosen; user-facing, so the caller supplies it translated. TR:
47
+ * Hiçbir şey seçilmemişken görünür; kullanıcıya gösterildiği için çevirisini çağıran veriyor.
48
+ */
49
+ placeholder: string;
50
+ /**
51
+ * options not in yet; the list holds its shape instead of showing a spinner TR: seçenekler
52
+ * henüz gelmedi; liste bir dönen simge göstermek yerine şeklini koruyor
53
+ */
54
+ loading?: boolean;
55
+ /**
56
+ * How many skeleton rows to hold while `loading`. SETTLED 2026-08-19 (open question 4): this
57
+ * is never a taste value; it is the number of records that are actually coming, because the
58
+ * whole point of the skeleton is that the panel does not resize when they land. Where that
59
+ * number comes from (api-kontrati.html A7, KİLİTLİ): · paginated list → the request's
60
+ * `page_size` (DRF default 25, max 100) · last page → `meta.count - (page - 1) * page_size` ·
61
+ * cursor list → `page_size` (no `count` is returned, by design) · known-size menu → the item
62
+ * count the caller already knows The default of 4 fits a menu, not a list. A list that leaves
63
+ * it at 4 is a bug that looks like a design choice. TR: `loading` sürerken kaç iskelet satırı
64
+ * tutulacağı. 2026-08-19'da KARARA BAĞLANDI (açık soru 4): bu asla bir zevk değeri değil;
65
+ * gerçekten gelmekte olan kayıt sayısı, çünkü iskeletin bütün amacı kayıtlar geldiğinde
66
+ * panelin yeniden boyutlanmaması. O sayının nereden geldiği (api-kontrati.html A7, KİLİTLİ):
67
+ * · sayfalı liste → isteğin `page_size` değeri (DRF varsayılanı 25, en çok 100) · son sayfa →
68
+ * `meta.count - (page - 1) * page_size` · imleçli liste → `page_size` (tasarım gereği `count`
69
+ * dönmüyor) · boyu bilinen menü → çağıranın zaten bildiği öğe sayısı Varsayılan 4 bir menüye
70
+ * uyuyor, bir listeye değil. 4'te bırakılmış bir liste, tasarım kararı gibi görünen bir
71
+ * hatadır.
72
+ */
73
+ loadingRows?: number;
74
+ /** Genişlik ve konum çağıranın. Varsayılan `w-56`; `w-full` verildiğinde
75
+ * tailwind-merge onu ezer, yani kontrol kabına uyar. */
76
+ className?: string;
77
+ }): import("react").JSX.Element;
78
+ /** Side panel. Overlay plane, so it carries the 6px offset and a scrim. */
79
+ export declare function Sheet({ open, onClose, title, children, footer, loading, closeLabel, }: {
80
+ open: boolean;
81
+ onClose: () => void;
82
+ title: string;
83
+ children: React.ReactNode;
84
+ footer?: React.ReactNode;
85
+ /**
86
+ * Accessible name for the close control, supplied by the caller (docs/08 rule 5). TR: Kapatma
87
+ * kontrolünün erişilebilir adı, çağıran veriyor (docs/08 kural 5).
88
+ */
89
+ closeLabel: string;
90
+ /**
91
+ * contents not in yet; the panel holds its shape instead of showing a spinner TR: içerik
92
+ * henüz gelmedi; panel bir dönen simge göstermek yerine şeklini koruyor
93
+ */
94
+ loading?: boolean;
95
+ }): import("react").JSX.Element | null;
96
+ //# sourceMappingURL=primitives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/components/primitives.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAWtC,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAQvC,wBAAgB,SAAS,CAAC,EAAE,QAAgB,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,+BAErE;AAED,yFAAyF;AACzF,wBAAgB,MAAM,CAAC,EACrB,IAAW,EACX,KAAK,EACL,QAAa,GACd,EAAE;IACD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,+BAQA;AAED,wBAAgB,KAAK,CAAC,EACpB,KAAiB,EACjB,KAAK,EACL,QAAQ,EACR,MAAM,GACP,EAAE;IACD,KAAK,CAAC,EAAE,IAAI,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC1B,+BAoBA;AAED,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,GACN,EAAE;IACD,KAAK,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;CACf,+BA0BA;AAED,wBAAgB,KAAK,CAAC,EACpB,KAAK,EACL,WAAW,EACX,KAAK,EACL,QAAQ,EACR,OAAO,GACR,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,+BAgBA;AAED,kFAAkF;AAClF,wBAAgB,MAAM,CAAC,EACrB,OAAO,EACP,KAAK,EACL,QAAQ,EACR,WAAW,EACX,OAAe,EACf,WAAe,EACf,SAAS,GACV,EAAE;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B;;;OAGG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;;;;;;;;;;;;;;;OAiBG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;6DACyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,+BAyEA;AAED,2EAA2E;AAC3E,wBAAgB,KAAK,CAAC,EACpB,IAAI,EACJ,OAAO,EACP,KAAK,EACL,QAAQ,EACR,MAAM,EACN,OAAe,EACf,UAAU,GACX,EAAE;IACD,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACzB;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB,sCA2CA"}