tamga-ui 0.1.1 → 0.2.1

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 (64) hide show
  1. package/CHANGELOG.md +128 -0
  2. package/README.md +83 -91
  3. package/dist/blocks/count-row.d.ts +3 -3
  4. package/dist/blocks/count-row.d.ts.map +1 -1
  5. package/dist/blocks/filter-bar.d.ts +13 -13
  6. package/dist/blocks/filter-bar.d.ts.map +1 -1
  7. package/dist/blocks/save-bar.d.ts +3 -3
  8. package/dist/blocks/save-bar.d.ts.map +1 -1
  9. package/dist/components/appearance.d.ts +78 -0
  10. package/dist/components/appearance.d.ts.map +1 -0
  11. package/dist/components/appearance.js +73 -0
  12. package/dist/components/chrome.d.ts +54 -3
  13. package/dist/components/chrome.d.ts.map +1 -1
  14. package/dist/components/chrome.js +43 -2
  15. package/dist/components/primitives.d.ts +32 -2
  16. package/dist/components/primitives.d.ts.map +1 -1
  17. package/dist/components/primitives.js +11 -4
  18. package/dist/components/rail-link.d.ts +15 -2
  19. package/dist/components/rail-link.d.ts.map +1 -1
  20. package/dist/components/rail-link.js +11 -9
  21. package/dist/components/square-picker.d.ts +41 -0
  22. package/dist/components/square-picker.d.ts.map +1 -0
  23. package/dist/components/square-picker.js +90 -0
  24. package/dist/index.d.ts +4 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +4 -1
  27. package/dist/kit.css +257 -4
  28. package/dist/lib/color.d.ts +31 -11
  29. package/dist/lib/color.d.ts.map +1 -1
  30. package/dist/lib/color.js +40 -18
  31. package/dist/lib/image.d.ts +46 -0
  32. package/dist/lib/image.d.ts.map +1 -0
  33. package/dist/lib/image.js +95 -0
  34. package/dist/lib/palette.d.ts +38 -19
  35. package/dist/lib/palette.d.ts.map +1 -1
  36. package/dist/lib/palette.js +45 -33
  37. package/dist/patterns/app-shell.d.ts +22 -6
  38. package/dist/patterns/app-shell.d.ts.map +1 -1
  39. package/dist/patterns/app-shell.js +4 -5
  40. package/dist/patterns/appearance-template.d.ts +105 -0
  41. package/dist/patterns/appearance-template.d.ts.map +1 -0
  42. package/dist/patterns/appearance-template.js +23 -0
  43. package/dist/patterns/auth-template.d.ts +9 -6
  44. package/dist/patterns/auth-template.d.ts.map +1 -1
  45. package/dist/patterns/detail-template.d.ts +5 -5
  46. package/dist/patterns/detail-template.d.ts.map +1 -1
  47. package/dist/patterns/index.d.ts +2 -1
  48. package/dist/patterns/index.d.ts.map +1 -1
  49. package/dist/patterns/index.js +6 -1
  50. package/dist/patterns/list-template.d.ts +6 -6
  51. package/dist/patterns/list-template.d.ts.map +1 -1
  52. package/dist/patterns/overview-template.d.ts +3 -3
  53. package/dist/patterns/overview-template.d.ts.map +1 -1
  54. package/dist/patterns/public-template.d.ts +3 -3
  55. package/dist/patterns/public-template.d.ts.map +1 -1
  56. package/dist/patterns/settings-template.d.ts +15 -4
  57. package/dist/patterns/settings-template.d.ts.map +1 -1
  58. package/dist/patterns/settings-template.js +2 -2
  59. package/dist/patterns/shared.d.ts +3 -3
  60. package/dist/patterns/shared.d.ts.map +1 -1
  61. package/dist/patterns/wizard-template.d.ts +1 -1
  62. package/dist/patterns/wizard-template.d.ts.map +1 -1
  63. package/dist/patterns/wizard-template.js +2 -9
  64. package/package.json +3 -2
package/dist/kit.css CHANGED
@@ -999,7 +999,7 @@
999
999
  min-width: 28px;
1000
1000
  height: 28px;
1001
1001
  padding: 0 6px;
1002
- border-radius: var(--radius-mark);
1002
+ border-radius: var(--radius-sm);
1003
1003
  color: var(--color-ink-soft);
1004
1004
  font-size: var(--text-caption);
1005
1005
  cursor: pointer;
@@ -1283,9 +1283,14 @@
1283
1283
  color: var(--color-accent-line);
1284
1284
  box-shadow: 2px 2px 0 0 var(--color-accent-line);
1285
1285
  }
1286
+ /* DOLGU `accent`, KENAR `accent-shadow` — düğmenin sözleşmesinin aynısı.
1287
+ Burada dolgu `accent-line` idi: o bir METİN token'ı, sayfaya karşı 4.5
1288
+ arayarak üretiliyor, yani yüzden hep daha koyu. Sonuç ekranda şuydu: biten
1289
+ adımlar koyu, aynı ekrandaki her düğme ve rozet açık. Üstündeki mürekkep de
1290
+ `accent`e göre ölçülüyordu, `accent-line`a göre değil. */
1286
1291
  .tamga-step-mark[data-state="done"] {
1287
- border-color: var(--color-accent-line);
1288
- background: var(--color-accent-line);
1292
+ border-color: var(--color-accent-shadow);
1293
+ background: var(--color-accent);
1289
1294
  color: var(--color-accent-ink);
1290
1295
  }
