@xiriframework/xiri-ng 0.2.26 → 0.2.27

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,277 @@
1
+ # Tables — xiri-ng Reference
2
+
3
+ Zwei Komponenten: `xiri-raw-table` (minimal) und `xiri-table` (voll — Paging, Sort, Search, Inline-Edit, Selection, Server-Side).
4
+
5
+ ## XiriRawTableComponent
6
+
7
+ ### Selector
8
+
9
+ `xiri-raw-table`
10
+
11
+ ### Inputs
12
+
13
+ ```typescript
14
+ @input.required settings: XiriRawTableSettings;
15
+
16
+ export interface XiriRawTableSettings {
17
+ data: any[]; // Zeilen
18
+ fields?: XiriTableField[]; // Spalten
19
+ dense?: number; // 6-12, CSS-Klasse 'dense-X'
20
+ forceMinWidth?: boolean;
21
+ showHeader?: boolean; // Default false. Bei true wird die <thead>-Zeile mit
22
+ // Spalten-Headern (column.header) gerendert.
23
+ }
24
+ ```
25
+
26
+ ### Outputs
27
+
28
+ Keine.
29
+
30
+ Kein Sorting, kein Paging, kein Editing. Nur Daten rendern.
31
+
32
+ **Header-Zeile standardmäßig aus.** Aufrufer (xiri-card, xiri-dialog) setzen `showHeader` aus dem Backend-Payload (xiri-go: `*Card.WithTableHeader()` bzw. `Dialog.WithTableHeader()`).
33
+
34
+ ## XiriTableComponent
35
+
36
+ ### Selector
37
+
38
+ `xiri-table`
39
+
40
+ ### Inputs
41
+
42
+ ```typescript
43
+ @input.required settings: XiriTableSettings;
44
+ @input filterData: any = undefined;
45
+ @input dyncomponent: TemplateRef<any> = undefined; // Custom-Cell-Rendering
46
+ ```
47
+
48
+ ### Outputs
49
+
50
+ ```typescript
51
+ @output clickedRow: EventEmitter<any>; // volles Row-Object
52
+ ```
53
+
54
+ ### Öffentliche Methoden
55
+
56
+ ```typescript
57
+ reload(): void
58
+ searchDo(text: string): void
59
+ selection: SelectionModel<any> // Checkbox-Selection (wenn options.select)
60
+ isAllSelected(): boolean
61
+ masterToggle(): void
62
+
63
+ // Inline-Edit
64
+ startInlineEdit(row: any, column: XiriTableField, skipSavingCheck?: boolean): void
65
+ cancelInlineEdit(): void
66
+ saveInlineEdit(row: any, column: XiriTableField): void
67
+ isEditing(row: any, fieldId: string): boolean
68
+ isSaving(row: any, fieldId: string): boolean
69
+ ```
70
+
71
+ ### XiriTableSettings
72
+
73
+ ```typescript
74
+ export interface XiriTableSettings {
75
+ url?: string; // API-Endpoint (POST mit filterData-payload)
76
+ data?: any[]; // Alternative zu url — statische Daten
77
+ fields?: XiriTableField[];
78
+ options?: XiriTableOptions;
79
+ hasFilter?: boolean; // True wenn filterData extern gesetzt
80
+ }
81
+ ```
82
+
83
+ ### XiriTableOptions
84
+
85
+ ```typescript
86
+ export interface XiriTableOptions {
87
+ reload?: boolean;
88
+ dense?: boolean;
89
+ sort?: boolean = true;
90
+ search?: boolean = true;
91
+ class?: string;
92
+
93
+ pagination?: boolean = true;
94
+ itemsPerPage?: number = 50;
95
+ pageSizes?: number[] = [10, 25, 50, 100, 500];
96
+
97
+ select?: boolean; // Checkbox für Row-Selection
98
+ selectButtons?: XiriButton[]; // Buttons die auf Selection wirken
99
+
100
+ title?: string;
101
+ textNoData?: string = 'no data found';
102
+ emptyState?: XiriTableEmptyState;
103
+
104
+ buttons?: XiriButtonlineSettings; // Action-Buttons über der Tabelle
105
+
106
+ minWidth?: string;
107
+ scrollHeight?: string;
108
+
109
+ saveState?: boolean = false; // Persist in SessionStorage
110
+ saveStateId?: string;
111
+
112
+ // Inline-Edit
113
+ saveInput?: string;
114
+ saveInputUrl?: string;
115
+ editUrl?: string; // POST-URL für Inline-Edit-Save
116
+
117
+ borders?: boolean;
118
+ bordersHeader?: boolean;
119
+ footer?: boolean; // Footer-Row mit count/sum/static
120
+
121
+ serverSide?: boolean; // Paging/Sort/Search serverseitig
122
+ }
123
+ ```
124
+
125
+ ### XiriTableField
126
+
127
+ ```typescript
128
+ export interface XiriTableField {
129
+ id: string;
130
+ name: string;
131
+ format?: string; // 'text' | 'number' | 'html' | 'icon' | 'button' | 'chips' | ...
132
+ search?: boolean;
133
+ sort?: boolean;
134
+
135
+ buttons?: XiriButton[]; // Action-Buttons in der Zelle
136
+ icons?: { icon: string; color?: string; hint?: string }[];
137
+
138
+ display?: string; // CSS-Klasse auf <td>
139
+ header?: string; // Custom Header-Text (falls ≠ name)
140
+ sticky?: boolean;
141
+
142
+ // Inline-Edit
143
+ inputType?: string;
144
+ inputRequired?: boolean;
145
+ inputLang?: string;
146
+ inputPaste?: boolean;
147
+
148
+ // Formatierung
149
+ textPrefix?: string;
150
+ textSuffix?: string;
151
+ width?: string;
152
+ minWidth?: string;
153
+
154
+ hide?: boolean;
155
+ headerSpan?: number; // colspan für Header-Gruppen
156
+
157
+ align?: 'left' | 'center' | 'right';
158
+ footer?: 'no' | 'count' | 'sum' | 'static';
159
+ webformat?: string; // 'integer' | 'float1'-'float4'
160
+
161
+ editable?: boolean;
162
+ editableOptions?: { value: string; label: string; color?: string }[];
163
+ editableOptionsUrl?: string;
164
+ }
165
+ ```
166
+
167
+ ### Chips-Format (Status-Tags pro Zelle)
168
+
169
+ `format: 'chips'` rendert pro Zelle ein Array farbiger Pills. Der Cell-Wert ist `Array<{label: string, color?: XiriColor}>`. Single-Value-Spalten liefern ein 1-elementiges Array (z. B. `[{ label: '45%', color: 'red' }]`).
170
+
171
+ ```typescript
172
+ fields: [
173
+ { id: 'state', name: 'State', format: 'chips' },
174
+ { id: 'metric', name: 'Battery', format: 'chips' },
175
+ { id: 'tags', name: 'Tags', format: 'chips' },
176
+ ],
177
+ data: [
178
+ { id: 1,
179
+ state: [ { label: 'Attention', color: 'warn' } ],
180
+ metric: [ { label: '45%', color: 'red' } ],
181
+ tags: [ { label: 'Frontend', color: 'primary' },
182
+ { label: 'Angular', color: 'emerald' } ] },
183
+ ]
184
+ ```
185
+
186
+ CSS-Klasse pro Chip: `.xiri-chip-display.<color>` (z. B. `.xiri-chip-display.red`). Theme-Farben (`primary`/`accent`/`warn`/…) und Extended-Farben (`red`/`green`/`yellow`/`gray`/…) werden vom Theming bereitgestellt.
187
+
188
+ **Editierbar (Multi-Select-Chips):** zusätzlich `editable: true` + `editableOptions` (oder `editableOptionsUrl`) auf dem Field — der Inline-Editor öffnet einen Multi-Select. Der Cell-Wert beim Edit-Save ist das Array der ausgewählten Labels.
189
+
190
+ **Backend-Pendant in xiri-go:** `b.ChipsField(id, name, accessor)` wo `accessor func(T) []table.Chip` (siehe `xiri-go-expert references/table-builder.md`).
191
+
192
+ ## Server-Side-Pagination — Flow
193
+
194
+ Wenn `options.serverSide: true`, postet die Tabelle bei jeder Änderung (Sort/Filter/Page) an `settings.url` mit Payload:
195
+
196
+ ```json
197
+ {
198
+ "pageIndex": 0,
199
+ "pageSize": 50,
200
+ "sortBy": "name",
201
+ "sortDir": "asc",
202
+ "search": "foo",
203
+ "filter": { ... filterData ... }
204
+ }
205
+ ```
206
+
207
+ Erwartete Response:
208
+
209
+ ```typescript
210
+ {
211
+ data: any[];
212
+ total: number;
213
+ }
214
+ ```
215
+
216
+ ## Beispiel — voll konfigurierte Tabelle
217
+
218
+ ```typescript
219
+ tableSettings: XiriTableSettings = {
220
+ url: '/api/devices',
221
+ options: {
222
+ serverSide: true,
223
+ pagination: true,
224
+ itemsPerPage: 50,
225
+ sort: true,
226
+ search: true,
227
+ saveState: true,
228
+ saveStateId: 'devices-table',
229
+ select: true,
230
+ selectButtons: [
231
+ { text: 'Löschen', type: 'raised', color: 'warn',
232
+ action: 'api', url: '/api/devices/bulk-delete' },
233
+ ],
234
+ editUrl: '/api/devices/inline-edit',
235
+ footer: true,
236
+ buttons: {
237
+ class: 'small',
238
+ buttons: [
239
+ { text: 'Neu', type: 'raised', color: 'primary',
240
+ action: 'dialog', url: '/api/devices/add' },
241
+ ],
242
+ },
243
+ },
244
+ fields: [
245
+ { id: 'id', name: 'ID', format: 'number', sticky: true, width: '80px' },
246
+ { id: 'name', name: 'Name', search: true, sort: true },
247
+ { id: 'status', name: 'Status', format: 'icon',
248
+ icons: [
249
+ { icon: 'check_circle', color: 'success', hint: 'Aktiv' },
250
+ { icon: 'cancel', color: 'warn', hint: 'Inaktiv' },
251
+ ]},
252
+ { id: 'count', name: 'Anzahl', format: 'number',
253
+ webformat: 'integer', align: 'right', footer: 'sum' },
254
+ { id: 'note', name: 'Notiz', editable: true, inputType: 'text' },
255
+ { id: 'actions', name: '', format: 'button',
256
+ buttons: [
257
+ { text: '', type: 'icon', icon: 'edit',
258
+ action: 'dialog', url: '/api/devices/edit' },
259
+ { text: '', type: 'icon', icon: 'delete', color: 'warn',
260
+ action: 'dialog', url: '/api/devices/delete' },
261
+ ]},
262
+ ],
263
+ };
264
+ ```
265
+
266
+ ## Reload nach Edit
267
+
268
+ ```typescript
269
+ @ViewChild(XiriTableComponent) table!: XiriTableComponent;
270
+
271
+ onButtonResult(res: XiriButtonResult) {
272
+ this.responseHandler.handle(res.result, {
273
+ onTableRefresh: () => this.table.reload(),
274
+ onTableUpdate: (id, field, content) => { /* optimistic UI */ },
275
+ });
276
+ }
277
+ ```
@@ -0,0 +1,120 @@
1
+ # Theming, Colors & i18n — xiri-ng Reference
2
+
3
+ ## Farben
4
+
5
+ ```typescript
6
+ export type XiriThemeColor =
7
+ | 'primary' | 'secondary' | 'tertiary' | 'accent'
8
+ | 'warn' | 'error' | 'success';
9
+
10
+ export type XiriExtendedColor =
11
+ | 'emerald' | 'red' | 'yellow' | 'green' | 'blue' | 'purple'
12
+ | 'gray' | 'lightgray' | 'darkgray' | 'orange'
13
+ | 'white' | 'black' | 'inherit';
14
+
15
+ export type XiriColor = XiriThemeColor | XiriExtendedColor;
16
+ ```
17
+
18
+ Wird in fast allen Settings-Interfaces genutzt (`iconColor`, `color`, `headerIconColor`). Für Backend-JSON: als String serialisiert (z.B. `"primary"`, `"warn"`).
19
+
20
+ ## ThemeService
21
+
22
+ ```typescript
23
+ import { ThemeService } from '@xiriframework/xiri-ng';
24
+
25
+ private theme = inject(ThemeService);
26
+
27
+ theme.mode // Signal<'light' | 'dark' | 'auto'>
28
+ theme.isDark // computed Signal<boolean>
29
+ theme.isLight // computed Signal<boolean>
30
+
31
+ theme.setTheme('dark' | 'light' | 'auto'); // persistiert in localStorage
32
+ theme.toggle(); // light ↔ dark
33
+ theme.resetToAuto(); // folgt System-Präferenz
34
+ ```
35
+
36
+ Typischer Toolbar-Toggle:
37
+
38
+ ```typescript
39
+ @Component({ ... })
40
+ export class HeaderComponent {
41
+ private theme = inject(ThemeService);
42
+ isDark = this.theme.isDark;
43
+ toggle() { this.theme.toggle(); }
44
+ }
45
+ ```
46
+
47
+ ## Material-Design-3 Theming
48
+
49
+ xiri-ng setzt auf Angular Material 3 mit SCSS-Theme-Konfiguration im konsumierenden Projekt. Typisches Setup:
50
+
51
+ ```scss
52
+ // src/styles.scss
53
+ @use '@angular/material' as mat;
54
+
55
+ html {
56
+ @include mat.theme((
57
+ color: (
58
+ primary: mat.$azure-palette,
59
+ tertiary: mat.$blue-palette,
60
+ ),
61
+ typography: Roboto,
62
+ density: 0,
63
+ ));
64
+ }
65
+
66
+ // Dark-Mode via ThemeService's 'dark'-Klasse auf <body>
67
+ body.dark {
68
+ color-scheme: dark;
69
+ }
70
+ ```
71
+
72
+ Die Komponenten nutzen `mat.*-theme` Tokens — kein Hart-kodiertes CSS.
73
+
74
+ ## Locale & Sprache
75
+
76
+ Backend (`xiri-go`) schickt `UiContext` mit Locale/Timezone pro Response. Frontend propagiert das an `XiriDateService` und `XiriNumberService`:
77
+
78
+ ```typescript
79
+ // z.B. in einem auth-response-handler:
80
+ import { de } from 'date-fns/locale';
81
+
82
+ this.date.setLocale('de-DE', de);
83
+ this.date.setTimezone('Europe/Vienna');
84
+ this.number.setLocale('de-DE');
85
+ ```
86
+
87
+ ### Date-Format-Helper
88
+
89
+ ```typescript
90
+ date.unixToStringDateTime(1708800000) // '2024-02-24 18:00'
91
+ date.unixToStringDate(1708800000) // '24. Feb.'
92
+ date.unixToStringDateYear(1708800000) // '24. Feb. 24'
93
+ date.unixToLocal(1708800000) // Date-Objekt oder null
94
+ date.dateToUnix(new Date()) // number
95
+ ```
96
+
97
+ ### Number-Format-Helper
98
+
99
+ ```typescript
100
+ number.formatNumber(1234.567, 'integer') // '1.235'
101
+ number.formatNumber(1234.567, 'float2') // '1.234,57'
102
+ number.formatNumber(1234.567, 'float4') // '1.234,5670'
103
+ ```
104
+
105
+ ## SafehtmlPipe
106
+
107
+ ```html
108
+ {{ htmlString | safeHtml }}
109
+ ```
110
+
111
+ Nur verwenden wenn der HTML-String vertrauenswürdig ist (nicht aus User-Input). Umgeht Angulars DomSanitizer.
112
+
113
+ ## Conventions im Library-Code
114
+
115
+ - Alle Komponenten: **standalone**, `OnPush`, kebab-case-Selector mit `xiri-`-Prefix
116
+ - Alle Directives: camelCase-Selector (z.B. `[xiriSelect]`)
117
+ - Signals für State, `input()`/`output()` für Komponenten-API
118
+ - `UntypedFormGroup` für dynamisch konstruierte Forms (Field-Liste aus JSON)
119
+ - `Observable` für HTTP, keine Promises
120
+ - Kein NgModule — niemand importiert xiri-ng als Modul