@xiriframework/xiri-ng 0.2.26 → 0.2.28

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.
@@ -0,0 +1,918 @@
1
+ # Components — xiri-ng Reference
2
+
3
+ Kompakt-Signaturen aller Komponenten die in `public-api.ts` exportiert werden. Inputs + Outputs mit Typen.
4
+
5
+ ## Form & Dialog
6
+
7
+ ### xiri-form
8
+
9
+ ```typescript
10
+ @input.required settings: XiriFormSettings;
11
+
12
+ interface XiriFormSettings {
13
+ load?: boolean; // Auto-load url im ngOnInit
14
+ url: string;
15
+ fields?: XiriFormField[]; // Init-Fields wenn load=false
16
+ buttons?: XiriButton[];
17
+ header?: string;
18
+ }
19
+ ```
20
+
21
+ Outputs: keine.
22
+
23
+ ### xiri-dialog (via MatDialog)
24
+
25
+ ```typescript
26
+ dialog.open(XiriDialogComponent, {
27
+ data: XiriDialogSettings,
28
+ });
29
+
30
+ interface XiriDialogSettings {
31
+ url?: string;
32
+ size?: string; // Default '600px'
33
+ type: 'form' | 'data' | 'question' | 'waiting' | 'table';
34
+ data?: any;
35
+ filter?: any;
36
+ }
37
+ ```
38
+
39
+ Bei `type: 'table'` wird der Backend-`content` (mit `data` + `fields`) direkt als `XiriRawTableSettings` an die eingebettete `xiri-raw-table` durchgereicht. Optionales `showHeader: true` im content (Backend: `dialog.Dialog.WithTableHeader()`) aktiviert die Spalten-Header-Zeile — Default aus.
40
+
41
+ ### xiri-query
42
+
43
+ ```typescript
44
+ @input.required settings: XiriQuerySettings;
45
+ @input dyncomponent: TemplateRef<any>;
46
+
47
+ interface XiriQuerySettings {
48
+ fields?: XiriFormField[];
49
+ dyn?: XiriDynData[]; // Initiale Komponenten (Results)
50
+ url?: string; // POST-URL bei Filter-Change
51
+ buttonline?: XiriDynData;
52
+ extra?: any;
53
+ saveState?: boolean;
54
+ saveStateId?: string;
55
+ collapsed?: boolean;
56
+ }
57
+
58
+ @output change: EventEmitter<any>; // debounced 300ms
59
+ ```
60
+
61
+ ### xiri-alert (via MatDialog)
62
+
63
+ ```typescript
64
+ dialog.open(XiriAlertComponent, {
65
+ data: { header: string; text: string; icon: string; buttons: XiriButton[] },
66
+ });
67
+ ```
68
+
69
+ ## Cards & Links
70
+
71
+ ### xiri-card
72
+
73
+ ```typescript
74
+ @input.required settings: XiriCardSettings;
75
+
76
+ interface XiriCardSettings {
77
+ url?: string; // POST mit null → Load
78
+ reload?: boolean;
79
+ data?: any;
80
+ fields?: XiriTableField[]; // Card als Mini-Table
81
+ components?: XiriDynData[]; // Multi-Component-Modus (xcol-Grid mit Sub-Components)
82
+ header?: string;
83
+ headerSub?: string;
84
+ headerIcon?: string;
85
+ headerIconColor?: XiriColor;
86
+ buttonsTop?: XiriButtonlineSettings;
87
+ buttonsBottom?: XiriButtonlineSettings;
88
+ dense?: number;
89
+ forceMinWidth?: boolean;
90
+ showHeader?: boolean; // Default false. Bei true zeigt die eingebettete
91
+ // xiri-raw-table die <thead>-Zeile mit Spalten-Headern.
92
+ // Backend setzt es via card.*Card.WithTableHeader().
93
+ collapsible?: boolean;
94
+ collapsed?: boolean;
95
+ maxHeight?: string;
96
+ padding?: string; // 'xs'|'sm'|'md'|'lg'|'xl' Token oder CSS-Wert.
97
+ // Wirkt nur im Multi-Component-Modus.
98
+ // Default 'md'. Auf xs-Viewport (<576px) immer 8px.
99
+ }
100
+ ```
101
+
102
+ **Render-Reihenfolge im Card-Body:**
103
+
104
+ 1. Wenn `components` befüllt ist → `<xiri-dyncomponent class="xrow">` (Multi-Component-Modus). Layout pro Sub-Component via `display: 'xcol-…'` auf jedem `XiriDynData`-Eintrag. Card-Header bleibt darüber. Beispiel:
105
+ ```ts
106
+ {
107
+ header: 'Activity', headerIcon: 'show_chart', headerIconColor: 'primary',
108
+ components: [
109
+ { type: 'barchart', mode: 'simple', display: 'xcol-12', data: { /* XiriBarChartSettings */ } },
110
+ { type: 'stat', display: 'xcol-6', data: { value: '18h', label: 'Today', compact: true } },
111
+ { type: 'stat', display: 'xcol-6', data: { value: '32h', label: 'Last 7 days', compact: true } },
112
+ ],
113
+ }
114
+ ```
115
+ 2. Sonst wenn `data` + `fields` vorhanden → bestehendes `xiri-raw-table`-Rendering (Mini-Table-Card).
116
+ 3. Sonst → bestehendes Content-Rendering.
117
+
118
+ Das **Vorhandensein** von `components` schaltet automatisch in den Multi-Component-Modus — kein eigener `cardType` nötig.
119
+
120
+ #### `compact?: boolean` auf Sub-Components
121
+
122
+ Die folgenden Components zeichnen sonst eine eigene `<mat-card>` mit Schatten — in einer `xiri-card` ergibt das einen Card-in-Card-Look. `compact: true` lässt die innere mat-card weg:
123
+
124
+ | Type | Settings-Interface | Wo |
125
+ | --- | --- | --- |
126
+ | `stat` | `XiriStatSettings.compact` | jede Stat-Verwendung |
127
+ | `barchart` | `XiriBarChartSettings.compact` | jede BarChart-Verwendung |
128
+ | `cardlink` | `XiriCardlinkSettings.compact` | jede Cardlink-Verwendung |
129
+ | `imagetext` | `XiriImagetextSettings.compact` | jede Imagetext-Verwendung |
130
+ | `infopoint` | `XiriInfopointSettings.compact` | jede InfoPoint-Verwendung |
131
+ | `links` | `XiriLinksSettings.compact` | jede Links-Verwendung |
132
+ | `multiprogress` | `XiriMultiprogressSettings.compact` | jede MultiProgress-Verwendung |
133
+
134
+ Implementierung pro Component: `[class.compact]` auf dem Host, `:host(.compact)`-Selectoren in SCSS (transparenter Background, kein Schatten, reduziertes Padding).
135
+
136
+ ### xiri-cardlink
137
+
138
+ ```typescript
139
+ @input.required settings: XiriCardlinkSettings;
140
+
141
+ interface XiriCardlinkSettings {
142
+ link: string;
143
+ icon?: string;
144
+ iconSet: string;
145
+ text?: string;
146
+ sub?: string;
147
+ compact?: boolean; // Skipt eigene mat-card-Hülle (nesting in xiri-card).
148
+ }
149
+ ```
150
+
151
+ ### xiri-links
152
+
153
+ ```typescript
154
+ @input.required settings: XiriLinksSettings;
155
+
156
+ interface XiriLinksSettings {
157
+ data: XiriButton[];
158
+ header?: string;
159
+ headerSub?: string;
160
+ headerIcon?: string;
161
+ headerIconColor?: XiriColor;
162
+ compact?: boolean; // Skipt eigene mat-card-Hülle (nesting in xiri-card).
163
+ }
164
+ ```
165
+
166
+ ## Buttons
167
+
168
+ ### xiri-button
169
+
170
+ ```typescript
171
+ @input.required button: XiriButton;
172
+ @input disabled: boolean = false;
173
+ @input filterData: any = undefined;
174
+ @input url: string = undefined; // Override button.url
175
+
176
+ @output result: EventEmitter<XiriButtonResult>;
177
+
178
+ interface XiriButtonResult {
179
+ button: XiriButton;
180
+ result: any;
181
+ done: boolean;
182
+ loading: boolean;
183
+ }
184
+ ```
185
+
186
+ **Custom-Payload (`button.data`):** Für `action: 'api'` und `action: 'download'` baut die Button-Komponente den POST-Body als `{ ...filterData, ...button.data }`. `data` ist `Record<string, any>`. Klassisches Beispiel: CSV-Download-Buttons des `xiri-go`-Tabellen-Builders setzen `data: { _csv: true }`, das Backend (`LoadFilterData`) erkennt das Flag und liefert CSV statt Web-JSON. Backend-Setter: `button.WithData(map[string]any{...})` (siehe xiri-go-expert).
187
+
188
+ ### xiri-buttonline
189
+
190
+ ```typescript
191
+ @input.required settings: XiriButtonlineSettings;
192
+ @input disabled: boolean = false;
193
+ @input filterData: any = undefined;
194
+
195
+ @output result: EventEmitter<XiriButtonResult>;
196
+
197
+ interface XiriButtonlineSettings {
198
+ buttons: XiriButton[];
199
+ class: string; // z.B. 'small'
200
+ }
201
+ ```
202
+
203
+ ### xiri-buttonstyle (interne Hilfskomponente)
204
+
205
+ ```typescript
206
+ @input.required button: XiriButton;
207
+ @input.required disabled: boolean;
208
+ @input loading: boolean = false;
209
+ ```
210
+
211
+ ### XiriButton
212
+
213
+ ```typescript
214
+ interface XiriButton {
215
+ text: string;
216
+ type: string; // 'raised' | 'flat' | 'fab' | 'icon' | 'stroked' | 'mini-fab' | …
217
+ action: string; // 'api' | 'dialog' | 'download' | 'link' | 'back' |
218
+ // 'close' | 'return' | 'menu' | …
219
+
220
+ default?: boolean;
221
+ url?: string;
222
+ hide?: boolean;
223
+ color?: XiriColor;
224
+ icon?: string;
225
+ iconColor?: XiriColor;
226
+ fontIcon?: string;
227
+ fontSet?: string;
228
+ class?: string;
229
+ hint?: string;
230
+ tabIndex?: number;
231
+ inline?: boolean;
232
+ disabled?: boolean;
233
+
234
+ data?: any;
235
+ target?: string;
236
+ loading?: boolean;
237
+ filename?: string;
238
+
239
+ // Send-Buttons (z.B. in Tables)
240
+ check?: any[];
241
+ send?: any[];
242
+
243
+ // action: 'menu'
244
+ menuItems?: {
245
+ action: string;
246
+ url?: string;
247
+ icon?: string;
248
+ color?: string;
249
+ text?: string;
250
+ data?: any;
251
+ }[];
252
+ }
253
+ ```
254
+
255
+ ## Wizard
256
+
257
+ ### xiri-stepper
258
+
259
+ ```typescript
260
+ @input.required settings: XiriStepperSettings;
261
+
262
+ interface XiriStepperSettings {
263
+ url?: string; // Default-URL für Steps
264
+ steps: XiriStepperStep[];
265
+ }
266
+
267
+ interface XiriStepperStep {
268
+ url?: string;
269
+ title: string;
270
+ fields: XiriFormField[];
271
+ data?: any;
272
+ extra?: any;
273
+ buttons: XiriButton[];
274
+ }
275
+ ```
276
+
277
+ ### xiri-done
278
+
279
+ Keine Inputs / Outputs. Zeigt ein Success-Checkmark-Icon.
280
+
281
+ ### xiri-error
282
+
283
+ ```typescript
284
+ @input.required text: string;
285
+ ```
286
+
287
+ ## Headers, Page-Header, Toolbar, Section, Divider
288
+
289
+ ### xiri-header
290
+
291
+ ```typescript
292
+ @input.required settings: XiriHeaderSettings;
293
+
294
+ interface XiriHeaderSettings {
295
+ text: string;
296
+ color: string;
297
+ size: string; // 'h1' | 'h2' | 'h3' | …
298
+ }
299
+ ```
300
+
301
+ ### xiri-page-header
302
+
303
+ ```typescript
304
+ @input.required settings: XiriPageHeaderSettings;
305
+
306
+ interface XiriPageHeaderSettings {
307
+ title: string;
308
+ subtitle?: string;
309
+ icon?: string;
310
+ iconColor?: string;
311
+ buttons?: XiriButtonlineSettings;
312
+ }
313
+ ```
314
+
315
+ ### xiri-toolbar
316
+
317
+ ```typescript
318
+ @input.required settings: XiriToolbarSettings;
319
+ @input filterData: any = undefined;
320
+
321
+ interface XiriToolbarSettings {
322
+ title?: string;
323
+ icon?: string;
324
+ search?: boolean | { placeholder?: string };
325
+ buttons?: XiriButtonlineSettings;
326
+ }
327
+
328
+ @output searchChanged: EventEmitter<string>;
329
+ ```
330
+
331
+ ### xiri-section
332
+
333
+ ```typescript
334
+ @input.required settings: XiriSectionSettings;
335
+ @input dyncomponent: TemplateRef<any>;
336
+
337
+ interface XiriSectionSettings {
338
+ title?: string;
339
+ subtitle?: string;
340
+ icon?: string;
341
+ iconColor?: string;
342
+ collapsible?: boolean;
343
+ collapsed?: boolean;
344
+ buttons?: XiriButtonlineSettings;
345
+ components?: XiriDynData[]; // rekursive Nested-Komponenten
346
+ }
347
+ ```
348
+
349
+ ### xiri-divider
350
+
351
+ ```typescript
352
+ @input.required settings: XiriDividerSettings;
353
+
354
+ interface XiriDividerSettings {
355
+ text?: string;
356
+ icon?: string;
357
+ spacing?: 'compact' | 'normal' | 'large';
358
+ }
359
+ ```
360
+
361
+ ## Listen, Infos, Fortschritt
362
+
363
+ ### xiri-list
364
+
365
+ ```typescript
366
+ @input.required settings: XiriListSettings;
367
+
368
+ interface XiriListSettings {
369
+ sections: XiriListSection[];
370
+ }
371
+
372
+ interface XiriListSection {
373
+ name: string;
374
+ data: XiriListItem[];
375
+ }
376
+
377
+ interface XiriListItem {
378
+ name: string;
379
+ info: string;
380
+ icon: string;
381
+ iconSet?: string;
382
+ iconColor: XiriColor;
383
+ url: string;
384
+ hasFavorite?: boolean;
385
+ isFavorite?: boolean;
386
+ favoriteUrl?: string;
387
+ favoriteHint?: string;
388
+ }
389
+ ```
390
+
391
+ ### xiri-infopoint
392
+
393
+ ```typescript
394
+ @input.required settings: XiriInfopointSettings;
395
+
396
+ interface XiriInfopointSettings {
397
+ text: string;
398
+ info: string;
399
+ url?: string;
400
+ urlParams?: object;
401
+ icon: string;
402
+ iconSet?: string;
403
+ iconColor: XiriColor;
404
+ dense?: boolean;
405
+ compact?: boolean; // Skipt eigene mat-card-Hülle (nesting in xiri-card).
406
+ }
407
+ ```
408
+
409
+ ### xiri-multiprogress
410
+
411
+ ```typescript
412
+ @input.required settings: XiriMultiprogressSettings;
413
+
414
+ interface XiriMultiprogressSettings {
415
+ data: XiriMultiprogressItem[];
416
+ header?: string;
417
+ headerIcon?: string;
418
+ headerIconColor?: XiriColor;
419
+ show?: number; // initiale Zahl sichtbarer Items
420
+ compact?: boolean; // Skipt eigene mat-card-Hülle (nesting in xiri-card).
421
+ }
422
+
423
+ interface XiriMultiprogressItem {
424
+ text: string;
425
+ value: string;
426
+ progress: number; // 0-100
427
+ color?: XiriColor;
428
+ }
429
+ ```
430
+
431
+ ### xiri-imagetext
432
+
433
+ ```typescript
434
+ @input.required settings: XiriImagetextSettings;
435
+
436
+ interface XiriImagetextSettings {
437
+ url: string;
438
+ info: string;
439
+ header?: string;
440
+ headerSub?: string;
441
+ headerIcon?: string;
442
+ headerIconColor?: XiriColor;
443
+ compact?: boolean; // Skipt eigene mat-card-Hülle (nesting in xiri-card).
444
+ }
445
+ ```
446
+
447
+ ## Search & Navigation
448
+
449
+ ### xiri-search
450
+
451
+ ```typescript
452
+ @input placeholder: string = '';
453
+ @input open: boolean = false;
454
+ @input reset: number = -1; // Trigger-Reset bei Änderung
455
+ @input escape: boolean = true;
456
+ @input focus: number = -1; // Trigger-Focus bei Änderung
457
+ @input text: string = '';
458
+
459
+ @output changed: EventEmitter<string>; // debounced 200ms
460
+ ```
461
+
462
+ ### xiri-sidenav
463
+
464
+ ```typescript
465
+ @input settings: XiriSidebarSettings;
466
+
467
+ interface XiriSidebarSettings {
468
+ prefix: string; // Route-Prefix zum Überspringen
469
+ fields: XiriNavigationField[];
470
+ }
471
+
472
+ interface XiriNavigationField {
473
+ name: string;
474
+ link?: string;
475
+ icon: string;
476
+ iconSet?: string;
477
+ extern?: string;
478
+ active?: boolean;
479
+ path?: string;
480
+ regex?: RegExp;
481
+ menu?: boolean;
482
+ showSubmenu?: boolean;
483
+ sub?: XiriNavigationField[];
484
+ }
485
+ ```
486
+
487
+ ### xiri-breadcrumb
488
+
489
+ ```typescript
490
+ @input.required settings: XiriBreadcrumbItem[];
491
+
492
+ interface XiriBreadcrumbItem {
493
+ label: string;
494
+ link?: string;
495
+ icon?: string;
496
+ extern?: boolean;
497
+ }
498
+ ```
499
+
500
+ ## Tabs & Expansion
501
+
502
+ ### xiri-tabs
503
+
504
+ ```typescript
505
+ @input.required settings: XiriTabsSettings;
506
+ @input filterData: any;
507
+ @input dyncomponent: TemplateRef<any>;
508
+
509
+ interface XiriTabsSettings {
510
+ tabs: XiriTabSettings[];
511
+ selectedIndex?: number;
512
+ dynamicHeight?: boolean;
513
+ animationDuration?: string;
514
+ lazy?: boolean; // Content erst bei tab-select
515
+ unload?: boolean; // Content bei deselect zerstören
516
+ headerPosition?: 'above' | 'below';
517
+ alignTabs?: 'start' | 'center' | 'end';
518
+ stretchTabs?: boolean;
519
+ }
520
+
521
+ interface XiriTabSettings {
522
+ label: string;
523
+ icon?: string;
524
+ disabled?: boolean;
525
+ data: XiriDynData[];
526
+ lazy?: boolean;
527
+ unload?: boolean;
528
+ }
529
+ ```
530
+
531
+ ### xiri-expansion
532
+
533
+ ```typescript
534
+ @input.required settings: XiriExpansionSettings;
535
+ @input filterData: any;
536
+ @input dyncomponent: TemplateRef<any>;
537
+
538
+ interface XiriExpansionSettings {
539
+ panels: XiriExpansionPanelSettings[];
540
+ multi?: boolean;
541
+ displayMode?: 'default' | 'flat';
542
+ togglePosition?: 'before' | 'after';
543
+ hideToggle?: boolean;
544
+ lazy?: boolean;
545
+ unload?: boolean;
546
+ }
547
+
548
+ interface XiriExpansionPanelSettings {
549
+ title: string;
550
+ description?: string;
551
+ icon?: string;
552
+ disabled?: boolean;
553
+ expanded?: boolean;
554
+ data: XiriDynData[];
555
+ lazy?: boolean;
556
+ unload?: boolean;
557
+ }
558
+ ```
559
+
560
+ ## Skeleton & Empty-State
561
+
562
+ ### xiri-skeleton
563
+
564
+ ```typescript
565
+ @input type: XiriSkeletonType = 'text';
566
+ // 'text' | 'circle' | 'rect' | 'table-row'
567
+
568
+ @input width: string = '100%';
569
+ @input height: string = '1em';
570
+ @input lines: number = 1;
571
+ @input columns: number = 4; // für 'table-row'
572
+ @input animate: boolean = true;
573
+ @input fill: boolean = false;
574
+ ```
575
+
576
+ ### xiri-empty-state
577
+
578
+ ```typescript
579
+ @input.required settings: XiriEmptyStateSettings;
580
+
581
+ interface XiriEmptyStateSettings {
582
+ icon?: string;
583
+ iconColor?: XiriColor;
584
+ title?: string;
585
+ description?: string;
586
+ button?: XiriButton;
587
+ }
588
+
589
+ @output buttonResult: EventEmitter<XiriButtonResult>;
590
+ ```
591
+
592
+ ## Stats & Timeline & Description-List
593
+
594
+ ### xiri-stat
595
+
596
+ ```typescript
597
+ @input.required settings: XiriStatSettings;
598
+
599
+ interface XiriStatSettings {
600
+ value: string | number;
601
+ label: string;
602
+ icon?: string;
603
+ iconColor?: XiriColor;
604
+ trend?: XiriStatTrend;
605
+ prefix?: string;
606
+ suffix?: string;
607
+ color?: XiriColor;
608
+ compact?: boolean; // Skipt eigene mat-card-Hülle, kleinere Schrift —
609
+ // für Stats die in einer äußeren Card geschachtelt sind
610
+ // (Card-in-Card-Look vermeiden).
611
+ }
612
+
613
+ interface XiriStatTrend {
614
+ value: number;
615
+ direction: 'up' | 'down' | 'neutral';
616
+ }
617
+ ```
618
+
619
+ ### xiri-stat-grid
620
+
621
+ ```typescript
622
+ @input.required settings: XiriStatGridSettings;
623
+
624
+ interface XiriStatGridSettings {
625
+ stats: XiriStatSettings[];
626
+ columns?: number;
627
+ title?: string;
628
+ }
629
+ ```
630
+
631
+ ### xiri-timeline
632
+
633
+ ```typescript
634
+ @input.required settings: XiriTimelineSettings;
635
+
636
+ interface XiriTimelineSettings {
637
+ items: XiriTimelineItem[];
638
+ orientation?: 'horizontal' | 'vertical';
639
+ }
640
+
641
+ interface XiriTimelineItem {
642
+ title: string;
643
+ description?: string;
644
+ datetime?: string;
645
+ icon?: string;
646
+ iconColor?: XiriColor;
647
+ }
648
+ ```
649
+
650
+ ### xiri-description-list
651
+
652
+ ```typescript
653
+ @input.required settings: XiriDescriptionListSettings;
654
+
655
+ interface XiriDescriptionListSettings {
656
+ items: XiriDescriptionListItem[];
657
+ columns?: 1 | 2 | 3;
658
+ layout?: 'horizontal' | 'stacked';
659
+ }
660
+
661
+ interface XiriDescriptionListItem {
662
+ label: string;
663
+ value: string;
664
+ icon?: string;
665
+ color?: string;
666
+ type?: 'text' | 'link' | 'html' | 'badge';
667
+ }
668
+ ```
669
+
670
+ ### xiri-barchart
671
+
672
+ ```typescript
673
+ @input mode: XiriBarChartMode = 'simple'; // 'simple' | 'stacked' | 'heatmap'
674
+ @input.required settings: XiriBarChartSettings;
675
+
676
+ interface XiriBarChartSettings {
677
+ title?: string;
678
+ yMin?: number;
679
+ yMax?: number;
680
+ color?: XiriColor; // Default-Farbe (simple/heatmap)
681
+ bars?: XiriBarChartBar[]; // simple + stacked
682
+ points?: XiriBarChartPoint[]; // heatmap
683
+ compact?: boolean; // Skipt eigene mat-card-Hülle (nesting in xiri-card).
684
+ }
685
+
686
+ interface XiriBarChartBar {
687
+ label: string; // Achsen-Label (kurz)
688
+ value?: number; // simple
689
+ segments?: XiriBarChartSegment[]; // stacked
690
+ name?: string; // optionaler Tooltip-Name (Vollbezeichnung)
691
+ }
692
+
693
+ interface XiriBarChartSegment {
694
+ value: number;
695
+ color?: XiriColor;
696
+ name?: string; // Tooltip-Name pro Segment ("Low strain" …)
697
+ }
698
+
699
+ interface XiriBarChartPoint {
700
+ time: number; // unix milliseconds
701
+ value: number;
702
+ name?: string; // optionaler Tooltip-Name (z. B. "Repeat #3")
703
+ }
704
+ ```
705
+
706
+ **Rendering:** Verwendet **echarts v6**. Die Library deklariert `echarts` als optionale `peerDependency` — Apps installieren `echarts` nur, wenn sie `xiri-barchart` (oder `type: 'barchart'`) verwenden. Der Component lädt echarts lazy via `await import('echarts')` (eigener Bundle-Chunk).
707
+
708
+ **Tooltip:** Pro Mode eigener Formatter. Wenn `bar.name` / `segment.name` / `point.name` gesetzt sind, erscheinen sie im Tooltip; sonst Fallback auf `label` bzw. echarts-Default. Demo-Pattern: `label: 'M', name: 'Monday'` → X-Achse zeigt "M", Tooltip zeigt "Monday".
709
+
710
+ **Resize:** intern via `ResizeObserver` — kein manuelles `resize()` nötig.
711
+
712
+ **Im dyncomponent:** `{ type: 'barchart', mode: 'stacked', data: XiriBarChartSettings }`.
713
+
714
+ ### xiri-linechart
715
+
716
+ ```typescript
717
+ @input.required settings: XiriLineChartSettings;
718
+
719
+ interface XiriLineChartSettings {
720
+ title?: string;
721
+ xLabels: string[];
722
+ lines: XiriLineChartLine[];
723
+ yMin?: number;
724
+ yMax?: number;
725
+ smooth?: boolean; // alle Linien als geglättete Kurve
726
+ compact?: boolean;
727
+ }
728
+
729
+ interface XiriLineChartLine {
730
+ name: string;
731
+ values: number[]; // Werte parallel zu xLabels
732
+ color?: XiriColor;
733
+ dashed?: boolean;
734
+ area?: boolean; // Fläche unter der Linie füllen
735
+ }
736
+ ```
737
+
738
+ Im dyncomponent: `{ type: 'linechart', data: XiriLineChartSettings }`.
739
+
740
+ ### xiri-piechart
741
+
742
+ ```typescript
743
+ @input.required settings: XiriPieChartSettings;
744
+
745
+ interface XiriPieChartSettings {
746
+ title?: string;
747
+ slices: XiriPieChartSlice[];
748
+ donut?: boolean; // Ring statt Pie
749
+ nightingale?: boolean; // Rose-Style: Slice-Radien skalieren mit Wert
750
+ nightingaleType?: 'radius' | 'area'; // Default 'radius'
751
+ compact?: boolean;
752
+ }
753
+
754
+ interface XiriPieChartSlice {
755
+ name: string;
756
+ value: number;
757
+ color?: XiriColor;
758
+ }
759
+ ```
760
+
761
+ Im dyncomponent: `{ type: 'piechart', data: XiriPieChartSettings }`.
762
+
763
+ ### xiri-gaugechart
764
+
765
+ ```typescript
766
+ @input.required settings: XiriGaugeChartSettings;
767
+
768
+ interface XiriGaugeChartSettings {
769
+ title?: string;
770
+ value: number;
771
+ min?: number; // Default 0
772
+ max?: number; // Default 100
773
+ color?: XiriColor;
774
+ label?: string; // Einheits-Label unter dem Wert ('%', 'GB', …)
775
+ compact?: boolean;
776
+ }
777
+ ```
778
+
779
+ Im dyncomponent: `{ type: 'gaugechart', data: XiriGaugeChartSettings }`.
780
+
781
+ ### xiri-heatmap
782
+
783
+ ```typescript
784
+ @input.required settings: XiriHeatmapSettings;
785
+
786
+ interface XiriHeatmapSettings {
787
+ title?: string;
788
+ xLabels: string[];
789
+ yLabels: string[];
790
+ cells: XiriHeatmapCell[]; // [{x: number, y: number, value: number}]
791
+ min?: number;
792
+ max?: number;
793
+ colorRange?: [string, string]; // CSS low → high (Default light → purple)
794
+ showValues?: boolean; // Werte in Zellen anzeigen
795
+ compact?: boolean;
796
+ }
797
+
798
+ interface XiriHeatmapCell { x: number; y: number; value: number; label?: string; }
799
+ ```
800
+
801
+ Im dyncomponent: `{ type: 'heatmap', data: XiriHeatmapSettings }`.
802
+
803
+ ### xiri-calendar
804
+
805
+ ```typescript
806
+ @input.required settings: XiriCalendarSettings;
807
+
808
+ interface XiriCalendarSettings {
809
+ title?: string;
810
+ range: string | [string, string]; // 'YYYY' oder ['YYYY-MM-DD', 'YYYY-MM-DD']
811
+ cells: XiriCalendarCell[]; // [{date: 'YYYY-MM-DD', value: number}]
812
+ min?: number;
813
+ max?: number;
814
+ colorRange?: [string, string]; // Default light-green → dark-green (GitHub-Style)
815
+ cellSize?: number; // px (Default 16, compact 12)
816
+ compact?: boolean;
817
+ }
818
+ ```
819
+
820
+ Im dyncomponent: `{ type: 'calendar', data: XiriCalendarSettings }`.
821
+
822
+ ### xiri-tree
823
+
824
+ ```typescript
825
+ @input.required settings: XiriTreeSettings;
826
+
827
+ interface XiriTreeSettings {
828
+ title?: string;
829
+ root: XiriTreeNode;
830
+ orient?: 'LR' | 'RL' | 'TB' | 'BT'; // Default 'LR'
831
+ layout?: 'orthogonal' | 'radial'; // Default 'orthogonal'
832
+ compact?: boolean;
833
+ }
834
+
835
+ interface XiriTreeNode {
836
+ name: string;
837
+ value?: number;
838
+ children?: XiriTreeNode[];
839
+ collapsed?: boolean; // initial eingeklappt
840
+ }
841
+ ```
842
+
843
+ Im dyncomponent: `{ type: 'tree', data: XiriTreeSettings }`.
844
+
845
+ ### xiri-sankey
846
+
847
+ ```typescript
848
+ @input.required settings: XiriSankeySettings;
849
+
850
+ interface XiriSankeySettings {
851
+ title?: string;
852
+ nodes: { name: string; color?: XiriColor }[];
853
+ links: { source: string; target: string; value: number }[];
854
+ orient?: 'horizontal' | 'vertical'; // Default 'horizontal'
855
+ compact?: boolean;
856
+ }
857
+ ```
858
+
859
+ Im dyncomponent: `{ type: 'sankey', data: XiriSankeySettings }`.
860
+
861
+ ### xiri-gantt
862
+
863
+ Echarts-Custom-Series-basierter Gantt. Zeiten in unix milliseconds.
864
+
865
+ ```typescript
866
+ @input.required settings: XiriGanttSettings;
867
+
868
+ interface XiriGanttSettings {
869
+ title?: string;
870
+ rows: string[]; // Y-Achsen-Kategorien (top-down)
871
+ tasks: XiriGanttTask[];
872
+ rangeStart?: number; // unix ms (optional X-Achsen-Range)
873
+ rangeEnd?: number;
874
+ compact?: boolean;
875
+ }
876
+
877
+ interface XiriGanttTask {
878
+ row: number; // Index in rows[]
879
+ name: string;
880
+ start: number; // unix ms
881
+ end: number; // unix ms
882
+ color?: XiriColor;
883
+ }
884
+ ```
885
+
886
+ Im dyncomponent: `{ type: 'gantt', data: XiriGanttSettings }`.
887
+
888
+ ### xiri-echarts-host (geteilte Basis)
889
+
890
+ Internes Plumbing für alle echarts-basierten Charts. Public exportiert, falls eigene Custom-Charts gebaut werden sollen.
891
+
892
+ ```typescript
893
+ @input.required option: any; // Vollständige echarts-Option
894
+ @input compact: boolean = false;
895
+ @input title?: string;
896
+ @input headerIcon?: string;
897
+ @input headerIconColor?: XiriColor;
898
+ @input chartHeight: string = '200px';
899
+ ```
900
+
901
+ Übernimmt: Lazy `await import('echarts')`, ResizeObserver, mat-card-Hülle (mit Compact-Modus = flat), Title-Header, Error-Display. Re-render via `effect` auf `option()`.
902
+
903
+ Eigenes Chart bauen:
904
+
905
+ ```typescript
906
+ @Component({
907
+ selector: 'app-my-chart',
908
+ template: `<xiri-echarts-host [option]="option()" [compact]="compact()" [title]="settings().title"/>`,
909
+ imports: [XiriEchartsHostComponent]
910
+ })
911
+ export class MyChart {
912
+ settings = input.required<MySettings>();
913
+ compact = computed(() => !!this.settings().compact);
914
+ option = computed(() => buildMyEchartsOption(this.settings(), this.compact()));
915
+ }
916
+ ```
917
+
918
+ Helper-Funktionen aus `lib/echarts/`: `resolveColor(token, fallback)` — XiriColor → CSS-Wert; `escapeHtml(s)` — für Tooltip-Strings.