1291
1296
  .tamga-step-line {
@@ -1296,7 +1301,7 @@
1296
1301
  background: var(--color-edge);
1297
1302
  }
1298
1303
  .tamga-step-line[data-done="true"] {
1299
- background: var(--color-accent-line);
1304
+ background: var(--color-accent);
1300
1305
  }
1301
1306
 
1302
1307
  .tamga-scrim {
@@ -1659,6 +1664,14 @@
1659
1664
  .tamga-table tbody tr[data-selected="true"] td:first-child {
1660
1665
  box-shadow: inset 2px 0 0 var(--color-accent-line);
1661
1666
  }
1667
+ /* SEÇİLİ SATIR İKİ ADLA GELEBİLİYOR, VE BİRİ BOYANMIYORDU.
1668
+ `SettingsTemplate` menüsündeki açık bölümü `data-active` ile işaretliyor
1669
+ (bir GEZİNME satırı: hangi sayfadasın), liste satırları ise `data-selected`
1670
+ ile (bir SEÇİM: hangi kayıtları işaretledin). İkisi farklı anlam ama aynı
1671
+ görünüm, ve kural yalnız ikincisi için yazılmıştı: ayarlar menüsünde
1672
+ hangi bölümde olduğun hiç görünmüyordu. Hiçbir şey patlamadı, çünkü
1673
+ tarayıcı bilmediği bir nitelik seçicisini sessizce atlıyor. */
1674
+ .tamga-list-row[data-active="true"],
1662
1675
  .tamga-list-row[data-selected="true"] {
1663
1676
  background: var(--color-accent-bg);
1664
1677
  box-shadow: inset 2px 0 0 var(--color-accent-line);
@@ -1668,6 +1681,10 @@
1668
1681
  color: var(--color-accent-line);
1669
1682
  font-weight: 500;
1670
1683
  text-underline-offset: 3px;
1684
+ /* `<a href>` pointer'ı tarayıcıdan alır; `href`siz bir `<a>`, bir `<span>`
1685
+ ya da link gibi görünen bir `<button>` almaz ve imleç `auto` kalır. Sınıf
1686
+ kendi imlecini söylemeli. */
1687
+ cursor: pointer;
1671
1688
  }
1672
1689
  .tamga-link:hover {
1673
1690
  text-decoration: underline;
@@ -1791,6 +1808,218 @@
1791
1808
  }
1792
1809
  }
1793
1810
 
