@ahmetilhn/hanui 4.1.0 → 5.3.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.
- package/README.md +260 -40
- package/build/charts.cjs +2 -0
- package/build/charts.cjs.map +1 -0
- package/build/charts.css +1 -0
- package/build/charts.js +1843 -0
- package/build/charts.js.map +1 -0
- package/build/chat.cjs +3 -0
- package/build/chat.cjs.map +1 -0
- package/build/chat.css +1 -0
- package/build/chat.js +707 -0
- package/build/chat.js.map +1 -0
- package/build/index.cjs +7 -7
- package/build/index.cjs.map +1 -1
- package/build/index.d.ts +473 -223
- package/build/index.js +3336 -3096
- package/build/index.js.map +1 -1
- package/build/scss/_colors.generated.scss +119 -0
- package/build/scss/_index.scss +6 -0
- package/build/scss/_metrics.generated.scss +49 -0
- package/build/scss/_mixins.scss +675 -0
- package/build/scss/_variables.scss +51 -0
- package/build/styles.css +1 -1
- package/build/types/charts/AreaChart/index.d.ts +14 -0
- package/build/types/charts/BarChart/index.d.ts +16 -0
- package/build/types/charts/BoxPlot/index.d.ts +43 -0
- package/build/types/charts/ComposedChart/index.d.ts +16 -0
- package/build/types/charts/Heatmap/index.d.ts +30 -0
- package/build/types/charts/Histogram/index.d.ts +29 -0
- package/build/types/charts/LineChart/index.d.ts +14 -0
- package/build/types/charts/PieChart/index.d.ts +36 -0
- package/build/types/charts/RadarChart/index.d.ts +40 -0
- package/build/types/charts/ScatterPlot/index.d.ts +41 -0
- package/build/types/charts/core/CartesianChart.d.ts +43 -0
- package/build/types/charts/core/ChartFrame.d.ts +55 -0
- package/build/types/charts/core/axes.d.ts +34 -0
- package/build/types/charts/core/cartesian.d.ts +79 -0
- package/build/types/charts/core/format.d.ts +9 -0
- package/build/types/charts/core/margins.d.ts +9 -0
- package/build/types/charts/core/palette.d.ts +13 -0
- package/build/types/charts/core/path.d.ts +24 -0
- package/build/types/charts/core/scale.d.ts +40 -0
- package/build/types/charts/core/series.d.ts +11 -0
- package/build/types/charts/core/spatial.d.ts +12 -0
- package/build/types/charts/core/stats.d.ts +34 -0
- package/build/types/charts/core/types.d.ts +31 -0
- package/build/types/charts/core/useChartWidth.d.ts +7 -0
- package/build/types/charts/index.d.ts +21 -0
- package/build/types/chat/ActionList/index.d.ts +46 -0
- package/build/types/chat/AppBar/index.d.ts +21 -0
- package/build/types/chat/ChatMessage/index.d.ts +24 -0
- package/build/types/chat/ChatThread/index.d.ts +24 -0
- package/build/types/chat/Citation/index.d.ts +15 -0
- package/build/types/chat/CodeBlock/index.d.ts +27 -0
- package/build/types/chat/DescriptionList/index.d.ts +16 -0
- package/build/types/chat/Legend/index.d.ts +20 -0
- package/build/types/chat/MessageActions/index.d.ts +21 -0
- package/build/types/chat/PromptInput/index.d.ts +47 -0
- package/build/types/chat/PromptSuggestions/index.d.ts +25 -0
- package/build/types/chat/Prose/index.d.ts +15 -0
- package/build/types/chat/ReasoningBlock/index.d.ts +24 -0
- package/build/types/chat/ReasoningText/index.d.ts +14 -0
- package/build/types/chat/SegmentBar/index.d.ts +46 -0
- package/build/types/chat/SourceList/index.d.ts +25 -0
- package/build/types/chat/TerminalOutput/index.d.ts +25 -0
- package/build/types/chat/ToolCall/index.d.ts +41 -0
- package/build/types/chat/index.d.ts +26 -0
- package/build/types/helpers/class-name.helper.d.ts +3 -0
- package/build/types/helpers/component.helper.d.ts +13 -0
- package/build/types/helpers/label.helper.d.ts +12 -0
- package/build/types/theme/palette.d.ts +203 -0
- package/build/types/theme/tokens.d.ts +208 -0
- package/build/types/types/common-element-props.type.d.ts +8 -0
- package/build/types/types/link.type.d.ts +14 -0
- package/build/types/types/theme.type.d.ts +223 -0
- package/package.json +19 -2
package/README.md
CHANGED
|
@@ -12,6 +12,10 @@ kurulu; tek çalışma zamanı bağımlılığı ikon seti (`react-bootstrap-ico
|
|
|
12
12
|
- **Yerel öğeler korunur.** `<dialog>`, `<input type="range">`,
|
|
13
13
|
`<input type="radio">` — odak tuzağı, klavye gezinmesi ve ekran okuyucu
|
|
14
14
|
duyurusu tarayıcıdan gelir.
|
|
15
|
+
- **Üç alt giriş, ana pakete sıfır bayt.** `@ahmetilhn/hanui/chat` (sohbet ve
|
|
16
|
+
araç arayüzleri), `@ahmetilhn/hanui/charts` (bağımlılıksız SVG grafikleri),
|
|
17
|
+
`@ahmetilhn/hanui/scss` (token değişkenleri ve mixin'ler). Kullanmayan uygulama
|
|
18
|
+
onları indirmez.
|
|
15
19
|
|
|
16
20
|
```bash
|
|
17
21
|
npm install @ahmetilhn/hanui @ahmetilhn/handy-utils react-bootstrap-icons
|
|
@@ -57,20 +61,24 @@ Sağlayıcı **zorunlu değil**: paket kurulup hiçbir yapılandırma yapılmada
|
|
|
57
61
|
Öznitelik yoksa `prefers-color-scheme` yedeği devreye girer — ama kullanıcının
|
|
58
62
|
**açık bir seçimi** varsa sistem tercihi onu ezmez.
|
|
59
63
|
|
|
60
|
-
### İlk boyamadan önce yazın
|
|
64
|
+
### İlk boyamadan önce yazın — `HanuiThemeScript`
|
|
61
65
|
|
|
62
66
|
```tsx
|
|
63
|
-
// app/layout.tsx — <head> içine.
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
/>
|
|
67
|
+
// app/layout.tsx — sunucu düzeni, <head> içine.
|
|
68
|
+
import { HanuiThemeScript } from '@ahmetilhn/hanui';
|
|
69
|
+
|
|
70
|
+
<head>
|
|
71
|
+
<HanuiThemeScript storageKey="theme" />
|
|
72
|
+
</head>;
|
|
70
73
|
```
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
Kayıtlı açık seçimi (`light` / `dark`) `<html data-hanui-theme>`e yazar; kayıt
|
|
76
|
+
yoksa sistem tercihi izlenir. Satır içi betik HTML ayrıştırılırken çalışır.
|
|
77
|
+
|
|
78
|
+
Bu iş sağlayıcıya bırakılamaz: sağlayıcı ağaç monte olduktan sonra çalışıyor ve
|
|
79
|
+
koyu tema seçmiş kullanıcı o ana kadar **bir kare beyaz ekran** görüyor.
|
|
80
|
+
⚠ Bir **bileşen**, fonksiyon değil: paket `'use client'` taşıdığı için dışa
|
|
81
|
+
verilen düz bir fonksiyon Next'in sunucu düzeninde çağrılamıyor.
|
|
74
82
|
|
|
75
83
|
### Token'ları ezmek
|
|
76
84
|
|
|
@@ -80,8 +88,8 @@ Yalnızca değiştirdiğiniz token'ı verin; gerisi varsayılanında kalır.
|
|
|
80
88
|
import { HanuiProvider } from '@ahmetilhn/hanui';
|
|
81
89
|
|
|
82
90
|
const THEME = {
|
|
83
|
-
light: {
|
|
84
|
-
dark: {
|
|
91
|
+
light: { link: '#0a58ca', 'ring-color': '#0d6efd' },
|
|
92
|
+
dark: { link: '#6ea8fe' },
|
|
85
93
|
fonts: { heading: 'Archivo, sans-serif', body: 'Inter, sans-serif' },
|
|
86
94
|
// Ölçüler tema başına DEĞİL: bir markanın yuvarlaklığı açık temada
|
|
87
95
|
// 12 px, koyu temada 8 px olmaz.
|
|
@@ -336,21 +344,27 @@ büyür, bir duyuru şeridi çıkıp kaybolduğunda değişir.
|
|
|
336
344
|
|
|
337
345
|
## Bileşen kataloğu
|
|
338
346
|
|
|
339
|
-
| Grup
|
|
340
|
-
|
|
|
341
|
-
| Eylem
|
|
342
|
-
| Seçim
|
|
343
|
-
| Girdi
|
|
344
|
-
| Yüzey
|
|
345
|
-
| Geri bild. | `Alert` · `Badge` · `CodeBadge` · `EmptyState` · `Skeleton` · `Spinner` · `Divider` · `Avatar` · `Rating` · `Price` · `CopyField` · `Breadcrumb`
|
|
346
|
-
| Kipsel
|
|
347
|
-
| Veri
|
|
347
|
+
| Grup | Bileşenler |
|
|
348
|
+
| --- | --- |
|
|
349
|
+
| Eylem | `Button` · `IconButton` · `TextLink` · `Tooltip` · `Menu` · `Popover` |
|
|
350
|
+
| Seçim | `Chip` · `ChipGroup` · `SegmentedControl` · `Select` · `Combobox` · `Checkbox` · `Switch` · `Radio` · `RadioCard` · `RangeSlider` · `RatingInput` · `QuantityStepper` · `TableCheckbox` |
|
|
351
|
+
| Girdi | `Input` · `PasswordInput` · `Textarea` · `TagInput` · `DateField` · `FileUpload` · `Field` |
|
|
352
|
+
| Yüzey | `Card` (+ `CardMedia`, `CardOverlay`, `CardBody`, `CardFooter`) · `SummaryCard` · `Panel` (+ `PanelForm`, `PanelRow`) · `PageHeader` · `SectionHeader` · `Tile` · `Directory` (+ `DirectoryGroup`, `DirectoryRow`, `DirectoryJump`) · `Carousel` · `ScrollArea` · `Disclosure` · `Accordion` · `Tabs` |
|
|
353
|
+
| Geri bild. | `Alert` · `Badge` · `StatusDot` · `CodeBadge` · `Kbd` · `EmptyState` · `Skeleton` (+ `SkeletonCard`, `SkeletonRows`, `SkeletonTable`) · `Spinner` · `Progress` · `Steps` · `Divider` · `Avatar` · `Rating` · `Price` · `Stat` · `CopyField` · `Breadcrumb` · `ToastHub` (+ `ToastPortal`) |
|
|
354
|
+
| Kipsel | `Modal` · `Drawer` · `BottomSheet` · `ConfirmDialog` · `PromptDialog` · `CommandPalette` |
|
|
355
|
+
| Veri | `Table` (+ `TableScroller`) · `DataTable` (+ `DataTableRow`) · `FilterBar` (+ `FilterBarField`) · `Pagination` · `Timeline` |
|
|
356
|
+
| Tema ve kancalar | `HanuiProvider` · `HanuiThemeScript` · `initHanui` · `useHanui` · `useHanuiTheme` · `useHanuiTokens` · `useAnnounce` · `useStickToBottom` · `usePositioning` · `useVirtualList` · `useListboxNavigation` · `hasOpenSurface` |
|
|
357
|
+
| Sohbet — `/chat` | `ChatThread` · `ChatMessage` · `PromptInput` · `PromptSuggestions` · `Prose` · `CodeBlock` · `ReasoningBlock` (+ `ReasoningText`) · `ToolCall` (+ `ToolCallSection`) · `TerminalOutput` · `SourceList` · `Citation` · `MessageActions` · `AppBar` · `ActionList` (+ `ActionListItem`) · `SegmentBar` · `Legend` · `DescriptionList` |
|
|
358
|
+
| Grafik — `/charts` | `LineChart` · `AreaChart` · `BarChart` · `ComposedChart` · `PieChart` · `ScatterPlot` · `Heatmap` · `BoxPlot` · `Histogram` · `RadarChart` |
|
|
359
|
+
|
|
360
|
+
Alt girişlerin stilleri ayrı dosyada ve `styles.css`ten **sonra** içe aktarılır:
|
|
361
|
+
`@ahmetilhn/hanui/chat.css`, `@ahmetilhn/hanui/charts.css`.
|
|
348
362
|
|
|
349
363
|
### Seçenek sayısı öğeyi belirler
|
|
350
364
|
|
|
351
365
|
| Seçenek sayısı | Öğe |
|
|
352
366
|
| -------------- | ----------------------------------------------- |
|
|
353
|
-
|
|
|
367
|
+
| ≤7 | `ChipGroup` — hepsi ekranda, tek dokunuş |
|
|
354
368
|
| 5–20 | `Select` — aramasız liste; mobilde alt sayfa |
|
|
355
369
|
| 20+ | `Combobox` — yazarak ara |
|
|
356
370
|
| Aralık | `RangeSlider` (+ kesin değer için sayı girdisi) |
|
|
@@ -363,14 +377,20 @@ da 3 seçeneği de aynı biçimde göstermek, ikisini de yanlış gösterir.
|
|
|
363
377
|
|
|
364
378
|
## Sistemin taşıdığı kararlar
|
|
365
379
|
|
|
380
|
+
**Zemin mürekkep ve kâğıt, yeşil eylemdir.** Nötrler sıcak mürekkep ekseninde
|
|
381
|
+
(açık sayfa `#faf9f5`, koyu sayfa `#141413`); markanın yeşili yalnızca birincil
|
|
382
|
+
eylemde, bağlantıda, odak halkasında ve marka işaretinde. Seçim — etkin sayfa,
|
|
383
|
+
seçili çip, sekme çizgisi, ilerleme, onay kutusu, anahtar — mürekkeptir.
|
|
384
|
+
Yeşilin yayılmasını `green-footprint.test.ts` derleme hatasına çevirir.
|
|
385
|
+
|
|
366
386
|
**Doygun dolgu = tıklanabilir.** Durum etiketleri **her zaman** tint zeminli
|
|
367
387
|
(`Badge`, `Alert`), eylemler **her zaman** dolgulu veya çerçeveli. Bu ayrım
|
|
368
388
|
bozulduğunda kullanıcı durum etiketine tıklamayı deniyor. `Badge`in `solid`
|
|
369
389
|
varyantı durum tonlarında bilinçli olarak `soft` ile aynı şeyi verir.
|
|
370
390
|
|
|
371
391
|
**Bir ekranda tek `PRIMARY`.** `UIVariant` bir vurgu hiyerarşisi: iki dolu düğme
|
|
372
|
-
yan yana durduğunda hiçbiri öne çıkmaz. `UIVariant.CART` ekrandaki
|
|
373
|
-
|
|
392
|
+
yan yana durduğunda hiçbiri öne çıkmaz. `UIVariant.CART` ekrandaki en parlak
|
|
393
|
+
yeşil — dönüşüm eylemi; birincil eylemden (koyu çam) aydınlıkla ayrışır.
|
|
374
394
|
|
|
375
395
|
**Renk tek başına anlam taşımaz** (WCAG 1.4.1). Her durum bir metin, ikon veya
|
|
376
396
|
işaretle de bildirilir: `Alert`in her tonunun kendi ikonu var, `Field`in zorunlu
|
|
@@ -407,7 +427,8 @@ benzemiyor. Bedeli (odak yönetimi, ok tuşları, `aria-activedescendant`) bir k
|
|
|
407
427
|
**Dokunma hedefi en az 44×44 px** (WCAG 2.5.8). Görsel kutu daha küçük olabilir;
|
|
408
428
|
tıklanabilir alan görünmez bir örtüyle korunur.
|
|
409
429
|
|
|
410
|
-
**
|
|
430
|
+
**Geçişler 200 ms'yi geçmez** — tek istisna dipten açılan panel
|
|
431
|
+
(`duration-slow`, 320 ms) — ve `prefers-reduced-motion` her animasyonda
|
|
411
432
|
karşılanır.
|
|
412
433
|
|
|
413
434
|
**Odak halkası `:focus-visible` ile.** `:focus` fareyle tıklandığında da halka
|
|
@@ -421,12 +442,30 @@ Paket `'use client'` sınırını **kendi içinde** çizer: sunucu bileşenlerin
|
|
|
421
442
|
doğrudan import edilebilir, `children` sunucuda çizilip aktarılır.
|
|
422
443
|
|
|
423
444
|
```tsx
|
|
424
|
-
// app/layout.tsx
|
|
445
|
+
// app/layout.tsx — sunucu bileşeni
|
|
425
446
|
import '@ahmetilhn/hanui/styles.css';
|
|
426
|
-
import
|
|
447
|
+
import '@ahmetilhn/hanui/chat.css'; // yalnızca /chat kullanılıyorsa
|
|
448
|
+
import '@ahmetilhn/hanui/charts.css'; // yalnızca /charts kullanılıyorsa
|
|
449
|
+
import { HanuiProvider, HanuiThemeScript } from '@ahmetilhn/hanui';
|
|
427
450
|
import NextLink from 'next/link';
|
|
451
|
+
|
|
452
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
453
|
+
return (
|
|
454
|
+
<html lang="tr" suppressHydrationWarning>
|
|
455
|
+
<head>
|
|
456
|
+
<HanuiThemeScript storageKey="theme" />
|
|
457
|
+
</head>
|
|
458
|
+
<body>
|
|
459
|
+
<HanuiProvider linkComponent={NextLink}>{children}</HanuiProvider>
|
|
460
|
+
</body>
|
|
461
|
+
</html>
|
|
462
|
+
);
|
|
463
|
+
}
|
|
428
464
|
```
|
|
429
465
|
|
|
466
|
+
`suppressHydrationWarning`: tema betiği `<html>`e sunucunun yazmadığı bir
|
|
467
|
+
öznitelik ekliyor; uyarı yalnızca o öğe için susturulur.
|
|
468
|
+
|
|
430
469
|
---
|
|
431
470
|
|
|
432
471
|
## Geliştirme
|
|
@@ -441,13 +480,14 @@ npm run playground # bileşen galerisi → http://localhost:5273
|
|
|
441
480
|
| Komut | |
|
|
442
481
|
| ------------------------- | --------------------------------------------------------------- |
|
|
443
482
|
| `npm run tokens` | SCSS token dosyalarını `theme/tokens.ts`ten üretir |
|
|
444
|
-
| `npm run build` | `build/` (ESM + CJS + `.d.ts` + `
|
|
483
|
+
| `npm run build` | `build/` — ana giriş + `chat` + `charts` (ESM + CJS + `.d.ts` + CSS) ve `build/scss/` |
|
|
445
484
|
| `npm run test` | Jest + Testing Library + `jest-axe` |
|
|
446
|
-
| `npm run test:coverage` | kapsam kapısı — `
|
|
485
|
+
| `npm run test:coverage` | kapsam kapısı — tüm `src/`: satır 89 · ifade 86 · fonksiyon 80 · dal 75 |
|
|
447
486
|
| `npm run test:visual` | görsel regresyon (Playwright); `verify` İÇİNDE DEĞİL, aşağı bkz. |
|
|
448
487
|
| `npm run test:device` | iOS (WebKit) + Android (Chromium) davranış nöbetçileri, aşağı bkz. |
|
|
449
|
-
| `npm run check:contrast` | WCAG kontrast ölçümü, iki temada
|
|
450
|
-
| `npm run check:
|
|
488
|
+
| `npm run check:contrast` | WCAG kontrast ölçümü, iki temada 210 çift |
|
|
489
|
+
| `npm run check:palette` | palet tarifinin çıktısı mı + nötr chroma tavanı + tint ve kategori ayrışması |
|
|
490
|
+
| `npm run check:api` | genel API nöbetçisi — dört giriş, dört taban çizgisi (ana 176 · sohbet 30 · grafik 22 · SCSS 252 ad) |
|
|
451
491
|
| `npm run size` | paket boyutu bütçesi (`size-limit`) |
|
|
452
492
|
| `npm run playground` | bileşen galerisi (tema · RTL · yoğunluk anahtarı) |
|
|
453
493
|
| `npm run lint` | ESLint (TS) + stylelint (SCSS) |
|
|
@@ -465,19 +505,32 @@ npm run playground # bileşen galerisi → http://localhost:5273
|
|
|
465
505
|
- **Token sözleşmesi** — açık/koyu anahtar kümeleri ve üretilmiş SCSS kaynakla
|
|
466
506
|
eşleşir. Ayrışma bugüne kadar sessizdi.
|
|
467
507
|
- **Paket boyutu** — tek bileşen import eden bir uygulamanın ne indirdiği
|
|
468
|
-
ölçülür. Ölçülen (2026-
|
|
469
|
-
`styles.css` **
|
|
470
|
-
|
|
508
|
+
ölçülür. Ölçülen (2026-10-10, `size-limit`): `Badge` **4,33 kB** · `Button`
|
|
509
|
+
**5,12 kB** · `styles.css` **23,07 kB** · tüm paket **42,05 kB** gzip. Alt
|
|
510
|
+
girişler ana pakette SAYILMAZ: sohbet **6,32 kB**, grafikler **14,02 kB**
|
|
511
|
+
(yalnızca `LineChart` **7,19 kB**).
|
|
512
|
+
⚠ **Bütçeler `.size-limit.js`te** (paket 43 kB, `styles.css` 24 kB) ve
|
|
513
|
+
başlıkta kalan pay dar. Bu satır bir dönem
|
|
471
514
|
`Badge 2,7 / Button 3,4 / paket 22,2` diyordu — ölçüm değil, bayat bir
|
|
472
515
|
kopyaydı ve okuyana **%70 boş alan** olduğunu düşündürüyordu. Yeni bir
|
|
473
516
|
bileşen eklerken bütçenin fiilen dolu olduğu bilinerek girilir; `size-limit`
|
|
474
517
|
kırmızıya döndüğünde doğru tepki limiti yükseltmek değil, ne eklendiğini
|
|
475
518
|
ölçmektir (`npm run size`).
|
|
476
|
-
- **Genel API** —
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
519
|
+
- **Genel API** — her girişin dışa aktarım kümesi kendi taban çizgisiyle
|
|
520
|
+
karşılaştırılır (`npm run check:api`): ana giriş `scripts/api-baseline.txt`
|
|
521
|
+
(176), `chat` (30), `charts` (22), `scss` (252 `$değişken` + `@mixin`). Düşen
|
|
522
|
+
bir ad **kırıcı**dır ve tüketiciler caret ile aldığı için bir sonraki
|
|
523
|
+
`npm install`da derleme hatası olarak çıkar. Bilinçli değişiklikte
|
|
524
|
+
`node scripts/check-api.mjs --update` + CLAUDE.md'ye gerekçe.
|
|
525
|
+
- **Alt giriş sınırı** — `chat` ve `charts` ana girişi yalnızca PAKET ADIYLA
|
|
526
|
+
alır (`subentry-boundary.test.ts`); göreli bir yol `HanuiProvider` bağlamının
|
|
527
|
+
ve kipsel yüzey yığınının ikinci bir kopyasını paketlerdi.
|
|
528
|
+
- **Yeşil ayak izi** — bileşen SCSS'inde yeşil token ailesine uzanan her
|
|
529
|
+
bileşen gerekçeli bir izin listesinde (`green-footprint.test.ts`).
|
|
530
|
+
- **Opacity ile soluklaştırma yasak** — `0`/`1` dışındaki her `opacity`
|
|
531
|
+
derlemeyi kırar (`passive-opacity.test.ts`); pasiflik token'larla çizilir.
|
|
532
|
+
- **iOS yakınlaştırması** — galerideki her metin girdisi dar ekranda ≥16px
|
|
533
|
+
(`e2e/mobile.spec.ts`, hesaplanmış stil).
|
|
481
534
|
- **Odak halkası ve hareket ölçeği** — stylelint, `focus-ring` mixin'i dışında
|
|
482
535
|
`outline` ve bileşen SCSS'inde ham süre değeri (`0.7s`) yazılmasını
|
|
483
536
|
engelliyor. Üç bileşen kendi halkasını, iki bileşen kendi süresini
|
|
@@ -525,17 +578,184 @@ yol, Playwright'ın resmi konteynerinde koşup `linux` referanslarını orada
|
|
|
525
578
|
> `=all` mod, pikseli değişen her dosyayı yazar (bayt bayt aynı olanlara
|
|
526
579
|
> dokunmaz, o yüzden dosya sayısı toplamdan az çıkabilir). Doğrulama:
|
|
527
580
|
> yenilemeden sonra bir referansın baskın renklerini örnekleyin.
|
|
581
|
+
> ⚠ `=changed` de yetmez: yalnızca eşiği (`maxDiffPixelRatio: 0.002`) aşan
|
|
582
|
+
> farkı yazar — iki küçük yazının kalktığı bir değişiklik eşiğin altında kalıp
|
|
583
|
+
> eski referans dosyada durur. Küçük bir değişiklikte bölümün referansını silip
|
|
584
|
+
> `=missing` ile yazdırın.
|
|
528
585
|
|
|
529
586
|
`master`a her push `npm publish` çalıştırır — **`package.json` sürümünü
|
|
530
587
|
yükseltmeyi unutmayın**, aynı sürüm ikinci kez yayımlanamaz ve iş akışı kırmızı
|
|
531
588
|
döner.
|
|
532
589
|
|
|
590
|
+
## Sohbet bileşenleri — `@ahmetilhn/hanui/chat`
|
|
591
|
+
|
|
592
|
+
Sohbet ve araç arayüzleri için ayrı bir giriş; ana paketi ve `styles.css`i
|
|
593
|
+
büyütmez.
|
|
594
|
+
|
|
595
|
+
```tsx
|
|
596
|
+
import '@ahmetilhn/hanui/styles.css';
|
|
597
|
+
import '@ahmetilhn/hanui/chat.css'; // styles.css'TEN SONRA
|
|
598
|
+
|
|
599
|
+
import { HanuiProvider } from '@ahmetilhn/hanui';
|
|
600
|
+
import { ChatMessage, ChatThread, PromptInput } from '@ahmetilhn/hanui/chat';
|
|
601
|
+
|
|
602
|
+
<ChatThread
|
|
603
|
+
isStreaming={isStreaming}
|
|
604
|
+
dock={
|
|
605
|
+
<PromptInput
|
|
606
|
+
value={draft}
|
|
607
|
+
onChange={setDraft}
|
|
608
|
+
onSubmit={send}
|
|
609
|
+
onStop={stop}
|
|
610
|
+
isBusy={isStreaming}
|
|
611
|
+
placeholder="Mesajınızı yazın…"
|
|
612
|
+
/>
|
|
613
|
+
}
|
|
614
|
+
>
|
|
615
|
+
{messages.map(message => (
|
|
616
|
+
<ChatMessage key={message.id} author={message.author}>
|
|
617
|
+
{message.content}
|
|
618
|
+
</ChatMessage>
|
|
619
|
+
))}
|
|
620
|
+
</ChatThread>;
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
Metinler aynı sağlayıcıdan, `labels.chat` altında:
|
|
624
|
+
|
|
625
|
+
```tsx
|
|
626
|
+
<HanuiProvider
|
|
627
|
+
labels={{
|
|
628
|
+
chat: {
|
|
629
|
+
thread: 'Sohbet',
|
|
630
|
+
send: 'Gönder',
|
|
631
|
+
stop: 'Durdur',
|
|
632
|
+
scrollToLatest: 'En yeniye in',
|
|
633
|
+
replyReady: 'Yanıt hazır',
|
|
634
|
+
messageActions: 'Mesaj eylemleri',
|
|
635
|
+
sources: 'Kaynaklar',
|
|
636
|
+
citation: index => `Kaynak ${index}`,
|
|
637
|
+
stderr: 'hata çıktısı',
|
|
638
|
+
toolStatus: { running: 'çalışıyor', ok: 'tamamlandı', error: 'hata', aborted: 'durduruldu', interrupted: 'kesildi' },
|
|
639
|
+
codeCopy: language => `${language} kodunu kopyala`,
|
|
640
|
+
codeCopied: 'Kod kopyalandı',
|
|
641
|
+
},
|
|
642
|
+
}}
|
|
643
|
+
>
|
|
644
|
+
```
|
|
645
|
+
|
|
646
|
+
Ayrıştırma ve vurgulama tüketicide kalır: `Prose` markdown ayrıştırmaz,
|
|
647
|
+
`CodeBlock` önceden vurgulanmış HTML alır (`html` prop'u — güvenliği sizin).
|
|
648
|
+
Bileşen listesi ve kararlar: `CLAUDE.md` → "`@ahmetilhn/hanui/chat`".
|
|
649
|
+
|
|
650
|
+
## SCSS API — `@ahmetilhn/hanui/scss`
|
|
651
|
+
|
|
652
|
+
Token değişkenleri ve mixin'ler kopyalanmadan alınır. Değişkenler
|
|
653
|
+
`var(--hanui-…)` dizeleridir; tema çalışma zamanında döner. Modül kural basmaz,
|
|
654
|
+
`styles.css` yine gerekir.
|
|
655
|
+
|
|
656
|
+
```scss
|
|
657
|
+
@use '@ahmetilhn/hanui/scss' as hanui;
|
|
658
|
+
|
|
659
|
+
.panel {
|
|
660
|
+
padding: hanui.$space-4;
|
|
661
|
+
border: 1px solid hanui.$border;
|
|
662
|
+
|
|
663
|
+
@include hanui.focus-ring;
|
|
664
|
+
|
|
665
|
+
@media (max-width: hanui.$breakpoint-tablet-portrait) {
|
|
666
|
+
padding: hanui.$space-3;
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
```
|
|
670
|
+
|
|
671
|
+
Next.js (Turbopack ve webpack) paket `exports`'unu çözer. Başka bir derleyici
|
|
672
|
+
çözemezse yol `node_modules/@ahmetilhn/hanui/build/scss` ile `loadPaths`e verilip
|
|
673
|
+
`@use 'index' as hanui` yazılabilir.
|
|
674
|
+
|
|
675
|
+
## Grafikler — `@ahmetilhn/hanui/charts`
|
|
676
|
+
|
|
677
|
+
On SVG grafiği, sıfır bağımlılık (çizim, ölçek ve istatistik kütüphanenin
|
|
678
|
+
kendisinde). Ana paketi ve `styles.css`i büyütmez.
|
|
679
|
+
|
|
680
|
+
```tsx
|
|
681
|
+
import '@ahmetilhn/hanui/styles.css';
|
|
682
|
+
import '@ahmetilhn/hanui/charts.css'; // styles.css'TEN SONRA
|
|
683
|
+
|
|
684
|
+
import { BarChart, LineChart, PieChart } from '@ahmetilhn/hanui/charts';
|
|
685
|
+
|
|
686
|
+
<LineChart
|
|
687
|
+
label="Aylık gelir ve gider"
|
|
688
|
+
description="Gelir ekimde zirve yaptı"
|
|
689
|
+
xKey="month"
|
|
690
|
+
data={[
|
|
691
|
+
{ month: 'Oca', revenue: 120, cost: 90 },
|
|
692
|
+
{ month: 'Şub', revenue: 180, cost: null }, // null = veri yok: çizgi KESİLİR
|
|
693
|
+
]}
|
|
694
|
+
series={[
|
|
695
|
+
{ key: 'revenue', label: 'Gelir' },
|
|
696
|
+
{ key: 'cost', label: 'Gider', format: value => `${value} ₺` },
|
|
697
|
+
]}
|
|
698
|
+
/>;
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
| Grafik | Ne zaman |
|
|
702
|
+
|---|---|
|
|
703
|
+
| `LineChart` · `AreaChart` | Zaman içinde eğilim; `AreaChart isStacked` toplamın parçaları |
|
|
704
|
+
| `BarChart` | Kategorileri karşılaştırma; `orientation="horizontal"` uzun adlar için |
|
|
705
|
+
| `ComposedChart` | Çubuk + çizgi; farklı birim `axis: 'right'` |
|
|
706
|
+
| `PieChart` | Bir bütünün ≤6 parçası (`variant="donut"` varsayılan) |
|
|
707
|
+
| `ScatterPlot` | İki değişkenin ilişkisi; `size` ile balon |
|
|
708
|
+
| `Heatmap` | İki kategorik eksende yoğunluk (gün × saat) |
|
|
709
|
+
| `BoxPlot` · `Histogram` | Dağılım: grupları karşılaştırma · tek değişkenin şekli |
|
|
710
|
+
| `RadarChart` | Birkaç seriyi aynı eksen takımında; eksenler AYNI ölçekte |
|
|
711
|
+
|
|
712
|
+
Her grafik tek bir sekme durağıdır: oklar öğeleri gezer (gelinen öğe
|
|
713
|
+
duyurulur), `Home`/`End` uçlara gider, `Escape` vurguyu kaldırır. Ekran okuyucu
|
|
714
|
+
grafiği gizli bir **veri tablosu** olarak da okur. Genişlik kapsayıcıdan ölçülür
|
|
715
|
+
(`width` ile sabitlenebilir), yükseklik `height`. Sayılar `labels.locale`
|
|
716
|
+
yereliyle biçimlenir; `formatValue` / `format` ile ezilir. Renkler kategorik
|
|
717
|
+
paletten (`tone`: `cat-1`…`cat-5`, `series-1`, `series-2`, `muted`).
|
|
718
|
+
|
|
719
|
+
## 5.0'a geçiş
|
|
720
|
+
|
|
721
|
+
5.0 bir **renk** sürümü: nötr eksen yeşilden sıcak mürekkebe geçti, yeşil
|
|
722
|
+
yalnızca eylem, bağlantı ve odakta kaldı. Bileşen API'si değişmedi; kırılan şey
|
|
723
|
+
token adları ve görünüm.
|
|
724
|
+
|
|
725
|
+
| 4.x token | 5.0 |
|
|
726
|
+
|---|---|
|
|
727
|
+
| `role`, `role-hover`, `role-active` | `selected`, `selected-hover`, `selected-active` (mürekkep) |
|
|
728
|
+
| `on-role` | `on-selected` |
|
|
729
|
+
| `role-tint` / `role-line` | `selected-tint` / `selected-line` |
|
|
730
|
+
| `role-text` | `link` (+ `link-hover`) |
|
|
731
|
+
| `shell*` | aynı ad, değer çamdan mürekkebe; yeni `on-shell`, `on-shell-2`, `on-shell-danger`, `shell-line` |
|
|
732
|
+
| — | `cat-1…5`, `series-1/2` (kategorik palet) |
|
|
733
|
+
|
|
734
|
+
Eski adlara takma ad **yok**. Kendi CSS'inizde `--hanui-role*` okuyan ya da
|
|
735
|
+
`theme={{ light: { role: … } }}` ezmesi yazan yerler yeni adlara geçer.
|
|
736
|
+
Görünüm değişiklikleri: açık sayfa krem (`#faf9f5`), koyu sayfa sıcak siyah
|
|
737
|
+
(`#141413`), kart ve panel durgunken gölgesiz, `info` tonu nötr, `CodeBadge`
|
|
738
|
+
mürekkep. Ayrıntı ve ölçümler: `CLAUDE.md` → "Renk kararları (5.0)".
|
|
739
|
+
|
|
740
|
+
## 5.1 – 5.3'te eklenenler
|
|
741
|
+
|
|
742
|
+
Hepsi ekleme; 5.0'ın token sözleşmesi dışında kırıcı değişiklik yok.
|
|
743
|
+
|
|
744
|
+
| Sürüm | Ne |
|
|
745
|
+
|---|---|
|
|
746
|
+
| 5.1 | `Disclosure`, `StatusDot`, `Kbd`; `useHanuiTokens`, `useStickToBottom`, `hasOpenSurface`; `Modal size="xl"`, `Button size={UISize.XSMALL}` + `shape="pill"`, `IconButton shape="round"`, `Textarea variant="bare"`, `Progress size="xs"`, etkileşimli `CodeBadge`, `Avatar` (`icon`, `shape="rounded"`, `tone="brand"`), `Stat variant="inline"`, `ScrollArea isFollowingEnd`; `CommandPalette` `hotkey` + komut kapanıştan SONRA çalışır |
|
|
747
|
+
| 5.2 | `HanuiThemeScript`; `@ahmetilhn/hanui/chat` — 20 sohbet bileşeni |
|
|
748
|
+
| 5.3 | `@ahmetilhn/hanui/charts` — 10 SVG grafiği; `@ahmetilhn/hanui/scss`; `Input --technical` dar ekranda ≥16px; `QuantityStepper` ve `DataTable` pasif/dinlenme hâli opacity yerine token |
|
|
749
|
+
|
|
750
|
+
Ayrıntı ve ölçülmüş gerekçeler: `CLAUDE.md` → "Göç ve `@deprecated` yollar",
|
|
751
|
+
"`@ahmetilhn/hanui/chat`", "`@ahmetilhn/hanui/charts`".
|
|
752
|
+
|
|
533
753
|
## Tasarım sözleşmesi
|
|
534
754
|
|
|
535
755
|
Öğe seçimi (hangi durumda hangi bileşen), yüzey/yükseklik merdiveni, renk
|
|
536
756
|
kararları, durum tintleri, tipografi rolleri, erişilebilirlik eşikleri, hareket
|
|
537
757
|
ölçeği ve `@deprecated` göç yolları **`CLAUDE.md`** içindedir. O dosya
|
|
538
|
-
|
|
758
|
+
kütüphaneyi kullanan uygulamalar için de normatiftir.
|
|
539
759
|
|
|
540
760
|
## Lisans
|
|
541
761
|
|
package/build/charts.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use client";"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const l=require("react/jsx-runtime"),f=require("react"),dt=require("@ahmetilhn/hanui"),at=(t,s)=>Object.assign(t,{displayName:s}),ue="hanui-axis-AqLAe",me="hanui-axis__label-dHxpo",de="hanui-axis__grid-RVxXW",xe="hanui-axis__baseline-jhG2z",st={axis:ue,axis__label:me,axis__grid:de,axis__baseline:xe},ce=6.4,ht=t=>t.length*ce,re=(t,s=8)=>{if(t.length<2)return[...t];const e=Math.max(...t.map(u=>ht(u.label))),n=Math.abs(t[1].position-t[0].position),r=n<=0?1:Math.max(1,Math.ceil((e+s)/n));return t.filter((u,m)=>m%r===0)},St=(t,s)=>{const e=Math.max(1,Math.floor(s/ce));return t.length<=e?t:`${t.slice(0,Math.max(1,e-1))}…`},ut=({area:t,ticks:s,side:e,hasGrid:n=!1})=>l.jsx("g",{className:st.axis,"aria-hidden":!0,children:s.map(r=>e==="bottom"?l.jsxs("g",{children:[n&&l.jsx("line",{className:st.axis__grid,x1:r.position,x2:r.position,y1:t.top,y2:t.bottom}),l.jsx("text",{className:st.axis__label,x:r.position,y:t.bottom+16,textAnchor:"middle",children:r.label})]},`${r.position}-${r.label}`):l.jsxs("g",{children:[n&&l.jsx("line",{className:st.axis__grid,x1:t.left,x2:t.right,y1:r.position,y2:r.position}),l.jsx("text",{className:st.axis__label,x:e==="left"?t.left-8:t.right+8,y:r.position,dy:"0.32em",textAnchor:e==="left"?"end":"start",children:r.label})]},`${r.position}-${r.label}`))}),qt=({area:t,ticks:s,side:e})=>l.jsx("g",{className:st.axis,"aria-hidden":!0,children:e==="bottom"?l.jsxs(l.Fragment,{children:[l.jsx("line",{className:st.axis__baseline,x1:t.left,x2:t.right,y1:t.bottom,y2:t.bottom}),re(s).map(n=>l.jsx("text",{className:st.axis__label,x:n.position,y:t.bottom+16,textAnchor:"middle",children:n.label},`${n.position}-${n.label}`))]}):l.jsxs(l.Fragment,{children:[l.jsx("line",{className:st.axis__baseline,x1:t.left,x2:t.left,y1:t.top,y2:t.bottom}),s.map(n=>l.jsx("text",{className:st.axis__label,x:t.left-8,y:n.position,dy:"0.32em",textAnchor:"end",children:St(n.label,t.left-12)},`${n.position}-${n.label}`))]})}),W=t=>Math.round(t*100)/100,fe=t=>{const s=[];let e=[];for(const n of t)n===null||!Number.isFinite(n.x)||!Number.isFinite(n.y)?(e.length>0&&s.push(e),e=[]):e.push(n);return e.length>0&&s.push(e),s},Ft=t=>t.map((s,e)=>`${e===0?"M":"L"}${W(s.x)},${W(s.y)}`).join(""),le=t=>{const s=t.length;if(s<3)return Ft(t);const e=[],n=[];for(let u=0;u<s-1;u+=1){const m=t[u+1].x-t[u].x;n.push(m===0?0:(t[u+1].y-t[u].y)/m)}e.push(n[0]);for(let u=1;u<s-1;u+=1)e.push(n[u-1]*n[u]<=0?0:(n[u-1]+n[u])/2);e.push(n[s-2]);for(let u=0;u<s-1;u+=1){if(n[u]===0){e[u]=0,e[u+1]=0;continue}const m=e[u]/n[u],d=e[u+1]/n[u],k=m*m+d*d;if(k>9){const T=3/Math.sqrt(k);e[u]=T*m*n[u],e[u+1]=T*d*n[u]}}let r=`M${W(t[0].x)},${W(t[0].y)}`;for(let u=0;u<s-1;u+=1){const m=t[u],d=t[u+1],k=(d.x-m.x)/3;r+=`C${W(m.x+k)},${W(m.y+e[u]*k)} ${W(d.x-k)},${W(d.y-e[u+1]*k)} ${W(d.x)},${W(d.y)}`}return r},pe=(t,s="linear")=>fe(t).map(e=>s==="monotone"?le(e):Ft(e)).join(""),ye=(t,s,e="linear")=>{const n=[];let r=[],u=[];const m=()=>{if(r.length>0){const d=e==="monotone"?le:Ft,k=d([...u].reverse()).replace(/^M/,"L");n.push(`${d(r)}${k}Z`)}r=[],u=[]};return t.forEach((d,k)=>{const T=s[k];d===null||T===null||T===void 0?m():(r.push(d),u.push(T))}),m(),n.join("")},tt=(t,s,e,n)=>({x:t+e*Math.sin(n),y:s-e*Math.cos(n)}),Xt=(t,s,e,n,r,u)=>{const m=u-r;if(m<=0||e<=0)return"";if(m>=Math.PI*2-1e-6){const M=(F,z)=>`M${W(t)},${W(s-F)}A${F},${F} 0 1 ${z} ${W(t)},${W(s+F)}A${F},${F} 0 1 ${z} ${W(t)},${W(s-F)}Z`;return M(e,1)+(n>0?M(n,0):"")}const d=m>Math.PI?1:0,k=tt(t,s,e,r),T=tt(t,s,e,u);if(n<=0)return`M${W(t)},${W(s)}L${W(k.x)},${W(k.y)}A${e},${e} 0 ${d} 1 ${W(T.x)},${W(T.y)}Z`;const A=tt(t,s,n,u),I=tt(t,s,n,r);return`M${W(k.x)},${W(k.y)}A${e},${e} 0 ${d} 1 ${W(T.x)},${W(T.y)}L${W(A.x)},${W(A.y)}A${n},${n} 0 ${d} 0 ${W(I.x)},${W(I.y)}Z`},Yt=t=>t.length===0?"":`${Ft(t)}Z`,mt=(t,s)=>{const[e,n]=t,[r,u]=s,m=n-e,d=k=>m===0?(r+u)/2:r+(k-e)/m*(u-r);return d.domain=t,d.range=s,d.invert=k=>u===r?e:e+(k-r)/(u-r)*m,d},Rt=(t,s,{paddingInner:e=.2,paddingOuter:n=.1}={})=>{const[r,u]=s,m=t.length,d=m===0?0:(u-r)/Math.max(1,m-e+n*2),k=d*(1-e),T=r+d*n,A=new Map(t.map((M,F)=>[M,F])),I=M=>{const F=A.get(M);return F===void 0?Number.NaN:T+F*d};return I.domain=t,I.range=s,I.bandwidth=k,I.step=d,I.indexAt=M=>m===0?-1:Math.min(m-1,Math.max(0,Math.floor((M-r-d*n+(d-k)/2)/d))),I},Ot=(t,s,e)=>{const n=Math.abs(s-t);if(n===0||!Number.isFinite(n)||e<=0)return 1;const r=n/e,u=10**Math.floor(Math.log10(r)),m=r/u;return(m>=7.5?10:m>=3.5?5:m>=1.5?2:1)*u},Gt=(t,s)=>{const e=Math.max(0,-Math.floor(Math.log10(s))+1);return Number(t.toFixed(Math.min(e,12)))},$t=(t,s,e=5)=>{if(!Number.isFinite(t)||!Number.isFinite(s))return[0,1];let n=Math.min(t,s),r=Math.max(t,s);if(n===r){if(n===0)return[0,1];const m=Math.abs(n)*.5;n=n>0?0:n-m,r=r<0?0:r+m}const u=Ot(n,r,e);return[Gt(Math.floor(n/u)*u,u),Gt(Math.ceil(r/u)*u,u)]},ot=(t,s,e=5)=>{if(!Number.isFinite(t)||!Number.isFinite(s))return[];if(t===s)return[t];const n=Ot(t,s,e),r=Math.ceil(t/n-1e-9),u=Math.floor(s/n+1e-9),m=[];for(let d=r;d<=u&&m.length<1e3;d+=1)m.push(Gt(d*n,n));return m},be=(t,s)=>{if(t.length===0)return-1;let e=0,n=t.length-1;for(;e<n;){const r=e+n>>1;t[r]<s?e=r+1:n=r}return e>0&&Math.abs(t[e-1]-s)<=Math.abs(t[e]-s)?e-1:e},Ht=t=>t.filter(s=>typeof s=="number"&&Number.isFinite(s)),xt=t=>{if(t.length===0)return[0,0];let s=t[0],e=t[0];for(const n of t)n<s&&(s=n),n>e&&(e=n);return[s,e]},zt=(t,s)=>{if(t.length===0)return Number.NaN;if(t.length===1)return t[0];const e=(t.length-1)*Math.min(1,Math.max(0,s)),n=Math.floor(e),r=e-n;return n+1<t.length?t[n]+(t[n+1]-t[n])*r:t[n]},ge=t=>{const s=Ht(t).sort((m,d)=>m-d);if(s.length===0)return null;const e=zt(s,.25),n=zt(s,.75),r=(n-e)*1.5,u=s.filter(m=>m>=e-r&&m<=n+r);return{count:s.length,min:s[0],q1:e,median:zt(s,.5),q3:n,max:s[s.length-1],whiskerLow:u[0]??e,whiskerHigh:u[u.length-1]??n,outliers:s.filter(m=>m<e-r||m>n+r)}},Me=(t,s)=>{const e=Ht(t);if(e.length===0)return[];const[n,r]=xt(e);if(n===r)return[{from:n,to:n+1,count:e.length}];const u=s??Math.ceil(Math.log2(e.length))+1,m=Ot(n,r,Math.max(1,u)),d=Math.floor(n/m)*m,k=Math.max(1,Math.ceil((r-d)/m-1e-9)),T=Array.from({length:k},(A,I)=>({from:d+I*m,to:d+(I+1)*m,count:0}));for(const A of e){const I=Math.min(T.length-1,Math.floor((A-d)/m));T[I].count+=1}return T},wt=t=>typeof t=="number"&&Number.isFinite(t)?t:null,ct={top:12,right:16,bottom:28,minLeft:32},_e=(t,s)=>{const e=t.map(()=>0),n=t.map(()=>0),r={};for(const u of s)r[u]=t.map((m,d)=>{const k=wt(m[u])??0;if(k>=0){const A=e[d];return e[d]+=k,{base:A,top:e[d]}}const T=n[d];return n[d]+=k,{base:T,top:n[d]}});return r},we=t=>{const{rows:s,xKey:e,series:n,width:r,height:u,isStacked:m,curve:d,formatX:k}=t,T=n.some(v=>v.type==="bar"),I=(T&&n.every(v=>v.type==="bar")?t.orientation:"vertical")==="horizontal",M=s.map(v=>v[e]),F=!T&&!I&&M.length>1&&M.every(v=>wt(v)!==null),z={};if(m)for(const v of["left","right"])for(const O of["bar","area"]){const B=n.filter(Y=>(Y.axis??"left")===v&&Y.type===O).map(Y=>Y.key);Object.assign(z,_e(s,B))}const H=(v,O)=>{if(z[v])return z[v][O];const B=wt(s[O][v]);return B===null?null:{base:0,top:B}},q=v=>{const O=n.filter(lt=>(lt.axis??"left")===v);if(O.length===0)return null;let B=Number.POSITIVE_INFINITY,Y=Number.NEGATIVE_INFINITY;for(const lt of O)for(let bt=0;bt<s.length;bt+=1){const it=H(lt.key,bt);it&&(B=Math.min(B,it.top,it.base),Y=Math.max(Y,it.top,it.base))}if(O.some(lt=>lt.type!=="line")&&(B=Math.min(B,0),Y=Math.max(Y,0)),!Number.isFinite(B)||!Number.isFinite(Y))return[0,1];const[et,J]=v==="left"?t.domain??[void 0,void 0]:[void 0,void 0],K=$t(et??B,J??Y);return[et??K[0],J??K[1]]},P=q("left")??[0,1],N=q("right"),R=N!==null&&!I,E=ot(P[0],P[1],5).map(t.formatLeft),w=N?ot(N[0],N[1],5).map(t.formatRight):[],j=s.map(v=>k(v[e])),h=I?Math.min(r*.4,Math.max(ct.minLeft,...j.map(ht))+12):Math.max(ct.minLeft,...E.map(ht))+10,y=R?Math.max(ct.minLeft,...w.map(ht))+10:ct.right,a={left:h,top:ct.top,right:Math.max(h+1,r-y),bottom:Math.max(ct.top+1,u-ct.bottom),width:Math.max(1,r-y-h),height:Math.max(1,u-ct.bottom-ct.top)},i=I?[a.top,a.bottom]:[a.left,a.right],c=I?[a.left,a.right]:[a.bottom,a.top],o=mt(P,c),x=N?mt(N,c):o,_=v=>(v.axis??"left")==="right"&&N?x:o;let $,b=0,p=null;if(F){const v=M.map(O=>wt(O));p=mt(xt(v),i),$=v.map(p)}else{const v=Rt(s.map((O,B)=>String(B)),i,T?{paddingInner:.24,paddingOuter:.12}:{paddingInner:0,paddingOuter:0});b=v.bandwidth,$=s.map((O,B)=>v(String(B))+v.bandwidth/2)}const C=(v,O)=>I?{x:O,y:v}:{x:v,y:O},G=[],V=n.filter(v=>v.type==="bar"),Z=m?1:Math.max(1,V.length),D=Z>1?Math.min(2,b*.04):0,g=Math.max(1,(b-D*(Z-1))/Z);V.forEach((v,O)=>{const B=_(v),Y=m?0:O;s.forEach((et,J)=>{const K=H(v.key,J);if(!K||K.top===K.base)return;const lt=$[J]-b/2+Y*(g+D),bt=B(K.base),it=B(K.top),Wt=Math.min(bt,it),Vt=Math.max(1,Math.abs(it-bt));G.push(I?{key:v.key,index:J,tone:v.tone,x:Wt,y:lt,width:Vt,height:g}:{key:v.key,index:J,tone:v.tone,x:lt,y:Wt,width:g,height:Vt})})});const S={},L=[],X=[];for(const v of n){if(v.type==="bar")continue;const O=_(v),B=s.map((Y,et)=>{const J=H(v.key,et);return J?C($[et],O(J.top)):null});if(S[v.key]=B,v.type==="area"){const Y=s.map((et,J)=>{const K=H(v.key,J);return K?C($[J],O(K.base)):null});X.push({key:v.key,tone:v.tone,d:ye(B,Y,d)})}L.push({key:v.key,tone:v.tone,d:pe(B,d)})}const rt=s.map((v,O)=>{let B=null;for(const et of n){const J=H(et.key,O);if(!J)continue;const K=_(et)(J.top);B=B===null?K:I?Math.max(B,K):Math.min(B,K)}const Y=I?a.left:a.bottom;return C($[O],B??Y)}),jt=(v,O,B)=>ot(O[0],O[1],I?Math.max(2,Math.floor(a.width/90)):Math.max(2,Math.floor(a.height/48))).map(Y=>({position:v(Y),label:B(Y)})),he=p?ot(p.domain[0],p.domain[1],Math.max(2,Math.floor(a.width/90))).map(v=>({position:p(v),label:k(v)})):s.map((v,O)=>({position:$[O],label:I?St(j[O],h-12):j[O]}));return{zero:P[0]<0&&P[1]>0?o(0):null,area:a,centers:$,bandwidth:b,isContinuous:F,categoryTicks:he,leftTicks:jt(o,P,t.formatLeft),rightTicks:R&&N?jt(x,N,t.formatRight):[],hasRightAxis:R,lines:L,areas:X,bars:G,points:S,anchors:rt}},Zt=(...t)=>{let s="";for(const e of t)e&&(s=s===""?e:`${s} ${e}`);return s},Ut=["cat-1","cat-2","cat-3","cat-4","cat-5","series-2"],vt=(t,s)=>s??Ut[t%Ut.length],U=t=>t==="muted"?"var(--hanui-text-3)":`var(--hanui-${t})`,$e="hanui-chart-iR-5u",je="hanui-chart__canvas-4wf8o",ke="hanui-chart__svg-yC5iw",Ne="hanui-chart__overlay-kbXEv",ve="hanui-chart__tooltip-wbhLY",Ae="hanui-chart__tooltipTitle-j-1Nw",Ce="hanui-chart__tooltipRow-phors",Te="hanui-chart__tooltipLabel-72x80",Ie="hanui-chart__tooltipValue-caeby",Re="hanui-chart__swatch--mk77",Se="hanui-chart__legend-EhXcQ",Fe="hanui-chart__legendItem--AaGe",He="hanui-chart__srOnly-Oyem2",Q={chart:$e,chart__canvas:je,chart__svg:ke,chart__overlay:Ne,chart__tooltip:ve,chart__tooltipTitle:Ae,chart__tooltipRow:Ce,chart__tooltipLabel:Te,chart__tooltipValue:Ie,chart__swatch:Re,chart__legend:Se,chart__legendItem:Fe,"chart__legendItem--hidden":"hanui-chart__legendItem--hidden-D3li8",chart__srOnly:He},Qt=12,ft=({label:t,description:s,containerRef:e,width:n,height:r,plot:u,overlay:m,underlay:d,itemCount:k,columns:T,pick:A,tooltip:I,anchor:M,tooltipSide:F="inward",announce:z,table:H,legend:q,className:P,testId:N})=>{const R=f.useId(),E=dt.useAnnounce(),[w,j]=f.useState(null),h=f.useRef(null),y=f.useRef(null),a=f.useRef(null);f.useEffect(()=>{w!==null&&w>=k&&j(k>0?k-1:null)},[w,k]),f.useEffect(()=>()=>{h.current!==null&&cancelAnimationFrame(h.current)},[]);const i=f.useCallback(b=>{const p=b.currentTarget.getBoundingClientRect();a.current={x:b.clientX-p.left,y:b.clientY-p.top},h.current===null&&(h.current=requestAnimationFrame(()=>{h.current=null;const C=a.current;C&&j(A(C.x,C.y))}))},[A]),c=b=>{const p=Math.min(k-1,Math.max(0,b));j(p),E(z(p))},o=b=>{if(k===0)return;const p=w??-1,C=T??1,G=b.key==="ArrowRight"?p+1:b.key==="ArrowLeft"?Math.max(0,p-1):b.key==="ArrowDown"?p<0?0:p+C:b.key==="ArrowUp"?Math.max(0,p-C):b.key==="Home"?0:b.key==="End"?k-1:null;if(b.key==="Escape"&&w!==null){b.preventDefault(),j(null);return}G!==null&&(b.preventDefault(),c(G))},x=w===null?null:I(w),_=w===null?null:M(w),$=_==null?void 0:_.x;return f.useLayoutEffect(()=>{const b=y.current;if(!b||$===void 0)return;const p=b.offsetWidth,C=$>n/2,G=F==="outward"?!C:C,V=$-Qt-p,Z=$+Qt,D=V>=0,g=Z+p<=n,S=F==="outward"?G?V:Z:G?D||!g?V:Z:g||!D?Z:V;b.style.left=`${Math.min(Math.max(0,S),Math.max(0,n-p))}px`},[w,$,n,F]),l.jsxs("figure",{className:Zt(Q.chart,P),"data-testid":N,children:[l.jsxs("div",{ref:e,className:Q.chart__canvas,style:{blockSize:r},children:[l.jsxs("svg",{className:Q.chart__svg,width:n,height:r,viewBox:`0 0 ${n} ${r}`,role:"img","aria-label":t,"aria-describedby":s?R:void 0,tabIndex:k>0?0:void 0,onPointerMove:i,onPointerDown:i,onPointerLeave:()=>j(null),onKeyDown:o,onBlur:()=>j(null),children:[w!==null&&d&&l.jsx("g",{className:Q.chart__overlay,children:d(w)}),u,w!==null&&l.jsx("g",{className:Q.chart__overlay,children:m(w)})]}),x&&_&&l.jsxs("div",{ref:y,"aria-hidden":!0,className:Q.chart__tooltip,style:{insetBlockStart:Math.max(24,Math.min(_.y,r-24))},children:[x.title&&l.jsx("span",{className:Q.chart__tooltipTitle,children:x.title}),x.rows.map(b=>l.jsxs("span",{className:Q.chart__tooltipRow,children:[b.tone&&l.jsx("span",{className:Q.chart__swatch,style:{backgroundColor:U(b.tone)}}),l.jsx("span",{className:Q.chart__tooltipLabel,children:b.label}),l.jsx("span",{className:Q.chart__tooltipValue,children:b.value})]},b.id))]})]}),q&&q.entries.length>1&&l.jsx("ul",{className:Q.chart__legend,children:q.entries.map(b=>{const p=q.hidden.has(b.id);return l.jsx("li",{children:l.jsxs("button",{type:"button",className:Zt(Q.chart__legendItem,p&&Q["chart__legendItem--hidden"]),"aria-pressed":!p,onClick:()=>q.onToggle(b.id),children:[l.jsx(Le,{tone:b.tone,isHidden:p}),b.label]})},b.id)})}),s&&l.jsx("p",{id:R,className:Q.chart__srOnly,children:s}),l.jsx("div",{className:Q.chart__srOnly,children:l.jsxs("table",{children:[l.jsx("caption",{children:t}),l.jsx("thead",{children:l.jsx("tr",{children:H.columns.map((b,p)=>l.jsx("th",{scope:"col",children:b},p))})}),l.jsx("tbody",{children:H.rows.map((b,p)=>l.jsx("tr",{children:b.map((C,G)=>G===0?l.jsx("th",{scope:"row",children:C},G):l.jsx("td",{children:C},G))},p))})]})})]})},Le=({tone:t,isHidden:s})=>l.jsx("span",{"aria-hidden":!0,className:Q.chart__swatch,style:s?{backgroundColor:"transparent",boxShadow:`inset 0 0 0 2px ${U(t)}`}:{backgroundColor:U(t)}}),Jt=new Map,ie=(t,s)=>{const e=`${t??""}|${JSON.stringify(s)}`;let n=Jt.get(e);return n||(n=new Intl.NumberFormat(t,s),Jt.set(e,n)),n},At=t=>s=>ie(t,{notation:"compact",maximumFractionDigits:1}).format(s),pt=t=>s=>ie(t,{maximumFractionDigits:2}).format(s),ze=640,Ee=typeof window>"u"?()=>{}:f.useLayoutEffect,yt=t=>{const s=f.useRef(null),[e,n]=f.useState(t??ze);return Ee(()=>{if(t!==void 0){n(t);return}const r=s.current;if(!r)return;const u=d=>{const k=Math.floor(d);k>0&&n(T=>T===k?T:k)};if(u(r.clientWidth),typeof ResizeObserver>"u")return;const m=new ResizeObserver(([d])=>u(d.contentRect.width));return m.observe(r),()=>m.disconnect()},[t]),[s,e]},Pe="hanui-line-CLpqU",De="hanui-area-LkWXB",qe="hanui-bar-260Bd",Ge="hanui-point-Vc-kX",Oe="hanui-marker-G-xZb",Be="hanui-crosshair-nV-xX",We="hanui-band-jnG7s",Ve="hanui-zero-GpHvw",nt={line:Pe,area:De,bar:qe,point:Ge,marker:Oe,crosshair:Be,band:We,zero:Ve},Xe=280,Kt="—",Ye=({label:t,description:s,data:e,xKey:n,xLabel:r,series:u,height:m=Xe,width:d,isStacked:k=!1,orientation:T="vertical",curve:A="monotone",hasPoints:I=!1,formatX:M=String,formatValue:F,domain:z,className:H,testId:q})=>{const{labels:P}=dt.useHanui(),N=P==null?void 0:P.locale,[R,E]=yt(d),[w,j]=f.useState(()=>new Set),h=f.useMemo(()=>F??pt(N),[F,N]),y=f.useMemo(()=>At(N),[N]),a=f.useCallback(g=>g==null?"":M(g),[M]),i=f.useMemo(()=>u.map((g,S)=>({...g,tone:vt(S,g.tone)})),[u]),c=f.useMemo(()=>i.filter(g=>!w.has(g.key)),[i,w]),o=f.useMemo(()=>we({rows:e,xKey:n,series:c,width:E,height:m,isStacked:k,orientation:T,curve:A,formatX:a,formatLeft:y,formatRight:y,domain:z}),[e,n,c,E,m,k,T,A,a,y,z]),x=T==="horizontal"&&c.length>0&&c.every(g=>g.type==="bar"),_=c.some(g=>g.type==="bar"),$=f.useMemo(()=>{const g=o.centers.map((S,L)=>({center:S,index:L})).sort((S,L)=>S.center-L.center);return{centers:g.map(S=>S.center),indices:g.map(S=>S.index)}},[o.centers]),b=f.useCallback((g,S)=>{const{area:L}=o;if(g<L.left-4||g>L.right+4||S<L.top-4||S>L.bottom+4)return null;const X=be($.centers,x?S:g);return X<0?null:$.indices[X]},[o,$,x]),p=f.useCallback(g=>{var S;return{title:a((S=e[g])==null?void 0:S[n]),rows:c.map(L=>{var rt;const X=wt((rt=e[g])==null?void 0:rt[L.key]);return{id:L.key,label:L.label,tone:L.tone,value:X===null?Kt:(L.format??h)(X)}})}},[e,n,c,h,a]),C=f.useCallback(g=>{const S=p(g);return`${S.title}: ${S.rows.map(L=>`${L.label} ${L.value}`).join(", ")}`},[p]),G=f.useMemo(()=>({columns:[r??n,...i.map(g=>g.label)],rows:e.map(g=>[a(g[n]),...i.map(S=>{const L=wt(g[S.key]);return L===null?Kt:(S.format??h)(L)})])}),[e,n,r,i,h,a]),V=f.useMemo(()=>l.jsxs("g",{children:[x?l.jsxs(l.Fragment,{children:[l.jsx(ut,{area:o.area,ticks:o.leftTicks,side:"bottom",hasGrid:!0}),l.jsx(qt,{area:o.area,ticks:o.categoryTicks,side:"left"})]}):l.jsxs(l.Fragment,{children:[l.jsx(ut,{area:o.area,ticks:o.leftTicks,side:"left",hasGrid:!0}),o.hasRightAxis&&l.jsx(ut,{area:o.area,ticks:o.rightTicks,side:"right"}),l.jsx(qt,{area:o.area,ticks:o.categoryTicks,side:"bottom"})]}),o.zero!==null&&(x?l.jsx("line",{className:nt.zero,x1:o.zero,x2:o.zero,y1:o.area.top,y2:o.area.bottom}):l.jsx("line",{className:nt.zero,x1:o.area.left,x2:o.area.right,y1:o.zero,y2:o.zero})),o.areas.map(g=>l.jsx("path",{d:g.d,className:nt.area,style:{fill:`color-mix(in srgb, ${U(g.tone)} 18%, transparent)`}},`area-${g.key}`)),o.bars.map(g=>l.jsx("rect",{className:nt.bar,x:g.x,y:g.y,width:g.width,height:g.height,rx:Math.min(3,g.width/4,g.height/4),style:{fill:U(g.tone)}},`bar-${g.key}-${g.index}`)),o.lines.map(g=>l.jsx("path",{d:g.d,className:nt.line,style:{stroke:U(g.tone)}},`line-${g.key}`)),c.filter(g=>g.type!=="bar").flatMap(g=>(o.points[g.key]??[]).map((S,L,X)=>S&&(I||!X[L-1]&&!X[L+1])?l.jsx("circle",{className:nt.point,cx:S.x,cy:S.y,r:3,style:{fill:U(g.tone)}},`point-${g.key}-${L}`):null))]}),[o,I,x,c]),Z=f.useCallback(g=>{if(!_||o.bandwidth<=0)return null;const{area:S}=o,L=o.centers[g],X=o.bandwidth*.12;return x?l.jsx("rect",{className:nt.band,x:S.left,width:S.width,y:L-o.bandwidth/2-X,height:o.bandwidth+X*2}):l.jsx("rect",{className:nt.band,y:S.top,height:S.height,x:L-o.bandwidth/2-X,width:o.bandwidth+X*2})},[o,x,_]),D=f.useCallback(g=>{const{area:S}=o,L=o.centers[g];return l.jsxs(l.Fragment,{children:[!_&&l.jsx("line",{className:nt.crosshair,x1:L,x2:L,y1:S.top,y2:S.bottom}),c.filter(X=>X.type!=="bar").map(X=>{var jt;const rt=(jt=o.points[X.key])==null?void 0:jt[g];return rt?l.jsx("circle",{className:nt.marker,cx:rt.x,cy:rt.y,r:4.5,style:{fill:U(X.tone)}},X.key):null})]})},[o,c,_]);return l.jsx(ft,{label:t,description:s,containerRef:R,width:E,height:m,plot:V,overlay:D,underlay:Z,itemCount:e.length,pick:b,tooltip:p,anchor:g=>o.anchors[g]??{x:0,y:0},announce:C,table:G,legend:{entries:i.map(g=>({id:g.key,label:g.label,tone:g.tone})),hidden:w,onToggle:g=>j(S=>{const L=new Set(S);return L.has(g)?L.delete(g):i.length-S.size>1&&L.add(g),L})},className:H,testId:q})},Lt=f.memo(Ye),Ze=({series:t,...s})=>{const e=f.useMemo(()=>t.map(n=>({...n,type:"line"})),[t]);return l.jsx(Lt,{...s,series:e})},Ue=f.memo(at(Ze,"LineChart")),Qe=({series:t,...s})=>{const e=f.useMemo(()=>t.map(n=>({...n,type:"area"})),[t]);return l.jsx(Lt,{...s,series:e})},Je=f.memo(at(Qe,"AreaChart")),Ke=({series:t,...s})=>{const e=f.useMemo(()=>t.map(n=>({...n,type:"bar"})),[t]);return l.jsx(Lt,{...s,series:e})},tn=f.memo(at(Ke,"BarChart")),en=t=>l.jsx(Lt,{...t}),nn=f.memo(at(en,"ComposedChart")),sn="hanui-slice-dFWuh",on="hanui-center__value-GnqKe",an="hanui-center__label-DsgTV",kt={slice:sn,center__value:on,center__label:an},Ct=6,te=1.5,cn=({label:t,description:s,data:e,variant:n="donut",centerValue:r,centerLabel:u,valueLabel:m,height:d=260,width:k,formatValue:T,className:A,testId:I})=>{const{labels:M}=dt.useHanui(),[F,z]=yt(k),[H,q]=f.useState(()=>new Set),P=f.useMemo(()=>pt(M==null?void 0:M.locale),[M==null?void 0:M.locale]),N=T??P,R=f.useMemo(()=>e.map((a,i)=>({...a,tone:vt(i,a.tone)})),[e]),E=f.useMemo(()=>{const a=R.filter(p=>!H.has(p.id)&&Number.isFinite(p.value)&&p.value>0),i=a.reduce((p,C)=>p+C.value,0),c=z/2,o=d/2,x=Math.max(8,Math.min(z,d)/2-Ct-4),_=n==="donut"?x*.62:0;let $=0;const b=a.map(p=>{const C=i>0?p.value/i*Math.PI*2:0,G=$;return $+=C,{...p,start:G,end:$,share:i>0?p.value/i:0}});return{cx:c,cy:o,outer:x,inner:_,total:i,slices:b}},[R,H,z,d,n]),w=f.useMemo(()=>{const a=new Intl.NumberFormat(M==null?void 0:M.locale,{style:"percent",maximumFractionDigits:1});return i=>a.format(i)},[M==null?void 0:M.locale]),j=f.useMemo(()=>{const{cx:a,cy:i,outer:c,inner:o,slices:x,total:_}=E;return l.jsxs("g",{children:[x.map($=>l.jsx("path",{className:kt.slice,d:Xt(a,i,c,o,$.start,$.end),style:{fill:U($.tone),strokeWidth:x.length>1?te:0}},$.id)),n==="donut"&&l.jsxs("g",{"aria-hidden":!0,className:kt.center,children:[l.jsx("text",{className:kt.center__value,x:a,y:u?i-4:i,dy:"0.32em",textAnchor:"middle",children:r??N(_)}),u&&l.jsx("text",{className:kt.center__label,x:a,y:i+16,dy:"0.32em",textAnchor:"middle",children:u})]})]})},[E,n,r,u,N]),h=f.useCallback((a,i)=>{const{cx:c,cy:o,outer:x,inner:_,slices:$}=E,b=Math.hypot(a-c,i-o);if(b>x+Ct||b<_)return null;let p=Math.atan2(a-c,-(i-o));p<0&&(p+=Math.PI*2);const C=$.findIndex(G=>p>=G.start&&p<G.end);return C<0?null:C},[E]),y=a=>{const i=E.slices[a];return`${N(i.value)} (${w(i.share)})`};return l.jsx(ft,{label:t,description:s,containerRef:F,width:z,height:d,plot:j,overlay:a=>{const{cx:i,cy:c,outer:o,inner:x,slices:_}=E,$=_[a],b=($.start+$.end)/2,p=tt(0,0,Ct,b);return l.jsx("path",{className:kt.slice,d:Xt(i+p.x,c+p.y,o,x,$.start,$.end),style:{fill:U($.tone),strokeWidth:te}})},itemCount:E.slices.length,pick:h,tooltip:a=>{const i=E.slices[a];return{rows:[{id:i.id,label:i.label,value:y(a),tone:i.tone}]}},anchor:a=>{const{cx:i,cy:c,outer:o,slices:x}=E,_=x[a];return tt(i,c,o+Ct,(_.start+_.end)/2)},tooltipSide:"outward",announce:a=>`${E.slices[a].label}: ${y(a)}`,table:{columns:[t,m],rows:R.map(a=>[a.label,Number.isFinite(a.value)?N(a.value):"—"])},legend:{entries:R.map(a=>({id:a.id,label:a.label,tone:a.tone})),hidden:H,onToggle:a=>q(i=>{const c=new Set(i);return c.has(a)?c.delete(a):R.length-i.size>1&&c.add(a),c})},className:A,testId:I})},rn=f.memo(at(cn,"PieChart")),Bt=(t,s,e,{top:n=12,right:r=16,bottom:u=28}={})=>{const m=Math.max(32,...e.map(ht))+10;return{left:m,top:n,right:Math.max(m+1,t-r),bottom:Math.max(n+1,s-u),width:Math.max(1,t-r-m),height:Math.max(1,s-n-u)}},Nt=(t,s)=>Math.max(2,Math.floor(t/(s?90:48))),ln=(t,s=24)=>{const e=new Map,n=(r,u)=>`${r}:${u}`;return t.forEach((r,u)=>{if(!Number.isFinite(r.x)||!Number.isFinite(r.y))return;const m=n(Math.floor(r.x/s),Math.floor(r.y/s)),d=e.get(m);d?d.push(u):e.set(m,[u])}),{nearest:(r,u,m)=>{const d=Math.ceil(m/s),k=Math.floor(r/s),T=Math.floor(u/s);let A=null,I=m*m;for(let M=-d;M<=d;M+=1)for(let F=-d;F<=d;F+=1)for(const z of e.get(n(k+M,T+F))??[]){const H=(t[z].x-r)**2+(t[z].y-u)**2;H<=I&&(I=H,A=z)}return A}}},hn="hanui-point-YKyMm",un="hanui-marker-ToO1T",ee={point:hn,marker:un},gt={plain:4,min:3,max:16},mn=22,dn=({label:t,description:s,series:e,xLabel:n,yLabel:r,sizeLabel:u,height:m=300,width:d,formatX:k,formatY:T,className:A,testId:I})=>{const{labels:M}=dt.useHanui(),[F,z]=yt(d),[H,q]=f.useState(()=>new Set),P=f.useMemo(()=>pt(M==null?void 0:M.locale),[M==null?void 0:M.locale]),N=f.useMemo(()=>At(M==null?void 0:M.locale),[M==null?void 0:M.locale]),R=k??P,E=T??P,w=f.useMemo(()=>e.map((c,o)=>({...c,tone:vt(o,c.tone)})),[e]),j=f.useMemo(()=>w.filter(c=>!H.has(c.id)).flatMap(c=>c.data.filter(o=>Number.isFinite(o.x)&&Number.isFinite(o.y)).map(o=>({...o,series:c}))).sort((c,o)=>c.x-o.x||c.y-o.y),[w,H]),h=f.useMemo(()=>{const c=$t(...xt(j.map(D=>D.x))),o=$t(...xt(j.map(D=>D.y))),x=ot(o[0],o[1],Nt(m,!1)),_=Bt(z,m,x.map(N),{right:20}),$=mt(c,[_.left,_.right]),b=mt(o,[_.bottom,_.top]),p=Ht(j.map(D=>D.size)),[C,G]=xt(p),V=D=>D===void 0||!Number.isFinite(D)||p.length===0?gt.plain:G===C?(gt.min+gt.max)/2:Math.sqrt(gt.min**2+(D-C)/(G-C)*(gt.max**2-gt.min**2)),Z=j.map(D=>({...D,cx:$(D.x),cy:b(D.y),r:V(D.size)}));return{area:_,placed:Z,index:ln(Z.map(D=>({x:D.cx,y:D.cy}))),xTicks:ot(c[0],c[1],Nt(_.width,!0)).map(D=>({position:$(D),label:N(D)})),yTicks:x.map(D=>({position:b(D),label:N(D)}))}},[j,z,m,N]),y=f.useMemo(()=>l.jsxs("g",{children:[l.jsx(ut,{area:h.area,ticks:h.yTicks,side:"left",hasGrid:!0}),l.jsx(ut,{area:h.area,ticks:h.xTicks,side:"bottom",hasGrid:!0}),h.placed.map((c,o)=>l.jsx("circle",{className:ee.point,cx:c.cx,cy:c.cy,r:c.r,style:{fill:`color-mix(in srgb, ${U(c.series.tone)} 72%, transparent)`,stroke:U(c.series.tone)}},o))]}),[h]),a=f.useCallback((c,o)=>h.index.nearest(c,o,mn),[h]),i=c=>{const o=h.placed[c];return{title:o.label??o.series.label,rows:[{id:"series",label:o.series.label,value:"",tone:o.series.tone},{id:"x",label:n,value:R(o.x)},{id:"y",label:r,value:E(o.y)},...o.size!==void 0&&u?[{id:"size",label:u,value:P(o.size)}]:[]]}};return l.jsx(ft,{label:t,description:s,containerRef:F,width:z,height:m,plot:y,overlay:c=>{const o=h.placed[c];return l.jsx("circle",{className:ee.marker,cx:o.cx,cy:o.cy,r:o.r+3,style:{stroke:U(o.series.tone)}})},itemCount:h.placed.length,pick:a,tooltip:i,anchor:c=>({x:h.placed[c].cx,y:h.placed[c].cy}),announce:c=>{const o=h.placed[c];return`${o.label?`${o.label}, `:""}${o.series.label}: ${n} ${R(o.x)}, ${r} ${E(o.y)}`},table:{columns:[t,n,r],rows:j.map(c=>[c.label??c.series.label,R(c.x),E(c.y)])},legend:{entries:w.map(c=>({id:c.id,label:c.label,tone:c.tone})),hidden:H,onToggle:c=>q(o=>{const x=new Set(o);return x.has(c)?x.delete(c):w.length-o.size>1&&x.add(c),x})},className:A,testId:I})},xn=f.memo(at(dn,"ScatterPlot")),fn="hanui-labels-MJWYF",pn="hanui-empty-AW7c9",yn="hanui-focus-hLQdB",Tt={labels:fn,empty:pn,focus:yn},Et=8,bn=28,Pt=140,ne=(t,s,e)=>{var r;const n=(r=t[s])==null?void 0:r[e];return typeof n=="number"&&Number.isFinite(n)?n:null},se=t=>t.map((s,e)=>String(e)),gn=({label:t,description:s,columns:e,rows:n,values:r,valueLabel:u,tone:m="cat-1",height:d=280,width:k,formatValue:T,className:A,testId:I})=>{const{labels:M}=dt.useHanui(),[F,z]=yt(k),H=f.useMemo(()=>pt(M==null?void 0:M.locale),[M==null?void 0:M.locale]),q=T??H,P=`hanui-heat-${f.useId().replace(/:/g,"")}`,N=f.useMemo(()=>{const y={left:Math.min(z*.3,Math.max(32,...n.map(ht))+12),top:8,right:z-8,bottom:d-28-bn},a=Rt(se(e),[y.left,y.right],{paddingInner:.06,paddingOuter:0}),i=Rt(se(n),[y.top,y.bottom],{paddingInner:.06,paddingOuter:0}),[c,o]=xt(Ht(r.flat())),x=$=>$===null?null:o===c?60:Et+($-c)/(o-c)*(100-Et),_=n.flatMap(($,b)=>e.map((p,C)=>{const G=ne(r,b,C);return{row:$,column:p,key:`${b}:${C}`,value:G,x:a(String(C)),y:i(String(b)),width:a.bandwidth,height:i.bandwidth,mix:x(G)}}));return{area:y,x:a,y:i,cells:_,min:c,max:o}},[e,n,r,z,d]),R=U(m),E=f.useMemo(()=>{const{area:h,x:y,y:a,cells:i}=N,c=q(N.max),o=h.right-ht(c)-8,x=re(e.map((_,$)=>({position:y(String($))+y.bandwidth/2,label:_})));return l.jsxs("g",{children:[i.map(_=>l.jsx("rect",{className:_.mix===null?Tt.empty:void 0,x:_.x,y:_.y,width:_.width,height:_.height,rx:2,style:_.mix===null?void 0:{fill:`color-mix(in srgb, ${R} ${_.mix}%, var(--hanui-surface))`}},_.key)),l.jsxs("g",{"aria-hidden":!0,className:Tt.labels,children:[n.map((_,$)=>l.jsx("text",{x:h.left-8,y:a(String($))+a.bandwidth/2,dy:"0.32em",textAnchor:"end",children:St(_,h.left-12)},$)),x.map(_=>l.jsx("text",{x:_.position,y:h.bottom+16,textAnchor:"middle",children:_.label},_.position))]}),l.jsx("defs",{children:l.jsxs("linearGradient",{id:P,children:[l.jsx("stop",{offset:"0%",style:{stopColor:`color-mix(in srgb, ${R} ${Et}%, var(--hanui-surface))`}}),l.jsx("stop",{offset:"100%",style:{stopColor:R}})]})}),l.jsxs("g",{"aria-hidden":!0,className:Tt.labels,children:[l.jsx("rect",{x:o-Pt,y:d-18,width:Pt,height:8,rx:4,style:{fill:`url(#${P})`}}),l.jsx("text",{x:o-Pt-8,y:d-14,dy:"0.32em",textAnchor:"end",children:q(N.min)}),l.jsx("text",{x:h.right,y:d-14,dy:"0.32em",textAnchor:"end",children:c})]})]})},[N,e,n,R,P,d,q]),w=f.useCallback((h,y)=>{const{area:a,x:i,y:c}=N;if(h<a.left||h>a.right||y<a.top||y>a.bottom)return null;const o=i.indexAt(h),x=c.indexAt(y);return o<0||x<0?null:x*e.length+o},[N,e.length]),j=h=>{const y=N.cells[h];return{cell:y,value:y.value===null?"—":q(y.value)}};return l.jsx(ft,{label:t,description:s,containerRef:F,width:z,height:d,plot:E,overlay:h=>{const y=N.cells[h];return l.jsx("rect",{className:Tt.focus,x:y.x-1,y:y.y-1,width:y.width+2,height:y.height+2,rx:3})},itemCount:N.cells.length,columns:e.length,pick:w,tooltip:h=>{const{cell:y,value:a}=j(h);return{title:`${y.row} · ${y.column}`,rows:[{id:"value",label:u,value:a,tone:m}]}},anchor:h=>{const y=N.cells[h];return{x:y.x+y.width/2,y:y.y+y.height/2}},announce:h=>{const{cell:y,value:a}=j(h);return`${y.row}, ${y.column}: ${u} ${a}`},table:{columns:[t,...e],rows:n.map((h,y)=>[h,...e.map((a,i)=>{const c=ne(r,y,i);return c===null?"—":q(c)})])},className:A,testId:I})},Mn=f.memo(at(gn,"Heatmap")),_n="hanui-box-7zEQ-",wn="hanui-median-J5g6o",$n="hanui-outlier-M0VN-",jn="hanui-band-kK09D",It={box:_n,median:wn,outlier:$n,band:jn},kn=({label:t,description:s,groups:e,groupLabel:n,labels:r,height:u=280,width:m,formatValue:d,className:k,testId:T})=>{const{labels:A}=dt.useHanui(),[I,M]=yt(m),F=f.useMemo(()=>pt(A==null?void 0:A.locale),[A==null?void 0:A.locale]),z=f.useMemo(()=>At(A==null?void 0:A.locale),[A==null?void 0:A.locale]),H=d??F,q=f.useMemo(()=>e.map((w,j)=>({group:w,tone:vt(j,w.tone),stats:ge(w.values)})),[e]),P=f.useMemo(()=>{const w=q.flatMap(x=>x.stats?[x.stats.min,x.stats.max]:[]),[j,h]=w.length?xt(w):[0,1],y=$t(j,h),a=ot(y[0],y[1],Nt(u,!1)),i=Bt(M,u,a.map(z)),c=Rt(e.map(x=>x.id),[i.left,i.right],{paddingInner:.4,paddingOuter:.2}),o=mt(y,[i.bottom,i.top]);return{area:i,band:c,y:o,yTicks:a.map(x=>({position:o(x),label:z(x)})),groupTicks:e.map(x=>({position:c(x.id)+c.bandwidth/2,label:x.label}))}},[q,e,M,u,z]),N=w=>[{id:"max",label:r.max,value:H(w.whiskerHigh)},{id:"q3",label:r.q3,value:H(w.q3)},{id:"median",label:r.median,value:H(w.median)},{id:"q1",label:r.q1,value:H(w.q1)},{id:"min",label:r.min,value:H(w.whiskerLow)},...w.outliers.length>0?[{id:"outliers",label:r.outliers,value:F(w.outliers.length)}]:[],{id:"count",label:r.count,value:F(w.count)}],R=f.useMemo(()=>{const{area:w,band:j,y:h}=P;return l.jsxs("g",{children:[l.jsx(ut,{area:w,ticks:P.yTicks,side:"left",hasGrid:!0}),l.jsx(qt,{area:w,ticks:P.groupTicks,side:"bottom"}),q.map(({group:y,tone:a,stats:i})=>{if(!i)return null;const c=j(y.id),o=c+j.bandwidth/2,x=j.bandwidth*.3,_=U(a);return l.jsxs("g",{style:{stroke:_},className:It.box,children:[l.jsx("line",{x1:o,x2:o,y1:h(i.whiskerHigh),y2:h(i.q3)}),l.jsx("line",{x1:o,x2:o,y1:h(i.q1),y2:h(i.whiskerLow)}),l.jsx("line",{x1:o-x,x2:o+x,y1:h(i.whiskerHigh),y2:h(i.whiskerHigh)}),l.jsx("line",{x1:o-x,x2:o+x,y1:h(i.whiskerLow),y2:h(i.whiskerLow)}),l.jsx("rect",{x:c,width:j.bandwidth,y:h(i.q3),height:Math.max(1,h(i.q1)-h(i.q3)),rx:2,style:{fill:`color-mix(in srgb, ${_} 22%, transparent)`}}),l.jsx("line",{className:It.median,x1:c,x2:c+j.bandwidth,y1:h(i.median),y2:h(i.median)}),i.outliers.map(($,b)=>l.jsx("circle",{className:It.outlier,cx:o,cy:h($),r:3},b))]},y.id)})]})},[P,q]),E=f.useCallback((w,j)=>{const{area:h,band:y}=P;if(w<h.left||w>h.right||j<h.top-4||j>h.bottom+4)return null;const a=y.indexAt(w);return a<0?null:a},[P]);return l.jsx(ft,{label:t,description:s,containerRef:I,width:M,height:u,plot:R,underlay:w=>{const{area:j,band:h}=P,y=h.step*.2;return l.jsx("rect",{className:It.band,x:h(e[w].id)-y,width:h.bandwidth+y*2,y:j.top,height:j.height})},overlay:()=>null,itemCount:e.length,pick:E,tooltip:w=>{const j=q[w];return{title:j.group.label,rows:j.stats?N(j.stats).map(h=>({...h,tone:h.id==="median"?j.tone:void 0})):[]}},anchor:w=>{const j=q[w],{band:h,y}=P;return{x:h(j.group.id)+h.bandwidth/2,y:j.stats?y(j.stats.q3):P.area.bottom}},announce:w=>{const j=q[w];return j.stats?`${j.group.label}: ${N(j.stats).map(h=>`${h.label} ${h.value}`).join(", ")}`:j.group.label},table:{columns:[n,r.min,r.q1,r.median,r.q3,r.max,r.count],rows:q.map(({group:w,stats:j})=>j?[w.label,H(j.whiskerLow),H(j.q1),H(j.median),H(j.q3),H(j.whiskerHigh),F(j.count)]:[w.label,"—","—","—","—","—","0"])},className:k,testId:T})},Nn=f.memo(at(kn,"BoxPlot")),vn="hanui-baseline-wWs7h",An="hanui-band-xvYtL",oe={baseline:vn,band:An},Mt=1,Cn=({label:t,description:s,values:e,bins:n,valueLabel:r,countLabel:u,tone:m="cat-1",height:d=260,width:k,formatValue:T,className:A,testId:I})=>{const{labels:M}=dt.useHanui(),[F,z]=yt(k),H=f.useMemo(()=>pt(M==null?void 0:M.locale),[M==null?void 0:M.locale]),q=f.useMemo(()=>At(M==null?void 0:M.locale),[M==null?void 0:M.locale]),P=T??H,N=f.useMemo(()=>Me(e,n),[e,n]),R=f.useMemo(()=>{var $,b;const h=Math.max(1,...N.map(p=>p.count)),y=$t(0,h),a=ot(0,y[1],Nt(d,!1)).filter(Number.isInteger),i=Bt(z,d,a.map(q)),c=(($=N[0])==null?void 0:$.from)??0,o=((b=N[N.length-1])==null?void 0:b.to)??1,x=mt([c,o],[i.left,i.right]),_=mt(y,[i.bottom,i.top]);return{area:i,columns:N.map(p=>({x:x(p.from)+Mt/2,width:Math.max(1,x(p.to)-x(p.from)-Mt),y:_(p.count),height:Math.max(0,i.bottom-_(p.count)),center:(x(p.from)+x(p.to))/2})),xTicks:ot(c,o,Nt(i.width,!0)).map(p=>({position:x(p),label:q(p)})),yTicks:a.map(p=>({position:_(p),label:q(p)}))}},[N,z,d,q]),E=h=>`${P(N[h].from)} – ${P(N[h].to)}`,w=f.useMemo(()=>l.jsxs("g",{children:[l.jsx(ut,{area:R.area,ticks:R.yTicks,side:"left",hasGrid:!0}),l.jsx(ut,{area:R.area,ticks:R.xTicks,side:"bottom"}),l.jsx("line",{className:oe.baseline,x1:R.area.left,x2:R.area.right,y1:R.area.bottom,y2:R.area.bottom}),R.columns.map((h,y)=>h.height>0?l.jsx("rect",{x:h.x,y:h.y,width:h.width,height:h.height,style:{fill:U(m)}},y):null)]}),[R,m]),j=f.useCallback((h,y)=>{const{area:a,columns:i}=R;if(h<a.left||h>a.right||y<a.top-4||y>a.bottom+4)return null;const c=i.findIndex(o=>h>=o.x-Mt&&h<=o.x+o.width+Mt);return c<0?null:c},[R]);return l.jsx(ft,{label:t,description:s,containerRef:F,width:z,height:d,plot:w,underlay:h=>{const y=R.columns[h];return l.jsx("rect",{className:oe.band,x:y.x-Mt/2,width:y.width+Mt,y:R.area.top,height:R.area.height})},overlay:()=>null,itemCount:N.length,pick:j,tooltip:h=>({title:E(h),rows:[{id:"count",label:u,value:H(N[h].count),tone:m}]}),anchor:h=>({x:R.columns[h].center,y:R.columns[h].y}),announce:h=>`${r} ${E(h)}: ${u} ${H(N[h].count)}`,table:{columns:[r,u],rows:N.map((h,y)=>[E(y),H(h.count)])},className:A,testId:I})},Tn=f.memo(at(Cn,"Histogram")),In="hanui-grid-fHioN",Rn="hanui-shape-Vbb9D",Sn="hanui-labels-nRfEk",Fn="hanui-axisLabel-UOZQ7",Hn="hanui-spoke-P-6cp",Ln="hanui-marker-xzn9h",_t={grid:In,shape:Rn,labels:Sn,axisLabel:Fn,spoke:Hn,marker:Ln},ae=10,zn=16,En=28,Dt=(t,s)=>{const e=t.values[s];return typeof e=="number"&&Number.isFinite(e)?e:null},Pn=({label:t,description:s,axes:e,series:n,max:r,height:u=320,width:m,formatValue:d,className:k,testId:T})=>{const{labels:A}=dt.useHanui(),[I,M]=yt(m),[F,z]=f.useState(()=>new Set),H=f.useMemo(()=>At(A==null?void 0:A.locale),[A==null?void 0:A.locale]),q=f.useMemo(()=>pt(A==null?void 0:A.locale),[A==null?void 0:A.locale]),P=d??q,N=f.useMemo(()=>n.map((a,i)=>({...a,tone:vt(i,a.tone)})),[n]),R=f.useMemo(()=>N.filter(a=>!F.has(a.id)),[N,F]),E=f.useMemo(()=>{const a=e.length,i=a>0?Math.PI*2/a:0,c=e.map((V,Z)=>Z*i),o=Math.min(M*.22,Math.max(0,...e.map(V=>ht(V.label)))),x=Math.max(24,Math.min(u/2-24,M/2-o-ae-4)),_=M/2,$=u/2;let b=0;for(const V of n)for(const Z of e){const D=Dt(V,Z.key);D!==null&&D>b&&(b=D)}const p=r!==void 0&&r>0?r:$t(0,b,4)[1],C=ot(0,p,4).filter(V=>V>0);return{cx:_,cy:$,radius:x,angles:c,step:i,top:p,rings:C,scale:V=>Math.min(Math.max(V,0),p)/p*x,labelRoom:o}},[e,n,r,M,u]),w=f.useMemo(()=>{const{cx:a,cy:i,angles:c,scale:o}=E;return R.map(x=>({...x,points:e.map((_,$)=>{const b=Dt(x,_.key);return{...tt(a,i,o(b??0),c[$]),value:b}})}))},[E,R,e]),j=f.useMemo(()=>{const{cx:a,cy:i,radius:c,angles:o,rings:x,scale:_,labelRoom:$}=E,b=x.length>0?_(x[0]):c,p=Math.max(1,Math.ceil(zn/Math.max(1,b)));return l.jsxs("g",{children:[l.jsxs("g",{"aria-hidden":!0,className:_t.grid,children:[x.map(C=>l.jsx("path",{d:Yt(o.map(G=>tt(a,i,_(C),G)))},C)),o.map((C,G)=>{const V=tt(a,i,c,C);return l.jsx("line",{x1:a,y1:i,x2:V.x,y2:V.y},e[G].key)})]}),w.map(C=>l.jsx("path",{className:_t.shape,d:Yt(C.points),style:{fill:`color-mix(in srgb, ${U(C.tone)} 14%, transparent)`,stroke:U(C.tone)}},C.id)),l.jsxs("g",{"aria-hidden":!0,className:_t.labels,children:[x.map((C,G)=>(x.length-1-G)%p===0?l.jsx("text",{x:a+4,y:i-_(C),dy:"1.1em",children:H(C)},C):null),e.map((C,G)=>{const V=o[G],Z=tt(a,i,c+ae,V),D=Math.sin(V),g=Math.cos(V),S=D>.3?"start":D<-.3?"end":"middle",L=g>.3?"-0.2em":g<-.3?"0.9em":"0.32em";return l.jsx("text",{className:_t.axisLabel,x:Z.x,y:Z.y,dy:L,textAnchor:S,children:St(C.label,S==="middle"?c*1.4:$)},C.key)})]})]})},[E,w,e,H]),h=f.useCallback((a,i)=>{const{cx:c,cy:o,radius:x,step:_}=E;if(e.length===0||Math.hypot(a-c,i-o)>x+En)return null;let $=Math.atan2(a-c,-(i-o));return $<0&&($+=Math.PI*2),Math.round($/_)%e.length},[E,e.length]),y=a=>w.map(i=>{const c=i.points[a].value;return{id:i.id,label:i.label,value:c===null?"—":P(c),tone:i.tone}});return l.jsx(ft,{label:t,description:s,containerRef:I,width:M,height:u,plot:j,overlay:a=>{const{cx:i,cy:c,radius:o,angles:x}=E,_=tt(i,c,o,x[a]);return l.jsxs("g",{children:[l.jsx("line",{className:_t.spoke,x1:i,y1:c,x2:_.x,y2:_.y}),w.map($=>{const b=$.points[a];return b.value===null?null:l.jsx("circle",{className:_t.marker,cx:b.x,cy:b.y,r:4.5,style:{fill:U($.tone)}},$.id)})]})},itemCount:e.length,pick:h,tooltip:a=>({title:e[a].label,rows:y(a)}),anchor:a=>{const{cx:i,cy:c,radius:o,angles:x}=E;let _=0;for(const $ of w){const b=$.points[a];_=Math.max(_,Math.hypot(b.x-i,b.y-c))}return tt(i,c,Math.min(o,_),x[a])},tooltipSide:"outward",announce:a=>`${e[a].label}: ${y(a).map(i=>`${i.label} ${i.value}`).join(", ")}`,table:{columns:[t,...N.map(a=>a.label)],rows:e.map(a=>[a.label,...N.map(i=>{const c=Dt(i,a.key);return c===null?"—":P(c)})])},legend:N.length>1?{entries:N.map(a=>({id:a.id,label:a.label,tone:a.tone})),hidden:F,onToggle:a=>z(i=>{const c=new Set(i);return c.has(a)?c.delete(a):N.length-i.size>1&&c.add(a),c})}:void 0,className:k,testId:T})},Dn=f.memo(at(Pn,"RadarChart"));exports.AreaChart=Je;exports.BarChart=tn;exports.BoxPlot=Nn;exports.ComposedChart=nn;exports.Heatmap=Mn;exports.Histogram=Tn;exports.LineChart=Ue;exports.PieChart=rn;exports.RadarChart=Dn;exports.ScatterPlot=xn;
|
|
2
|
+
//# sourceMappingURL=charts.cjs.map
|