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,10 @@
1
+ import { type ClassValue } from "clsx";
2
+ /**
3
+ * Joins class names and lets a caller's utility win over the component's own.
4
+ *
5
+ * Without the merge, `<Button className="px-8">` produces "px-4 px-8" and which
6
+ * one applies depends on their order in the stylesheet, not on which the caller
7
+ * asked for. twMerge drops the loser, so an override is an override.
8
+ */
9
+ export declare function cn(...inputs: ClassValue[]): string;
10
+ //# sourceMappingURL=cn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/lib/cn.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C;;;;;;GAMG;AACH,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
package/dist/lib/cn.js ADDED
@@ -0,0 +1,12 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ /**
4
+ * Joins class names and lets a caller's utility win over the component's own.
5
+ *
6
+ * Without the merge, `<Button className="px-8">` produces "px-4 px-8" and which
7
+ * one applies depends on their order in the stylesheet, not on which the caller
8
+ * asked for. twMerge drops the loser, so an override is an override.
9
+ */
10
+ export function cn(...inputs) {
11
+ return twMerge(clsx(inputs));
12
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Renk matematiği: sRGB · OKLab · WCAG oranı · CIE L*.
3
+ *
4
+ * Bir bağımlılık değil çünkü ihtiyaç küçük ve KAPI'ya bağlı: paletin doğru
5
+ * olup olmadığını `check-token-contrast` ölçüyor, ve ölçenle üretenin aynı
6
+ * aritmetiği kullanması gerekiyor. `lib/color.test.ts` ikisinin aynı sayıyı
7
+ * verdiğini kanıtlıyor.
8
+ *
9
+ * NEDEN OKLCH. Palet "aynı açıklıkta, başka renk" üretmek zorunda: mor bir
10
+ * markanın zemini ile mavi bir markanın zemini AYNI açıklıkta olmalı, yoksa
11
+ * biri ötekinden koyu görünür ve kontrast eşikleri kayar. HSL bunu yapamıyor
12
+ * (HSL'de %50 sarı ile %50 mavi bambaşka parlaklıkta); OKLab algısal olarak
13
+ * düzgün, yani L sabit tutulduğunda açıklık gerçekten sabit kalıyor.
14
+ */
15
+ export type Oklch = {
16
+ l: number;
17
+ c: number;
18
+ h: number;
19
+ };
20
+ /** `#abc` ya da `#aabbcc`. Kısa biçim de sayılıyor, boşluk sayılmıyor. */
21
+ export declare const gecerliHex: (v: string) => boolean;
22
+ /**
23
+ * Hex → RGB, GEÇERSİZ GİRDİDE FIRLATARAK.
24
+ *
25
+ * Önce sessizce `NaN` üretiyordu ve palet gri bir şeye düşüyordu: bir kullanıcı
26
+ * hex kutusuna `#7c3aed` yazarken ara adımlarda (`#7`, `#7c`) panel griye
27
+ * dönüyor, sonra geri geliyordu. Hata vermeyen bir bozulma en pahalısı, çünkü
28
+ * sebebi rengin kendisinde aranıyor.
29
+ *
30
+ * Kit KATI, çağıran toleranslı: yarım yazılmış bir kodun ne anlama geldiği
31
+ * ekranın kararı (bkz. `gecerliHex`).
32
+ */
33
+ export declare function hexRgb(hex: string): [number, number, number];
34
+ export declare const rgbHex: (r: number, g: number, b: number) => string;
35
+ /** WCAG bağıl parlaklık. Metin kontrastı bununla ölçülüyor. */
36
+ export declare function parlaklik(hex: string): number;
37
+ /** WCAG kontrast oranı. AA metin eşiği 4.5. */
38
+ export declare function oran(a: string, b: string): number;
39
+ /**
40
+ * CIE L* · algısal açıklık.
41
+ *
42
+ * İki YÜZEYİN ayrı okunup okunmadığı bununla ölçülüyor; kontrast oranı metin
43
+ * içindir, yüzey için değil. Bir kartın kenarı sayfadan ΔL* ≥ 10 ayrı olmalı.
44
+ */
45
+ export declare function acikligi(hex: string): number;
46
+ export declare const dL: (a: string, b: string) => number;
47
+ export declare function hexOklch(hex: string): Oklch;
48
+ /**
49
+ * OKLCH → hex, GAMUT DIŞINA TAŞMADAN.
50
+ *
51
+ * Bir renk sRGB'ye sığmıyorsa kanalları kırpmak TONU kaydırıyor: mor bir yüz
52
+ * kırpıldığında maviye dönüyor ve marka rengi olmaktan çıkıyor. Onun yerine
53
+ * doyum (C) ikili aramayla sığana kadar düşürülüyor; ton ve açıklık korunuyor,
54
+ * yalnız canlılık gerektiği kadar azalıyor.
55
+ */
56
+ export declare function oklchHex({ l, c, h }: Oklch): string;
57
+ /**
58
+ * Verilen ton ve doyumda, HEDEF ORANI tutturan açıklığı arar.
59
+ *
60
+ * Palet "şu formülle koyulaştır" demiyor, ÖLÇÜP arıyor: bir rengin beyaz
61
+ * mürekkebi 4.5'te taşıyıp taşımadığı tona göre değişiyor (sarı ile lacivert
62
+ * aynı L'de aynı oranı vermiyor). Formül tahmin eder, arama ölçer.
63
+ *
64
+ * `yon` "koyulaş" (-1) ya da "açıl" (+1): koyu temada aynı hedef ters yönden
65
+ * yakalanıyor.
66
+ */
67
+ export declare function oranaGoreAcikligi(taban: Oklch, karsi: string, hedef: number, yon: -1 | 1): Oklch;
68
+ //# sourceMappingURL=color.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.d.ts","sourceRoot":"","sources":["../../src/lib/color.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,MAAM,MAAM,KAAK,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAKxD,0EAA0E;AAC1E,eAAO,MAAM,UAAU,MAAO,MAAM,KAAG,OAA0D,CAAC;AAElG;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM5D;AAGD,eAAO,MAAM,MAAM,MAAO,MAAM,KAAK,MAAM,KAAK,MAAM,WACuB,CAAC;AAE9E,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED,+CAA+C;AAC/C,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5C;AAED,eAAO,MAAM,EAAE,MAAO,MAAM,KAAK,MAAM,WAAwC,CAAC;AAIhF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAiB3C;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG,MAAM,CA6BnD;AAED;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GACV,KAAK,CAQP"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Renk matematiği: sRGB · OKLab · WCAG oranı · CIE L*.
3
+ *
4
+ * Bir bağımlılık değil çünkü ihtiyaç küçük ve KAPI'ya bağlı: paletin doğru
5
+ * olup olmadığını `check-token-contrast` ölçüyor, ve ölçenle üretenin aynı
6
+ * aritmetiği kullanması gerekiyor. `lib/color.test.ts` ikisinin aynı sayıyı
7
+ * verdiğini kanıtlıyor.
8
+ *
9
+ * NEDEN OKLCH. Palet "aynı açıklıkta, başka renk" üretmek zorunda: mor bir
10
+ * markanın zemini ile mavi bir markanın zemini AYNI açıklıkta olmalı, yoksa
11
+ * biri ötekinden koyu görünür ve kontrast eşikleri kayar. HSL bunu yapamıyor
12
+ * (HSL'de %50 sarı ile %50 mavi bambaşka parlaklıkta); OKLab algısal olarak
13
+ * düzgün, yani L sabit tutulduğunda açıklık gerçekten sabit kalıyor.
14
+ */
15
+ const srgbDoğrusal = (v) => (v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4);
16
+ const doğrusalSrgb = (v) => (v <= 0.0031308 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055);
17
+ /** `#abc` ya da `#aabbcc`. Kısa biçim de sayılıyor, boşluk sayılmıyor. */
18
+ export const gecerliHex = (v) => /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.test(v.trim());
19
+ /**
20
+ * Hex → RGB, GEÇERSİZ GİRDİDE FIRLATARAK.
21
+ *
22
+ * Önce sessizce `NaN` üretiyordu ve palet gri bir şeye düşüyordu: bir kullanıcı
23
+ * hex kutusuna `#7c3aed` yazarken ara adımlarda (`#7`, `#7c`) panel griye
24
+ * dönüyor, sonra geri geliyordu. Hata vermeyen bir bozulma en pahalısı, çünkü
25
+ * sebebi rengin kendisinde aranıyor.
26
+ *
27
+ * Kit KATI, çağıran toleranslı: yarım yazılmış bir kodun ne anlama geldiği
28
+ * ekranın kararı (bkz. `gecerliHex`).
29
+ */
30
+ export function hexRgb(hex) {
31
+ if (!gecerliHex(hex))
32
+ throw new Error(`Geçersiz hex: ${JSON.stringify(hex)}`);
33
+ const s = hex.trim().replace("#", "");
34
+ const t = s.length === 3 ? [...s].map((c) => c + c).join("") : s;
35
+ const n = Number.parseInt(t, 16);
36
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
37
+ }
38
+ const kanal = (v) => Math.max(0, Math.min(255, Math.round(v * 255)));
39
+ export const rgbHex = (r, g, b) => "#" + [r, g, b].map((v) => kanal(v).toString(16).padStart(2, "0")).join("");
40
+ /** WCAG bağıl parlaklık. Metin kontrastı bununla ölçülüyor. */
41
+ export function parlaklik(hex) {
42
+ const [r, g, b] = hexRgb(hex).map((v) => srgbDoğrusal(v / 255));
43
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
44
+ }
45
+ /** WCAG kontrast oranı. AA metin eşiği 4.5. */
46
+ export function oran(a, b) {
47
+ const [ust, alt] = [parlaklik(a), parlaklik(b)].sort((x, y) => y - x);
48
+ return (ust + 0.05) / (alt + 0.05);
49
+ }
50
+ /**
51
+ * CIE L* · algısal açıklık.
52
+ *
53
+ * İki YÜZEYİN ayrı okunup okunmadığı bununla ölçülüyor; kontrast oranı metin
54
+ * içindir, yüzey için değil. Bir kartın kenarı sayfadan ΔL* ≥ 10 ayrı olmalı.
55
+ */
56
+ export function acikligi(hex) {
57
+ const y = parlaklik(hex);
58
+ return y > 216 / 24389 ? 116 * Math.cbrt(y) - 16 : (y * 24389) / 27;
59
+ }
60
+ export const dL = (a, b) => Math.abs(acikligi(a) - acikligi(b));
61
+ /* ---- OKLab ---- */
62
+ export function hexOklch(hex) {
63
+ const [r8, g8, b8] = hexRgb(hex);
64
+ const r = srgbDoğrusal(r8 / 255);
65
+ const g = srgbDoğrusal(g8 / 255);
66
+ const b = srgbDoğrusal(b8 / 255);
67
+ const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
68
+ const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
69
+ const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
70
+ const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
71
+ const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
72
+ const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
73
+ const c = Math.hypot(A, B);
74
+ const h = c < 1e-6 ? 0 : ((Math.atan2(B, A) * 180) / Math.PI + 360) % 360;
75
+ return { l: L, c, h };
76
+ }
77
+ /**
78
+ * OKLCH → hex, GAMUT DIŞINA TAŞMADAN.
79
+ *
80
+ * Bir renk sRGB'ye sığmıyorsa kanalları kırpmak TONU kaydırıyor: mor bir yüz
81
+ * kırpıldığında maviye dönüyor ve marka rengi olmaktan çıkıyor. Onun yerine
82
+ * doyum (C) ikili aramayla sığana kadar düşürülüyor; ton ve açıklık korunuyor,
83
+ * yalnız canlılık gerektiği kadar azalıyor.
84
+ */
85
+ export function oklchHex({ l, c, h }) {
86
+ const dene = (kroma) => {
87
+ const hr = (h * Math.PI) / 180;
88
+ const A = Math.cos(hr) * kroma;
89
+ const B = Math.sin(hr) * kroma;
90
+ const l_ = (l + 0.3963377774 * A + 0.2158037573 * B) ** 3;
91
+ const m_ = (l - 0.1055613458 * A - 0.0638541728 * B) ** 3;
92
+ const s_ = (l - 0.0894841775 * A - 1.291485548 * B) ** 3;
93
+ return [
94
+ doğrusalSrgb(+4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_),
95
+ doğrusalSrgb(-1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_),
96
+ doğrusalSrgb(-0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_),
97
+ ];
98
+ };
99
+ const sigiyorMu = (v) => v.every((x) => x >= -0.001 && x <= 1.001);
100
+ let rgb = dene(c);
101
+ if (!sigiyorMu(rgb)) {
102
+ let alt = 0;
103
+ let ust = c;
104
+ for (let i = 0; i < 24; i++) {
105
+ const orta = (alt + ust) / 2;
106
+ if (sigiyorMu(dene(orta)))
107
+ alt = orta;
108
+ else
109
+ ust = orta;
110
+ }
111
+ rgb = dene(alt);
112
+ }
113
+ return rgbHex(...rgb);
114
+ }
115
+ /**
116
+ * Verilen ton ve doyumda, HEDEF ORANI tutturan açıklığı arar.
117
+ *
118
+ * Palet "şu formülle koyulaştır" demiyor, ÖLÇÜP arıyor: bir rengin beyaz
119
+ * mürekkebi 4.5'te taşıyıp taşımadığı tona göre değişiyor (sarı ile lacivert
120
+ * aynı L'de aynı oranı vermiyor). Formül tahmin eder, arama ölçer.
121
+ *
122
+ * `yon` "koyulaş" (-1) ya da "açıl" (+1): koyu temada aynı hedef ters yönden
123
+ * yakalanıyor.
124
+ */
125
+ export function oranaGoreAcikligi(taban, karsi, hedef, yon) {
126
+ let en = { ...taban };
127
+ for (let i = 0; i < 60; i++) {
128
+ const aday = { ...taban, l: Math.max(0.02, Math.min(0.99, taban.l + yon * 0.01 * i)) };
129
+ en = aday;
130
+ if (oran(oklchHex(aday), karsi) >= hedef)
131
+ break;
132
+ }
133
+ return en;
134
+ }
@@ -0,0 +1,84 @@
1
+ import { acikligi, dL, gecerliHex, oran } from "./color.js";
2
+ /**
3
+ * Tek bir marka renginden iki temalık palet.
4
+ *
5
+ * NEDEN ÜRETİLİYOR. Bugüne kadar bir müşterinin rengi elle geçiriliyordu: yüz,
6
+ * taban, mürekkep, seçili satır zemini ve koyu tema karşılıkları tek tek
7
+ * seçiliyordu. Beş token için makul, otuz altı token için değil, ve her seferinde
8
+ * kontrast eşiği elle kontrol ediliyordu.
9
+ *
10
+ * ZEMİN DE DÖNÜYOR. Bugünün zemini sıcak kâğıt (#f5f2ec) ve aksandan bağımsız;
11
+ * mor bir markanın yanında sarıya çalıyor. Nötrler markanın TONUNU çok düşük
12
+ * doyumla taşıyor: gri kalıyorlar ama markanın grisi oluyorlar.
13
+ *
14
+ * EŞİKLER TAHMİN DEĞİL ARAMA. Her renk "şu formülle koyulaştır" ile değil,
15
+ * hedef orana ulaşana kadar ÖLÇÜLEREK bulunuyor — çünkü bir tonun beyaz
16
+ * mürekkebi hangi açıklıkta taşıdığı tona göre değişiyor. Sonuç
17
+ * `check-token-contrast` ile aynı aritmetikten geçiyor (bkz. `lib/color.ts`).
18
+ */
19
+ /** Bir temanın üreteceği token'lar. Adlar `theme.css`'teki kit ailesiyle birebir. */
20
+ export type Palet = {
21
+ page: string;
22
+ shell: string;
23
+ hover: string;
24
+ band: string;
25
+ rail: string;
26
+ sunk: string;
27
+ chartFill: string;
28
+ line: string;
29
+ edge: string;
30
+ tick: string;
31
+ ink: string;
32
+ inkSoft: string;
33
+ inkFaint: string;
34
+ accent: string;
35
+ accentHover: string;
36
+ accentActive: string;
37
+ accentInk: string;
38
+ accentLine: string;
39
+ accentBg: string;
40
+ accentShadow: string;
41
+ navIdle: string;
42
+ navHover: string;
43
+ navHoverBg: string;
44
+ };
45
+ export type PaletCifti = {
46
+ light: Palet;
47
+ dark: Palet;
48
+ };
49
+ /**
50
+ * Bir marka renginden iki tema.
51
+ *
52
+ * Geçersiz bir kodda FIRLATIYOR, sessizce griye düşmüyor: yarım yazılmış bir
53
+ * hex'in ne anlama geldiğine çağıran karar veriyor (`gecerliHex`).
54
+ */
55
+ export declare function paletUret(markaHex: string): PaletCifti;
56
+ export { gecerliHex };
57
+ export type Olcum = {
58
+ ad: string;
59
+ tur: "oran" | "dL";
60
+ deger: number;
61
+ esik: number;
62
+ gecti: boolean;
63
+ };
64
+ /**
65
+ * Üretilen paleti `check-token-contrast` ile AYNI eşiklerden geçirir.
66
+ *
67
+ * Üreticiye güvenmek yerine ölçmek şart: bir formül bugün doğru olabilir ve
68
+ * yarın bir ton için yanlış olur. Marka rengi değiştiğinde bu liste yeniden
69
+ * koşuyor, ve geçmeyen bir palet build'i kırıyor.
70
+ */
71
+ export declare function paletiOlc(p: Palet): Olcum[];
72
+ /**
73
+ * Bir paleti CSS değişkeni sözlüğüne çevirir: `{ "--color-accent": "#..." }`.
74
+ *
75
+ * NEDEN `paletCss` YETMİYOR: o bir STİL SAYFASI dizgisi üretiyor (`:root { … }`),
76
+ * ve bir stil sayfası ancak belgenin tamamına uygulanabiliyor. Bir paleti tek
77
+ * bir kutuya uygulamak (bir önizleme, bir tema seçici) ya da köke çalışma
78
+ * zamanında yazmak için gereken şey bir SÖZLÜK. Simge adları kalıtsal olduğu
79
+ * için bir kutuya yazılan palet, içindeki her bileşeni birlikte döndürüyor.
80
+ */
81
+ export declare function paletStili(p: Palet): Record<string, string>;
82
+ export declare function paletCss(cift: PaletCifti): string;
83
+ export { acikligi, dL, oran };
84
+ //# sourceMappingURL=palette.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"palette.d.ts","sourceRoot":"","sources":["../../src/lib/palette.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,UAAU,EAAsB,IAAI,EAAc,MAAM,YAAY,CAAC;AAE5F;;;;;;;;;;;;;;;;GAgBG;AAEH,qFAAqF;AACrF,MAAM,MAAM,KAAK,GAAG;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC;AAqHvD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,CAItD;AAED,OAAO,EAAE,UAAU,EAAE,CAAC;AAItB,MAAM,MAAM,KAAK,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpG;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,EAAE,CAsB3C;AAwBD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAI3D;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAMjD;AAED,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC"}
@@ -0,0 +1,193 @@
1
+ import { acikligi, dL, gecerliHex, hexOklch, oklchHex, oran } from "./color.js";
2
+ /**
3
+ * Nötrlerin AÇIKLIK basamakları, iki temada.
4
+ *
5
+ * Sayılar bugünkü paletten ölçüldü, uydurulmadı: `#f5f2ec` ile `#fdfcfa`
6
+ * arasındaki fark ne ise mor bir markada da o. Böylece marka değişince
7
+ * yüzeylerin BİRBİRİNE göre yeri sabit kalıyor, yalnız tonu dönüyor.
8
+ */
9
+ const BASAMAK = {
10
+ light: { page: 0.962, shell: 0.991, hover: 0.933, sunk: 0.933, line: 0.891, edge: 0.845, tick: 0.771, ink: 0.246, inkSoft: 0.372, inkFaint: 0.516, navIdle: 0.523, navHover: 0.386 },
11
+ dark: { page: 0.166, shell: 0.212, hover: 0.262, sunk: 0.262, line: 0.302, edge: 0.372, tick: 0.409, ink: 0.951, inkSoft: 0.869, inkFaint: 0.643, navIdle: 0.606, navHover: 0.869 },
12
+ };
13
+ /**
14
+ * Nötrlerin doyumu: gri kalacak kadar az, markayı taşıyacak kadar çok.
15
+ *
16
+ * YÜKSELEN YÜZEY TONSUZ, ve bu bir tutarsızlık değil bir ayrım. Marka rengi
17
+ * ZEMİNE giriyor: sayfa, şerit, ray, satır vurgusu. Kart ise zeminin üstünde
18
+ * DURAN şey, ve beyaza yakın kalması onu her markada aynı yükseklikte
19
+ * tutuyor — kartın rengi değil kenarı yükseltiyor (13 Yasa 1).
20
+ *
21
+ * Pratik karşılığı: müşteri rengini değiştirdiğinde sayfanın zemini dönüyor
22
+ * ama kenar çubuğu, üst şerit ve kartlar yerinde kalıyor. Panelin iskeleti
23
+ * sabit, rengi değişken.
24
+ */
25
+ const NOTR_DOYUM = { zemin: 0.006, yuzey: 0, cizgi: 0.009, murekkep: 0.014 };
26
+ const notr = (h, l, c) => oklchHex({ l, c, h });
27
+ /**
28
+ * Yüzün üstündeki mürekkep: beyaz mı koyu mu.
29
+ *
30
+ * ÖLÇÜLEREK seçiliyor, kurala göre değil. Lacivert bir yüz beyaz mürekkep
31
+ * taşıyor, sarı bir yüz taşımıyor — ve "markalar koyu olur" varsayımı ilk sarı
32
+ * markada okunmayan bir düğme üretiyor.
33
+ */
34
+ function yuzMurekkebi(yuz, acikNotr, koyuNotr) {
35
+ return oran(acikNotr, yuz) >= oran(koyuNotr, yuz) ? acikNotr : koyuNotr;
36
+ }
37
+ function temaUret(marka, koyu) {
38
+ const h = marka.h;
39
+ const b = koyu ? BASAMAK.dark : BASAMAK.light;
40
+ const page = notr(h, b.page, NOTR_DOYUM.zemin);
41
+ /* Kart · üst şerit · kenar çubuğu: markadan bağımsız. */
42
+ const shell = notr(h, b.shell, NOTR_DOYUM.yuzey);
43
+ const hover = notr(h, b.hover, NOTR_DOYUM.zemin);
44
+ const ink = notr(h, b.ink, NOTR_DOYUM.murekkep);
45
+ /* YÜZ: markanın KENDİ açıklığından başlıyor.
46
+ *
47
+ * İlk hâli sabit bir açıklıktan başlayıp beyaz mürekkep geçene kadar
48
+ * koyulaştırıyordu, ve sarı bir markayı `#8f6c00` yapıyordu: ölçüm geçiyor
49
+ * ama kimse ona sarı demiyor. Marka rengini tanınmaz hâle getiren bir palet
50
+ * üreticisi işini yapmıyor.
51
+ *
52
+ * Doğrusu: yüz markanın açıklığında kalıyor (kullanılabilir bir banda
53
+ * kırpılarak), MÜREKKEP ona göre seçiliyor. Lacivert bir yüz beyaz taşır,
54
+ * sarı bir yüz koyu taşır — ikisi de markasını koruyor. Yalnız hiçbir
55
+ * mürekkeple 4.5'e ulaşılamıyorsa yüz mürekkepten UZAĞA itiliyor. */
56
+ const band = koyu ? { alt: 0.58, ust: 0.82 } : { alt: 0.45, ust: 0.78 };
57
+ const yuzL = Math.max(band.alt, Math.min(band.ust, marka.l));
58
+ /* DOYUM KIRPILMIYOR. Bir süre `min(marka.c, 0.16)` vardı ve doygun bir marka
59
+ kırmızısını (C 0.215) `#c74a4a`ya soldurup markayı gözle görülür şekilde
60
+ değiştiriyordu. Kırpma gereksizdi: `oklchHex` zaten gamut'a sığmayan bir
61
+ rengi ikili aramayla sığdırıyor ve TONU koruyor. Kırpmak, çözülmüş bir
62
+ sorunu ikinci kez ve daha kötü çözmekti. */
63
+ const kroma = marka.c;
64
+ let yuz = oklchHex({ l: yuzL, c: kroma, h });
65
+ let murekkep = yuzMurekkebi(yuz, shell, ink);
66
+ for (let i = 1; i <= 40 && oran(yuz, murekkep) < 4.5; i++) {
67
+ /* Mürekkep açıksa yüz koyulaşır, koyuysa açılır: mesafe hep açılıyor. */
68
+ const yon = acikligi(murekkep) > 50 ? -1 : 1;
69
+ yuz = oklchHex({ l: Math.max(0.2, Math.min(0.92, yuzL + yon * 0.01 * i)), c: kroma, h });
70
+ murekkep = yuzMurekkebi(yuz, shell, ink);
71
+ }
72
+ const yuzOk = hexOklch(yuz);
73
+ const adim = (d) => oklchHex({ ...yuzOk, l: Math.max(0.06, Math.min(0.96, yuzOk.l + d)) });
74
+ /* ÇİZGİ RENGİ (bağlantı, odak halkası) sayfada AA geçmek zorunda: bir
75
+ bağlantı metindir. Yüz genelde geçmiyor, o yüzden ayrıca aranıyor. */
76
+ let cizgi = koyu ? adim(0.08) : adim(-0.18);
77
+ for (let i = 0; i < 40 && oran(cizgi, page) < 4.5; i++) {
78
+ cizgi = oklchHex({ ...yuzOk, l: Math.max(0.08, Math.min(0.95, yuzOk.l + (koyu ? 1 : -1) * (0.18 + 0.01 * i))) });
79
+ }
80
+ return {
81
+ page,
82
+ shell,
83
+ hover,
84
+ band: page,
85
+ rail: page,
86
+ sunk: hover,
87
+ chartFill: hover,
88
+ line: notr(h, b.line, NOTR_DOYUM.cizgi),
89
+ edge: notr(h, b.edge, NOTR_DOYUM.cizgi),
90
+ tick: notr(h, b.tick, NOTR_DOYUM.cizgi),
91
+ ink,
92
+ inkSoft: notr(h, b.inkSoft, NOTR_DOYUM.murekkep),
93
+ inkFaint: notr(h, b.inkFaint, NOTR_DOYUM.murekkep),
94
+ accent: yuz,
95
+ accentHover: adim(koyu ? 0.05 : -0.06),
96
+ accentActive: adim(koyu ? -0.04 : -0.11),
97
+ accentInk: murekkep,
98
+ accentLine: cizgi,
99
+ /* Seçili satır zemini: sayfaya çok yakın, ama ayrı okunuyor. */
100
+ accentBg: oklchHex({ l: koyu ? b.page + 0.06 : b.page - 0.035, c: 0.03, h }),
101
+ /* Taban: yüzün ALTINDA duran koyu, doygun renk (13 Yasa 1). */
102
+ accentShadow: oklchHex({ l: koyu ? 0.42 : 0.28, c: Math.min(marka.c, 0.13), h }),
103
+ navIdle: notr(h, b.navIdle, NOTR_DOYUM.murekkep),
104
+ navHover: notr(h, b.navHover, NOTR_DOYUM.murekkep),
105
+ navHoverBg: notr(h, koyu ? b.hover : b.hover - 0.01, NOTR_DOYUM.zemin),
106
+ };
107
+ }
108
+ /**
109
+ * Bir marka renginden iki tema.
110
+ *
111
+ * Geçersiz bir kodda FIRLATIYOR, sessizce griye düşmüyor: yarım yazılmış bir
112
+ * hex'in ne anlama geldiğine çağıran karar veriyor (`gecerliHex`).
113
+ */
114
+ export function paletUret(markaHex) {
115
+ if (!gecerliHex(markaHex))
116
+ throw new Error(`Geçersiz marka rengi: ${JSON.stringify(markaHex)}`);
117
+ const marka = hexOklch(markaHex);
118
+ return { light: temaUret(marka, false), dark: temaUret(marka, true) };
119
+ }
120
+ export { gecerliHex };
121
+ /**
122
+ * Üretilen paleti `check-token-contrast` ile AYNI eşiklerden geçirir.
123
+ *
124
+ * Üreticiye güvenmek yerine ölçmek şart: bir formül bugün doğru olabilir ve
125
+ * yarın bir ton için yanlış olur. Marka rengi değiştiğinde bu liste yeniden
126
+ * koşuyor, ve geçmeyen bir palet build'i kırıyor.
127
+ */
128
+ export function paletiOlc(p) {
129
+ const metin = (ad, a, b, esik = 4.5) => {
130
+ const deger = Number(oran(a, b).toFixed(2));
131
+ return { ad, tur: "oran", deger, esik, gecti: deger >= esik };
132
+ };
133
+ const yuzey = (ad, a, b, esik) => {
134
+ const deger = Number(dL(a, b).toFixed(1));
135
+ return { ad, tur: "dL", deger, esik, gecti: deger >= esik };
136
+ };
137
+ return [
138
+ metin("ink · page", p.ink, p.page),
139
+ metin("ink · shell", p.ink, p.shell),
140
+ metin("inkSoft · page", p.inkSoft, p.page),
141
+ metin("inkFaint · page", p.inkFaint, p.page),
142
+ metin("inkFaint · sunk", p.inkFaint, p.sunk),
143
+ metin("accentInk · accent", p.accentInk, p.accent),
144
+ metin("accentLine · page", p.accentLine, p.page),
145
+ metin("navIdle · rail", p.navIdle, p.rail),
146
+ yuzey("edge · page", p.edge, p.page, 10),
147
+ yuzey("line · page", p.line, p.page, 4),
148
+ yuzey("accentBg · page", p.accentBg, p.page, 1.2),
149
+ ];
150
+ }
151
+ /** `:root` bloğuna yapıştırılabilir CSS. */
152
+ /**
153
+ * Palet alanı → CSS simge adı.
154
+ *
155
+ * DIŞARI AÇIK, ÇÜNKÜ ÜÇÜNCÜ KOPYASI DOĞACAKTI. Bu eşleme `paletCss`in içinde
156
+ * özeldi; bir ürün paneli aynısını kendi dosyasına elle yazmıştı (rengi
157
+ * çalışma zamanında köke yazmak için), ve doküman sitesi de üçüncüsünü
158
+ * yazacaktı. Aynı yirmi iki satırın üç kopyası, kite bir simge eklendiği gün
159
+ * ikisinin sessizce eksik kalması demek.
160
+ */
161
+ const AD = {
162
+ page: "--color-page", shell: "--color-shell", hover: "--color-hover", band: "--color-band",
163
+ rail: "--color-rail", sunk: "--color-sunk", chartFill: "--color-chart-fill",
164
+ line: "--color-line", edge: "--color-edge", tick: "--color-tick",
165
+ ink: "--color-ink", inkSoft: "--color-ink-soft", inkFaint: "--color-ink-faint",
166
+ accent: "--color-accent", accentHover: "--color-accent-hover",
167
+ accentActive: "--color-accent-active", accentInk: "--color-accent-ink",
168
+ accentLine: "--color-accent-line", accentBg: "--color-accent-bg",
169
+ accentShadow: "--color-accent-shadow", navIdle: "--color-nav-idle",
170
+ navHover: "--color-nav-hover", navHoverBg: "--color-nav-hover-bg",
171
+ };
172
+ /**
173
+ * Bir paleti CSS değişkeni sözlüğüne çevirir: `{ "--color-accent": "#..." }`.
174
+ *
175
+ * NEDEN `paletCss` YETMİYOR: o bir STİL SAYFASI dizgisi üretiyor (`:root { … }`),
176
+ * ve bir stil sayfası ancak belgenin tamamına uygulanabiliyor. Bir paleti tek
177
+ * bir kutuya uygulamak (bir önizleme, bir tema seçici) ya da köke çalışma
178
+ * zamanında yazmak için gereken şey bir SÖZLÜK. Simge adları kalıtsal olduğu
179
+ * için bir kutuya yazılan palet, içindeki her bileşeni birlikte döndürüyor.
180
+ */
181
+ export function paletStili(p) {
182
+ const stil = {};
183
+ for (const alan of Object.keys(AD))
184
+ stil[AD[alan]] = p[alan];
185
+ return stil;
186
+ }
187
+ export function paletCss(cift) {
188
+ const blok = (p) => Object.entries(paletStili(p))
189
+ .map(([ad, deger]) => ` ${ad}: ${deger};`)
190
+ .join("\n");
191
+ return `:root {\n${blok(cift.light)}\n}\n\n.dark {\n${blok(cift.dark)}\n}\n`;
192
+ }
193
+ export { acikligi, dL, oran };
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Modal açıkken arkadaki sayfanın kaymasını durdurur.
3
+ *
4
+ * NEDEN VAR. `Sheet` ve `Dialog` odağı hapsediyordu ve Escape'i dinliyordu ama
5
+ * arkadaki sayfa kaymaya devam ediyordu. Kullanıcı panel açıkken tekerleği
6
+ * çevirdiğinde arkadaki liste kayıyor, panel kapandığında da kendini bambaşka
7
+ * bir yerde buluyordu. Odak zaten hapsedildiği için arkayla ETKİLEŞEMİYOR;
8
+ * kaydırabilmesi bir yetenek değil, bir kaçak.
9
+ *
10
+ * ÇUBUK GENİŞLİĞİ TELAFİ EDİLİYOR. `overflow: hidden` kaydırma çubuğunu
11
+ * kaldırıyor, ve çubuk kaybolunca sayfa o kadar genişleyip SIÇRIYOR. Kaybolan
12
+ * genişlik kadar sağdan dolgu veriliyor; kapanınca geri alınıyor.
13
+ *
14
+ * PANELİN KENDİSİ KAYAR. Bu kilit yalnız `body`ye bakıyor; panelin gövdesi
15
+ * kendi `overflow-y: auto` kabında, yani içeriği ekrandan uzunsa yine
16
+ * okunabiliyor. Her şeyi birden kilitlemek erişilebilirlik hatası olurdu.
17
+ */
18
+ export declare function useScrollLock(active: boolean): void;
19
+ //# sourceMappingURL=scroll-lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll-lock.d.ts","sourceRoot":"","sources":["../../src/lib/scroll-lock.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,QAc5C"}
@@ -0,0 +1,33 @@
1
+ import { useEffect } from "react";
2
+ /**
3
+ * Modal açıkken arkadaki sayfanın kaymasını durdurur.
4
+ *
5
+ * NEDEN VAR. `Sheet` ve `Dialog` odağı hapsediyordu ve Escape'i dinliyordu ama
6
+ * arkadaki sayfa kaymaya devam ediyordu. Kullanıcı panel açıkken tekerleği
7
+ * çevirdiğinde arkadaki liste kayıyor, panel kapandığında da kendini bambaşka
8
+ * bir yerde buluyordu. Odak zaten hapsedildiği için arkayla ETKİLEŞEMİYOR;
9
+ * kaydırabilmesi bir yetenek değil, bir kaçak.
10
+ *
11
+ * ÇUBUK GENİŞLİĞİ TELAFİ EDİLİYOR. `overflow: hidden` kaydırma çubuğunu
12
+ * kaldırıyor, ve çubuk kaybolunca sayfa o kadar genişleyip SIÇRIYOR. Kaybolan
13
+ * genişlik kadar sağdan dolgu veriliyor; kapanınca geri alınıyor.
14
+ *
15
+ * PANELİN KENDİSİ KAYAR. Bu kilit yalnız `body`ye bakıyor; panelin gövdesi
16
+ * kendi `overflow-y: auto` kabında, yani içeriği ekrandan uzunsa yine
17
+ * okunabiliyor. Her şeyi birden kilitlemek erişilebilirlik hatası olurdu.
18
+ */
19
+ export function useScrollLock(active) {
20
+ useEffect(() => {
21
+ if (!active)
22
+ return;
23
+ const { overflow, paddingRight } = document.body.style;
24
+ const bosluk = window.innerWidth - document.documentElement.clientWidth;
25
+ document.body.style.overflow = "hidden";
26
+ if (bosluk > 0)
27
+ document.body.style.paddingRight = `${bosluk}px`;
28
+ return () => {
29
+ document.body.style.overflow = overflow;
30
+ document.body.style.paddingRight = paddingRight;
31
+ };
32
+ }, [active]);
33
+ }
@@ -0,0 +1,36 @@
1
+ import type { ComponentProps, ReactNode } from "react";
2
+ import { Icon } from "../components/icon.js";
3
+ import { type LinkComponent } from "./shared.js";
4
+ /**
5
+ * Oturum açmış her ekranın içinde durduğu çerçeve: ray, üst şerit, yüzey.
6
+ *
7
+ * Menü ve açık giriş DIŞARIDAN gelir; kabuk hiçbir ürünün sözlüğünü ve hiçbir
8
+ * yönlendiriciyi tanımaz. Gerekçe: docs/adr/0004-sablon-katmani.md
9
+ */
10
+ export type NavEntry = {
11
+ key: string;
12
+ href: string;
13
+ /** Çevrilmiş etiket. Ray dar olduğu için ekranda değil, `title` ve etikette. */
14
+ label: string;
15
+ icon: ComponentProps<typeof Icon>["icon"];
16
+ };
17
+ export type AppShellProps = {
18
+ /** Rayın tepesindeki marka işareti; kendi bağlantısını çağıran veriyor. */
19
+ brand?: ReactNode;
20
+ nav: readonly NavEntry[];
21
+ /** Açık yol. Rota `usePathname()` geçiyor. */
22
+ activePath: string;
23
+ /**
24
+ * Üst şerit KÜRESEL BAĞLAM, iş değil. İçerik çağıranın; şablon yalnız yerini
25
+ * garanti ediyor.
26
+ */
27
+ topbar?: ReactNode;
28
+ linkComponent?: LinkComponent;
29
+ labels: {
30
+ home: string;
31
+ primaryNav: string;
32
+ };
33
+ children: ReactNode;
34
+ };
35
+ export declare function AppShell({ brand, nav, activePath, topbar, linkComponent: Link, labels, children, }: AppShellProps): import("react").JSX.Element;
36
+ //# sourceMappingURL=app-shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-shell.d.ts","sourceRoot":"","sources":["../../src/patterns/app-shell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvD,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAC7C,OAAO,EAAa,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5D;;;;;GAKG;AAEH,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,2EAA2E;IAC3E,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,GAAG,EAAE,SAAS,QAAQ,EAAE,CAAC;IACzB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,QAAQ,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,GAAG,EACH,UAAU,EACV,MAAM,EACN,aAAa,EAAE,IAAgB,EAC/B,MAAM,EACN,QAAQ,GACT,EAAE,aAAa,+BAwDf"}
@@ -0,0 +1,14 @@
1
+ "use client";
2
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Icon } from "../components/icon.js";
4
+ import { PlainLink } from "./shared.js";
5
+ export function AppShell({ brand, nav, activePath, topbar, linkComponent: Link = PlainLink, labels, children, }) {
6
+ /* Bir giriş kendi alt ağacına sahip: `/urunler`, `/urunler/42/fotograflar`
7
+ üzerinde de açık giriştir. Tam eşleşme yalnız kök yol için, yoksa kısa href
8
+ altındaki her rotayı yutar. */
9
+ const isCurrent = (href) => href === "/" ? activePath === href : activePath === href || activePath.startsWith(`${href}/`);
10
+ return (_jsxs("div", { className: "flex h-dvh w-full overflow-hidden bg-shell text-ink-soft", children: [_jsxs("aside", { className: "flex w-16 shrink-0 flex-col items-center gap-2 bg-shell px-1 py-4", children: [brand ? (_jsxs(_Fragment, { children: [_jsx("span", { "aria-label": labels.home, className: "mb-2 flex size-10 shrink-0 items-center justify-center text-ink", children: brand }), _jsx("span", { className: "h-0 w-6 border-t border-line" })] })) : null, _jsx("nav", { "aria-label": labels.primaryNav, className: "tamga-rail-scroll flex w-full flex-1 flex-col items-center gap-2 py-1", children: nav.map((entry) => {
11
+ const current = isCurrent(entry.href);
12
+ return (_jsx(Link, { href: entry.href, "aria-label": entry.label, title: entry.label, "aria-current": current ? "page" : undefined, "data-active": current, "data-nav": entry.key, className: "tamga-rail-link", children: _jsx(Icon, { icon: entry.icon, size: "base" }) }, entry.key));
13
+ }) })] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("header", { className: "tamga-gutter flex items-center gap-4 py-4", children: topbar }), _jsx("div", { className: "min-h-0 flex-1 overflow-hidden p-4 pt-0", children: _jsx("main", { className: "tamga-surface h-full min-h-0 overflow-y-auto", children: children }) })] })] }));
14
+ }