1811
+ /* Çekmece kenardan kayarak girer; yön `side` ile aynı olmak zorunda, yoksa
1812
+ kapatma hareketi ters öğretilir. Gerekçe: /docs/sheet */
1813
+ .tamga-sheet-start {
1814
+ animation: tamga-sheet-start var(--duration-base) var(--ease-standard);
1815
+ }
1816
+ .tamga-sheet-end {
1817
+ animation: tamga-sheet-end var(--duration-base) var(--ease-standard);
1818
+ }
1819
+
1820
+ /* ------------------------------------------------------------------ *
1821
+ * GÖRÜNÜM AYARLARININ PARÇALARI.
1822
+ *
1823
+ * Üçü de bir üründe doğdu ve kite AYNI GEREKÇEYLE taşındı: her panelin bir
1824
+ * görünüm ayarı oluyor, ve kit onu vermediğinde her ürün kendi hex kutusunu
1825
+ * çiziyor. Kiti kuran bir ekip "renk seçimi" deyince altı hazır
1826
+ * kutuyu değil, çıplak bir metin girdisi elde ediyordu.
1827
+ * ------------------------------------------------------------------ */
1828
+
1829
+ /* Marka rengi kutusu. Seçili olan kitin fiziğiyle işaretli: 1px kenar artı
1830
+ 2px sert kaydırma. Kutunun İÇİNE çentik konmuyor, çentiğin kontrastı
1831
+ seçilen renge göre değişiyor ve açık bir renkte kayboluyor. */
1832
+ .tamga-swatch {
1833
+ display: inline-flex;
1834
+ width: var(--control);
1835
+ height: var(--control);
1836
+ align-items: center;
1837
+ justify-content: center;
1838
+ border: 1px solid var(--color-edge);
1839
+ border-radius: var(--radius-ctl);
1840
+ background: var(--color-shell);
1841
+ cursor: pointer;
1842
+ transition:
1843
+ transform var(--duration-press) var(--ease-standard),
1844
+ box-shadow var(--duration-press) var(--ease-standard);
1845
+ }
1846
+ .tamga-swatch > span {
1847
+ width: 20px;
1848
+ height: 20px;
1849
+ border-radius: var(--radius-mark);
1850
+ }
1851
+ .tamga-swatch:hover {
1852
+ transform: translate(-1px, -1px);
1853
+ box-shadow: 3px 3px 0 var(--color-edge);
1854
+ }
1855
+ .tamga-swatch[data-selected="true"] {
1856
+ border-color: var(--color-accent-line);
1857
+ box-shadow: 2px 2px 0 var(--color-accent-line);
1858
+ }
1859
+ .tamga-swatch:active {
1860
+ transform: translate(2px, 2px);
1861
+ box-shadow: 0 0 0 var(--color-edge);
1862
+ }
1863
+
1864
+ /* Tarayıcının kendi renk kutusu, kitin kenarlığıyla. */
1865
+ .tamga-color-input {
1866
+ width: 36px;
1867
+ height: 36px;
1868
+ padding: 2px;
1869
+ border: 1px solid var(--color-edge);
1870
+ border-radius: var(--radius-ctl);
1871
+ background: var(--color-shell);
1872
+ cursor: pointer;
1873
+ }
1874
+
1875
+ /* ------------------------------------------------------------------ *
1876
+ * TEMA KARTI — panelin minyatürü.
1877
+ *
1878
+ * "Açık · Koyu · Sistem" üç kelimeydi, ve bir tema seçimi kelimeyle
1879
+ * yapılmıyor: kullanıcı sonucu görmek istiyor. Her seçenek panelin
1880
+ * minyatürünü çiziyor (ray, gövde, satırlar) ve "Sistem" ikisini bir karede
1881
+ * yan yana gösteriyor, çünkü anlamı tam olarak bu.
1882
+ *
1883
+ * MİNYATÜR SABİT RENKLERLE, ve kitin tek istisnası bu. Seçenekler o an
1884
+ * yürürlükteki temayı değil SEÇİLİRSE ne olacağını gösteriyor; token
1885
+ * kullanılsaydı üçü de aynı görünürdü. Tek token: marka vurgusu, çünkü
1886
+ * önizlemenin yarısı o.
1887
+ * ------------------------------------------------------------------ */
1888
+ .tamga-theme-card {
1889
+ display: flex;
1890
+ flex-direction: column;
1891
+ gap: 8px;
1892
+ padding: 0;
1893
+ border: 0;
1894
+ background: none;
1895
+ cursor: pointer;
1896
+ text-align: center;
1897
+ }
1898
+ .tamga-theme-box {
1899
+ position: relative;
1900
+ display: flex;
1901
+ overflow: hidden;
1902
+ width: 112px;
1903
+ height: 72px;
1904
+ border: 1px solid var(--color-edge);
1905
+ border-radius: var(--radius-card);
1906
+ box-shadow: 2px 2px 0 var(--color-edge);
1907
+ transition:
1908
+ transform var(--duration-press) var(--ease-standard),
1909
+ box-shadow var(--duration-press) var(--ease-standard),
1910
+ border-color var(--duration-press) var(--ease-standard);
1911
+ }
1912
+ .tamga-theme-card:hover .tamga-theme-box {
1913
+ transform: translate(-1px, -1px);
1914
+ box-shadow: 3px 3px 0 var(--color-edge);
1915
+ }
1916
+ .tamga-theme-card:active .tamga-theme-box {
1917
+ transform: translate(2px, 2px);
1918
+ box-shadow: 0 0 0 var(--color-edge);
1919
+ }
1920
+ .tamga-theme-card[data-selected="true"] .tamga-theme-box {
1921
+ border-color: var(--color-accent-line);
1922
+ box-shadow: 2px 2px 0 var(--color-accent-line);
1923
+ }
1924
+ .tamga-theme-name {
1925
+ font-size: var(--text-small);
1926
+ color: var(--color-ink-faint);
1927
+ }
1928
+ .tamga-theme-card[data-selected="true"] .tamga-theme-name {
1929
+ font-weight: 500;
1930
+ color: var(--color-ink);
1931
+ }
1932
+
1933
+ .tamga-theme-half {
1934
+ display: flex;
1935
+ min-width: 0;
1936
+ flex: 1;
1937
+ gap: 4px;
1938
+ padding: 6px;
1939
+ }
1940
+ .tamga-theme-half[data-theme="light"] { background: #f4f2ee; }
1941
+ .tamga-theme-half[data-theme="dark"] { background: #16161a; }
1942
+
1943
+ .tamga-theme-rail {
1944
+ display: flex;
1945
+ width: 12px;
1946
+ flex-shrink: 0;
1947
+ flex-direction: column;
1948
+ gap: 3px;
1949
+ border-radius: 3px;
1950
+ padding: 3px;
1951
+ }
1952
+ .tamga-theme-half[data-theme="light"] .tamga-theme-rail { background: #fcfcfc; }
1953
+ .tamga-theme-half[data-theme="dark"] .tamga-theme-rail { background: #232327; }
1954
+
1955
+ .tamga-theme-body {
1956
+ display: flex;
1957
+ min-width: 0;
1958
+ flex: 1;
1959
+ flex-direction: column;
1960
+ gap: 3px;
1961
+ border-radius: 3px;
1962
+ padding: 4px;
1963
+ }
1964
+ .tamga-theme-half[data-theme="light"] .tamga-theme-body { background: #fcfcfc; }
1965
+ .tamga-theme-half[data-theme="dark"] .tamga-theme-body { background: #232327; }
1966
+
1967
+ .tamga-theme-line {
1968
+ height: 3px;
1969
+ border-radius: 2px;
1970
+ }
1971
+ .tamga-theme-half[data-theme="light"] .tamga-theme-line { background: #d8d4cf; }
1972
+ .tamga-theme-half[data-theme="dark"] .tamga-theme-line { background: #3a3a42; }
1973
+ /* Vurgu tema kuralını YENMEK ZORUNDA: daha düşük özgüllükte yazıldığında
1974
+ `[data-theme] .tamga-theme-line` onu eziyor ve marka rengi önizlemede hiç
1975
+ görünmüyor. */
1976
+ .tamga-theme-half .tamga-theme-line[data-accent="true"] {
1977
+ background: var(--color-accent);
1978
+ }
1979
+
1980
+ .tamga-theme-dot {
1981
+ height: 5px;
1982
+ width: 5px;
1983
+ border-radius: 2px;
1984
+ }
1985
+ .tamga-theme-half[data-theme="light"] .tamga-theme-dot { background: #d8d4cf; }
1986
+ .tamga-theme-half[data-theme="dark"] .tamga-theme-dot { background: #3a3a42; }
1987
+ .tamga-theme-half .tamga-theme-dot[data-accent="true"] {
1988
+ background: var(--color-accent);
1989
+ }
1990
+
1991
+ /* Yüklenen görselin durduğu kutu. Çıplak duran bir logo "buraya yüklendi"
1992
+ demiyor, "burada unutulmuş" diyor. Yükseklik sabit: logo geniş, amblem
1993
+ kare, ve ikisi farklı yükseklikte kutularda dursaydı bloklar hizasız
1994
+ görünürdü. */
1995
+ .tamga-image-field {
1996
+ display: flex;
1997
+ align-items: center;
1998
+ justify-content: center;
1999
+ height: 72px;
2000
+ min-width: 96px;
2001
+ padding: 10px 14px;
2002
+ border: 1px solid var(--color-edge);
2003
+ border-radius: var(--radius-card);
2004
+ background: var(--color-shell);
2005
+ box-shadow: 2px 2px 0 var(--color-edge);
2006
+ }
2007
+ /* Boş hâl: kesik çizgi "burası dolabilir" diyor, düz kenar "burası boş
2008
+ kaldı" diyor. */
2009
+ .tamga-image-field[data-empty] {
2010
+ border-style: dashed;
2011
+ box-shadow: none;
2012
+ color: var(--color-ink-faint);
2013
+ font-size: var(--text-small);
2014
+ }
2015
+
2016
+ /* Ayar bölümü, sol kenarında marka rengi. `SettingsPanel`in `accent`
2017
+ varyantı: bir görünüm ekranında bloklar birbirinden ayrılmalı ve ayıran
2018
+ şey rengin kendisi olmalı, çünkü ekranın konusu o. */
2019
+ .tamga-settings-panel-accent {
2020
+ border-left: 4px solid var(--color-accent);
2021
+ }
2022
+
1794
2023
  .tamga-label {
1795
2024
  font-size: var(--text-caption);
1796
2025
  font-weight: 500;
@@ -2105,6 +2334,24 @@
2105
2334
  }
2106
2335
  }
2107
2336
 
2337
+ @keyframes tamga-sheet-start {
2338
+ from {
2339
+ transform: translateX(-100%);
2340
+ }
2341
+ to {
2342
+ transform: none;
2343
+ }
2344
+ }
2345
+
2346
+ @keyframes tamga-sheet-end {
2347
+ from {
2348
+ transform: translateX(100%);
2349
+ }
2350
+ to {
2351
+ transform: none;
2352
+ }
2353
+ }
2354
+
2108
2355
  @keyframes tamga-bar {
2109
2356
  0%,
2110
2357
  100% {
@@ -2185,6 +2432,12 @@
2185
2432
  .tamga-toast {
2186
2433
  animation: none;
2187
2434
  }
2435
+ /* Duran bir çekmece yine de AÇIK olmalı: kayma gidiyor, panel yerinde
2436
+ beliriyor. */
2437
+ .tamga-sheet-start,
2438
+ .tamga-sheet-end {
2439
+ animation: none;
2440
+ }
2188
2441
  /* a stopped spinner must still be a visible mark, never an empty box */
2189
2442
  .tamga-spin-part {
2190
2443
  animation: none !important;
@@ -18,7 +18,7 @@ export type Oklch = {
18
18
  h: number;
19
19
  };
20
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;
21
+ export declare const isHex: (v: string) => boolean;
22
22
  /**
23
23
  * Hex → RGB, GEÇERSİZ GİRDİDE FIRLATARAK.
24
24
  *
@@ -28,23 +28,23 @@ export declare const gecerliHex: (v: string) => boolean;
28
28
  * sebebi rengin kendisinde aranıyor.
29
29
  *
30
30
  * Kit KATI, çağıran toleranslı: yarım yazılmış bir kodun ne anlama geldiği
31
- * ekranın kararı (bkz. `gecerliHex`).
31
+ * ekranın kararı (bkz. `isHex`).
32
32
  */
33
- export declare function hexRgb(hex: string): [number, number, number];
34
- export declare const rgbHex: (r: number, g: number, b: number) => string;
33
+ export declare function hexToRgb(hex: string): [number, number, number];
34
+ export declare const rgbToHex: (r: number, g: number, b: number) => string;
35
35
  /** WCAG bağıl parlaklık. Metin kontrastı bununla ölçülüyor. */
36
- export declare function parlaklik(hex: string): number;
36
+ export declare function luminance(hex: string): number;
37
37
  /** WCAG kontrast oranı. AA metin eşiği 4.5. */
38
- export declare function oran(a: string, b: string): number;
38
+ export declare function contrast(a: string, b: string): number;
39
39
  /**
40
40
  * CIE L* · algısal açıklık.
41
41
  *
42
42
  * İki YÜZEYİN ayrı okunup okunmadığı bununla ölçülüyor; kontrast oranı metin
43
43
  * içindir, yüzey için değil. Bir kartın kenarı sayfadan ΔL* ≥ 10 ayrı olmalı.
44
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;
45
+ export declare function lightness(hex: string): number;
46
+ export declare const deltaL: (a: string, b: string) => number;
47
+ export declare function hexToOklch(hex: string): Oklch;
48
48
  /**
49
49
  * OKLCH → hex, GAMUT DIŞINA TAŞMADAN.
50
50
  *
@@ -53,7 +53,7 @@ export declare function hexOklch(hex: string): Oklch;
53
53
  * doyum (C) ikili aramayla sığana kadar düşürülüyor; ton ve açıklık korunuyor,
54
54
  * yalnız canlılık gerektiği kadar azalıyor.
55
55
  */
56
- export declare function oklchHex({ l, c, h }: Oklch): string;
56
+ export declare function oklchToHex({ l, c, h }: Oklch): string;
57
57
  /**
58
58
  * Verilen ton ve doyumda, HEDEF ORANI tutturan açıklığı arar.
59
59
  *
@@ -64,5 +64,25 @@ export declare function oklchHex({ l, c, h }: Oklch): string;
64
64
  * `yon` "koyulaş" (-1) ya da "açıl" (+1): koyu temada aynı hedef ters yönden
65
65
  * yakalanıyor.
66
66
  */
67
- export declare function oranaGoreAcikligi(taban: Oklch, karsi: string, hedef: number, yon: -1 | 1): Oklch;
67
+ export declare function lightnessForContrast(taban: Oklch, karsi: string, hedef: number, yon: -1 | 1): Oklch;
68
+ /** @deprecated `isHex` kullan. 0.3.0'da kaldırılacak. */
69
+ export declare const gecerliHex: typeof isHex;
70
+ /** @deprecated `hexToRgb` kullan. 0.3.0'da kaldırılacak. */
71
+ export declare const hexRgb: typeof hexToRgb;
72
+ /** @deprecated `rgbToHex` kullan. 0.3.0'da kaldırılacak. */
73
+ export declare const rgbHex: typeof rgbToHex;
74
+ /** @deprecated `luminance` kullan. 0.3.0'da kaldırılacak. */
75
+ export declare const parlaklik: typeof luminance;
76
+ /** @deprecated `contrast` kullan. 0.3.0'da kaldırılacak. */
77
+ export declare const oran: typeof contrast;
78
+ /** @deprecated `lightness` kullan. 0.3.0'da kaldırılacak. */
79
+ export declare const acikligi: typeof lightness;
80
+ /** @deprecated `deltaL` kullan. 0.3.0'da kaldırılacak. */
81
+ export declare const dL: typeof deltaL;
82
+ /** @deprecated `hexToOklch` kullan. 0.3.0'da kaldırılacak. */
83
+ export declare const hexOklch: typeof hexToOklch;
84
+ /** @deprecated `oklchToHex` kullan. 0.3.0'da kaldırılacak. */
85
+ export declare const oklchHex: typeof oklchToHex;
86
+ /** @deprecated `lightnessForContrast` kullan. 0.3.0'da kaldırılacak. */
87
+ export declare const oranaGoreAcikligi: typeof lightnessForContrast;
68
88
  //# sourceMappingURL=color.d.ts.map
@@ -1 +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"}
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,KAAK,MAAO,MAAM,KAAG,OAA0D,CAAC;AAE7F;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM9D;AAGD,eAAO,MAAM,QAAQ,MAAO,MAAM,KAAK,MAAM,KAAK,MAAM,WACqB,CAAC;AAE9E,+DAA+D;AAC/D,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGrD;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C;AAED,eAAO,MAAM,MAAM,MAAO,MAAM,KAAK,MAAM,WAA0C,CAAC;AAItF,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAiB7C;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,KAAK,GAAG,MAAM,CA6BrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GACV,KAAK,CAQP;AAKD,yDAAyD;AACzD,eAAO,MAAM,UAAU,cAAQ,CAAC;AAChC,4DAA4D;AAC5D,eAAO,MAAM,MAAM,iBAAW,CAAC;AAC/B,4DAA4D;AAC5D,eAAO,MAAM,MAAM,iBAAW,CAAC;AAC/B,6DAA6D;AAC7D,eAAO,MAAM,SAAS,kBAAY,CAAC;AACnC,4DAA4D;AAC5D,eAAO,MAAM,IAAI,iBAAW,CAAC;AAC7B,6DAA6D;AAC7D,eAAO,MAAM,QAAQ,kBAAY,CAAC;AAClC,0DAA0D;AAC1D,eAAO,MAAM,EAAE,eAAS,CAAC;AACzB,8DAA8D;AAC9D,eAAO,MAAM,QAAQ,mBAAa,CAAC;AACnC,8DAA8D;AAC9D,eAAO,MAAM,QAAQ,mBAAa,CAAC;AACnC,wEAAwE;AACxE,eAAO,MAAM,iBAAiB,6BAAuB,CAAC"}
package/dist/lib/color.js CHANGED
@@ -15,7 +15,7 @@
15
15
  const srgbDoğrusal = (v) => (v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4);
16
16
  const doğrusalSrgb = (v) => (v <= 0.0031308 ? v * 12.92 : 1.055 * v ** (1 / 2.4) - 0.055);
17
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());
18
+ export const isHex = (v) => /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.test(v.trim());
19
19
  /**
20
20
  * Hex → RGB, GEÇERSİZ GİRDİDE FIRLATARAK.
21
21
  *
@@ -25,10 +25,10 @@ export const gecerliHex = (v) => /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.test(v.trim())
25
25
  * sebebi rengin kendisinde aranıyor.
26
26
  *
27
27
  * Kit KATI, çağıran toleranslı: yarım yazılmış bir kodun ne anlama geldiği
28
- * ekranın kararı (bkz. `gecerliHex`).
28
+ * ekranın kararı (bkz. `isHex`).
29
29
  */
30
- export function hexRgb(hex) {
31
- if (!gecerliHex(hex))
30
+ export function hexToRgb(hex) {
31
+ if (!isHex(hex))
32
32
  throw new Error(`Geçersiz hex: ${JSON.stringify(hex)}`);
33
33
  const s = hex.trim().replace("#", "");
34
34
  const t = s.length === 3 ? [...s].map((c) => c + c).join("") : s;
@@ -36,15 +36,15 @@ export function hexRgb(hex) {
36
36
  return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
37
37
  }
38
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("");
39
+ export const rgbToHex = (r, g, b) => "#" + [r, g, b].map((v) => kanal(v).toString(16).padStart(2, "0")).join("");
40
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));
41
+ export function luminance(hex) {
42
+ const [r, g, b] = hexToRgb(hex).map((v) => srgbDoğrusal(v / 255));
43
43
  return 0.2126 * r + 0.7152 * g + 0.0722 * b;
44
44
  }
45
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);
46
+ export function contrast(a, b) {
47
+ const [ust, alt] = [luminance(a), luminance(b)].sort((x, y) => y - x);
48
48
  return (ust + 0.05) / (alt + 0.05);
49
49
  }
50
50
  /**
@@ -53,14 +53,14 @@ export function oran(a, b) {
53
53
  * İki YÜZEYİN ayrı okunup okunmadığı bununla ölçülüyor; kontrast oranı metin
54
54
  * içindir, yüzey için değil. Bir kartın kenarı sayfadan ΔL* ≥ 10 ayrı olmalı.
55
55
  */
56
- export function acikligi(hex) {
57
- const y = parlaklik(hex);
56
+ export function lightness(hex) {
57
+ const y = luminance(hex);
58
58
  return y > 216 / 24389 ? 116 * Math.cbrt(y) - 16 : (y * 24389) / 27;
59
59
  }
60
- export const dL = (a, b) => Math.abs(acikligi(a) - acikligi(b));
60
+ export const deltaL = (a, b) => Math.abs(lightness(a) - lightness(b));
61
61
  /* ---- OKLab ---- */
62
- export function hexOklch(hex) {
63
- const [r8, g8, b8] = hexRgb(hex);
62
+ export function hexToOklch(hex) {
63
+ const [r8, g8, b8] = hexToRgb(hex);
64
64
  const r = srgbDoğrusal(r8 / 255);
65
65
  const g = srgbDoğrusal(g8 / 255);
66
66
  const b = srgbDoğrusal(b8 / 255);
@@ -82,7 +82,7 @@ export function hexOklch(hex) {
82
82
  * doyum (C) ikili aramayla sığana kadar düşürülüyor; ton ve açıklık korunuyor,
83
83
  * yalnız canlılık gerektiği kadar azalıyor.
84
84
  */
85
- export function oklchHex({ l, c, h }) {
85
+ export function oklchToHex({ l, c, h }) {
86
86
  const dene = (kroma) => {
87
87
  const hr = (h * Math.PI) / 180;
88
88
  const A = Math.cos(hr) * kroma;
@@ -110,7 +110,7 @@ export function oklchHex({ l, c, h }) {
110
110
  }
111
111
  rgb = dene(alt);
112
112
  }
113
- return rgbHex(...rgb);
113
+ return rgbToHex(...rgb);
114
114
  }
115
115
  /**
116
116
  * Verilen ton ve doyumda, HEDEF ORANI tutturan açıklığı arar.
@@ -122,13 +122,35 @@ export function oklchHex({ l, c, h }) {
122
122
  * `yon` "koyulaş" (-1) ya da "açıl" (+1): koyu temada aynı hedef ters yönden
123
123
  * yakalanıyor.
124
124
  */
125
- export function oranaGoreAcikligi(taban, karsi, hedef, yon) {
125
+ export function lightnessForContrast(taban, karsi, hedef, yon) {
126
126
  let en = { ...taban };
127
127
  for (let i = 0; i < 60; i++) {
128
128
  const aday = { ...taban, l: Math.max(0.02, Math.min(0.99, taban.l + yon * 0.01 * i)) };
129
129
  en = aday;
130
- if (oran(oklchHex(aday), karsi) >= hedef)
130
+ if (contrast(oklchToHex(aday), karsi) >= hedef)
131
131
  break;
132
132
  }
133
133
  return en;
134
134
  }
135
+ /* Eski Türkçe adlar, 0.3.0'a kadar. SİLME: 0.1.1 npm'de yayında ve bu adları
136
+ kullanan bir tüketici var. Gerekçe: ADR-0001. */
137
+ /** @deprecated `isHex` kullan. 0.3.0'da kaldırılacak. */
138
+ export const gecerliHex = isHex;
139
+ /** @deprecated `hexToRgb` kullan. 0.3.0'da kaldırılacak. */
140
+ export const hexRgb = hexToRgb;
141
+ /** @deprecated `rgbToHex` kullan. 0.3.0'da kaldırılacak. */
142
+ export const rgbHex = rgbToHex;
143
+ /** @deprecated `luminance` kullan. 0.3.0'da kaldırılacak. */
144
+ export const parlaklik = luminance;
145
+ /** @deprecated `contrast` kullan. 0.3.0'da kaldırılacak. */
146
+ export const oran = contrast;
147
+ /** @deprecated `lightness` kullan. 0.3.0'da kaldırılacak. */
148
+ export const acikligi = lightness;
149
+ /** @deprecated `deltaL` kullan. 0.3.0'da kaldırılacak. */
150
+ export const dL = deltaL;
151
+ /** @deprecated `hexToOklch` kullan. 0.3.0'da kaldırılacak. */
152
+ export const hexOklch = hexToOklch;
153
+ /** @deprecated `oklchToHex` kullan. 0.3.0'da kaldırılacak. */
154
+ export const oklchHex = oklchToHex;
155
+ /** @deprecated `lightnessForContrast` kullan. 0.3.0'da kaldırılacak. */
156
+ export const oranaGoreAcikligi = lightnessForContrast;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Turning an uploaded file into something a panel can carry.
3
+ *
4
+ * NO LIBRARY, and none is needed: a `<canvas>` and `drawImage`.
5
+ *
6
+ * A DATA URI, NOT AN OBJECT URL. `URL.createObjectURL` dies with the tab, so a
7
+ * logo chosen today would be gone tomorrow. A data URI survives in storage and
8
+ * goes straight into `<img src>`. When a server arrives this file becomes an
9
+ * upload call and nothing else changes: screens already hold a STRING and do
10
+ * not care whether it is a data URI or an `https://` address.
11
+ *
12
+ * WHY IT IS RESIZED. `localStorage` holds about 5 MB per browser and a phone
13
+ * photo alone is 4 MB. Writing one unresized throws `QuotaExceeded`, and the
14
+ * thing that gets lost may not be the logo but whatever else was being saved
15
+ * at that moment.
16
+ *
17
+ * THE RATIO IS KEPT, NOTHING IS CROPPED. Cropping to fit a square is the most
18
+ * common and most silent mistake: the logo looks fine and its edge is gone.
19
+ * The long side is pulled to the limit, the short side follows.
20
+ *
21
+ * PNG, NOT JPEG. Logos are flat and transparent; JPEG turns transparency into
22
+ * solid black and rings the edges.
23
+ */
24
+ export type ImageError = "type" | "size" | "unreadable";
25
+ export declare const IMAGE_ACCEPT = "image/png,image/jpeg,image/svg+xml,image/webp";
26
+ /**
27
+ * Resizes so the longest side is `maxEdge` pixels and returns a data URI.
28
+ *
29
+ * SVG PASSES THROUGH UNTOUCHED. Drawing a vector onto a canvas and writing PNG
30
+ * stops it being scalable: a logo baked at 512px is blurry on a 4K screen. SVG
31
+ * is already small and already sharp at every size.
32
+ */
33
+ export declare function prepareImage(file: File, maxEdge: number): Promise<string>;
34
+ /**
35
+ * Cuts a SQUARE piece out of an image: for a mark or a profile photo.
36
+ *
37
+ * `area` is given in RATIOS (0 to 1), not in the image's own pixels, because
38
+ * the picker runs on a preview whose scale changes from screen to screen. A
39
+ * ratio points at the same place at every scale.
40
+ */
41
+ export declare function cropSquare(source: string, area: {
42
+ x: number;
43
+ y: number;
44
+ size: number;
45
+ }, maxEdge: number): Promise<string>;
46
+ //# sourceMappingURL=image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image.d.ts","sourceRoot":"","sources":["../../src/lib/image.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,YAAY,CAAC;AAKxD,eAAO,MAAM,YAAY,kDAAkD,CAAC;AAE5E;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAoB/E;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC,CAcjB"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Turning an uploaded file into something a panel can carry.
3
+ *
4
+ * NO LIBRARY, and none is needed: a `<canvas>` and `drawImage`.
5
+ *
6
+ * A DATA URI, NOT AN OBJECT URL. `URL.createObjectURL` dies with the tab, so a
7
+ * logo chosen today would be gone tomorrow. A data URI survives in storage and
8
+ * goes straight into `<img src>`. When a server arrives this file becomes an
9
+ * upload call and nothing else changes: screens already hold a STRING and do
10
+ * not care whether it is a data URI or an `https://` address.
11
+ *
12
+ * WHY IT IS RESIZED. `localStorage` holds about 5 MB per browser and a phone
13
+ * photo alone is 4 MB. Writing one unresized throws `QuotaExceeded`, and the
14
+ * thing that gets lost may not be the logo but whatever else was being saved
15
+ * at that moment.
16
+ *
17
+ * THE RATIO IS KEPT, NOTHING IS CROPPED. Cropping to fit a square is the most
18
+ * common and most silent mistake: the logo looks fine and its edge is gone.
19
+ * The long side is pulled to the limit, the short side follows.
20
+ *
21
+ * PNG, NOT JPEG. Logos are flat and transparent; JPEG turns transparency into
22
+ * solid black and rings the edges.
23
+ */
24
+ /** Raw file limit, before resizing. Over 8 MB is not a logo, it is an accident. */
25
+ const RAW_LIMIT = 8 * 1024 * 1024;
26
+ export const IMAGE_ACCEPT = "image/png,image/jpeg,image/svg+xml,image/webp";
27
+ /**
28
+ * Resizes so the longest side is `maxEdge` pixels and returns a data URI.
29
+ *
30
+ * SVG PASSES THROUGH UNTOUCHED. Drawing a vector onto a canvas and writing PNG
31
+ * stops it being scalable: a logo baked at 512px is blurry on a 4K screen. SVG
32
+ * is already small and already sharp at every size.
33
+ */
34
+ export async function prepareImage(file, maxEdge) {
35
+ if (!file.type.startsWith("image/"))
36
+ throw new Error("type");
37
+ if (file.size > RAW_LIMIT)
38
+ throw new Error("size");
39
+ const raw = await readFile(file);
40
+ if (file.type === "image/svg+xml")
41
+ return raw;
42
+ const image = await loadImage(raw);
43
+ const scale = Math.min(1, maxEdge / Math.max(image.width, image.height));
44
+ if (scale >= 1)
45
+ return raw;
46
+ const canvas = document.createElement("canvas");
47
+ canvas.width = Math.round(image.width * scale);
48
+ canvas.height = Math.round(image.height * scale);
49
+ const ctx = canvas.getContext("2d");
50
+ if (!ctx)
51
+ return raw;
52
+ /* The browser's own smoothing: better than a hand-written resampler, and free. */
53
+ ctx.imageSmoothingQuality = "high";
54
+ ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
55
+ return canvas.toDataURL("image/png");
56
+ }
57
+ /**
58
+ * Cuts a SQUARE piece out of an image: for a mark or a profile photo.
59
+ *
60
+ * `area` is given in RATIOS (0 to 1), not in the image's own pixels, because
61
+ * the picker runs on a preview whose scale changes from screen to screen. A
62
+ * ratio points at the same place at every scale.
63
+ */
64
+ export async function cropSquare(source, area, maxEdge) {
65
+ const image = await loadImage(source);
66
+ /* The square is measured against the SHORT side: a 350x65 logo can hold a
67
+ square of at most 65px. Measured against the long side the frame would
68
+ fall outside the image. */
69
+ const edge = Math.min(image.width, image.height) * area.size;
70
+ const canvas = document.createElement("canvas");
71
+ canvas.width = maxEdge;
72
+ canvas.height = maxEdge;
73
+ const ctx = canvas.getContext("2d");
74
+ if (!ctx)
75
+ return source;
76
+ ctx.imageSmoothingQuality = "high";
77
+ ctx.drawImage(image, area.x * image.width, area.y * image.height, edge, edge, 0, 0, maxEdge, maxEdge);
78
+ return canvas.toDataURL("image/png");
79
+ }
80
+ function readFile(file) {
81
+ return new Promise((resolve, reject) => {
82
+ const reader = new FileReader();
83
+ reader.onload = () => resolve(String(reader.result));
84
+ reader.onerror = () => reject(new Error("unreadable"));
85
+ reader.readAsDataURL(file);
86
+ });
87
+ }
88
+ function loadImage(src) {
89
+ return new Promise((resolve, reject) => {
90
+ const img = new Image();
91
+ img.onload = () => resolve(img);
92
+ img.onerror = () => reject(new Error("unreadable"));
93
+ img.src = src;
94
+ });
95
+ }