@konce-pt/angular 0.6.1 → 0.7.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/CHANGELOG.md +384 -0
  2. package/README.md +38 -19
  3. package/fesm2022/konce-pt-angular-charts.mjs +1409 -0
  4. package/fesm2022/konce-pt-angular-charts.mjs.map +1 -0
  5. package/fesm2022/konce-pt-angular-grid.mjs +232 -0
  6. package/{dist/fesm2022 → fesm2022}/konce-pt-angular-grid.mjs.map +1 -1
  7. package/fesm2022/konce-pt-angular-map.mjs +4568 -0
  8. package/fesm2022/konce-pt-angular-map.mjs.map +1 -0
  9. package/fesm2022/konce-pt-angular-roadmap.mjs +1919 -0
  10. package/fesm2022/konce-pt-angular-roadmap.mjs.map +1 -0
  11. package/fesm2022/konce-pt-angular.mjs +12307 -0
  12. package/fesm2022/konce-pt-angular.mjs.map +1 -0
  13. package/map/src/lib/llms.txt +741 -0
  14. package/package.json +44 -54
  15. package/roadmap/src/lib/llms.txt +112 -0
  16. package/src/lib/app-shell/llms.txt +89 -0
  17. package/src/lib/breakpoint/llms.txt +45 -0
  18. package/{dist/src → src}/lib/datepicker/llms.txt +3 -0
  19. package/src/lib/dialog/llms.txt +68 -0
  20. package/{dist/src → src}/lib/form-field/llms.txt +24 -1
  21. package/{dist/src → src}/lib/icon/llms.txt +2 -1
  22. package/{dist/src → src}/lib/input/llms.txt +14 -4
  23. package/src/lib/input-number/llms.txt +61 -0
  24. package/{dist/src → src}/lib/select/llms.txt +9 -0
  25. package/src/lib/sidenav/llms.txt +29 -0
  26. package/src/lib/toolbar/llms.txt +31 -0
  27. package/src/lib/tooltip/llms.txt +33 -0
  28. package/{dist/types → types}/konce-pt-angular-charts.d.ts +1 -0
  29. package/types/konce-pt-angular-charts.d.ts.map +1 -0
  30. package/{dist/types → types}/konce-pt-angular-grid.d.ts +1 -0
  31. package/types/konce-pt-angular-grid.d.ts.map +1 -0
  32. package/{dist/types → types}/konce-pt-angular-icons.d.ts +1 -0
  33. package/types/konce-pt-angular-icons.d.ts.map +1 -0
  34. package/types/konce-pt-angular-map.d.ts +1585 -0
  35. package/types/konce-pt-angular-map.d.ts.map +1 -0
  36. package/types/konce-pt-angular-roadmap.d.ts +649 -0
  37. package/types/konce-pt-angular-roadmap.d.ts.map +1 -0
  38. package/{dist/types → types}/konce-pt-angular.d.ts +373 -23
  39. package/types/konce-pt-angular.d.ts.map +1 -0
  40. package/dist/LICENSE +0 -21
  41. package/dist/README.md +0 -316
  42. package/dist/fesm2022/konce-pt-angular-charts.mjs +0 -957
  43. package/dist/fesm2022/konce-pt-angular-charts.mjs.map +0 -1
  44. package/dist/fesm2022/konce-pt-angular-grid.mjs +0 -218
  45. package/dist/fesm2022/konce-pt-angular.mjs +0 -8462
  46. package/dist/fesm2022/konce-pt-angular.mjs.map +0 -1
  47. package/dist/package.json +0 -79
  48. package/dist/src/lib/app-shell/llms.txt +0 -29
  49. package/dist/src/lib/dialog/llms.txt +0 -27
  50. package/dist/src/lib/input-number/llms.txt +0 -17
  51. package/dist/src/lib/sidenav/llms.txt +0 -20
  52. package/dist/src/lib/toolbar/llms.txt +0 -23
  53. package/dist/src/lib/tooltip/llms.txt +0 -19
  54. /package/{dist/charts → charts}/src/lib/llms.txt +0 -0
  55. /package/{dist/fesm2022 → fesm2022}/konce-pt-angular-icons.mjs +0 -0
  56. /package/{dist/fesm2022 → fesm2022}/konce-pt-angular-icons.mjs.map +0 -0
  57. /package/{dist/grid → grid}/src/lib/llms.txt +0 -0
  58. /package/{dist/src → src}/lib/accordion/llms.txt +0 -0
  59. /package/{dist/src → src}/lib/alert/llms.txt +0 -0
  60. /package/{dist/src → src}/lib/autocomplete/llms.txt +0 -0
  61. /package/{dist/src → src}/lib/avatar/llms.txt +0 -0
  62. /package/{dist/src → src}/lib/avatar-group/llms.txt +0 -0
  63. /package/{dist/src → src}/lib/badge/llms.txt +0 -0
  64. /package/{dist/src → src}/lib/bottom-sheet/llms.txt +0 -0
  65. /package/{dist/src → src}/lib/breadcrumb/llms.txt +0 -0
  66. /package/{dist/src → src}/lib/button/llms.txt +0 -0
  67. /package/{dist/src → src}/lib/button-group/llms.txt +0 -0
  68. /package/{dist/src → src}/lib/card/llms.txt +0 -0
  69. /package/{dist/src → src}/lib/carousel/llms.txt +0 -0
  70. /package/{dist/src → src}/lib/checkbox/llms.txt +0 -0
  71. /package/{dist/src → src}/lib/chip/llms.txt +0 -0
  72. /package/{dist/src → src}/lib/chips-input/llms.txt +0 -0
  73. /package/{dist/src → src}/lib/color-picker/llms.txt +0 -0
  74. /package/{dist/src → src}/lib/confirm/llms.txt +0 -0
  75. /package/{dist/src → src}/lib/context-menu/llms.txt +0 -0
  76. /package/{dist/src → src}/lib/data-table/llms.txt +0 -0
  77. /package/{dist/src → src}/lib/data-view/llms.txt +0 -0
  78. /package/{dist/src → src}/lib/date-range/llms.txt +0 -0
  79. /package/{dist/src → src}/lib/divider/llms.txt +0 -0
  80. /package/{dist/src → src}/lib/drawer/llms.txt +0 -0
  81. /package/{dist/src → src}/lib/empty/llms.txt +0 -0
  82. /package/{dist/src → src}/lib/fab/llms.txt +0 -0
  83. /package/{dist/src → src}/lib/fieldset/llms.txt +0 -0
  84. /package/{dist/src → src}/lib/file-upload/llms.txt +0 -0
  85. /package/{dist/src → src}/lib/galleria/llms.txt +0 -0
  86. /package/{dist/src → src}/lib/i18n/llms.txt +0 -0
  87. /package/{dist/src → src}/lib/icon-button/llms.txt +0 -0
  88. /package/{dist/src → src}/lib/image/llms.txt +0 -0
  89. /package/{dist/src → src}/lib/input-mask/llms.txt +0 -0
  90. /package/{dist/src → src}/lib/input-otp/llms.txt +0 -0
  91. /package/{dist/src → src}/lib/knob/llms.txt +0 -0
  92. /package/{dist/src → src}/lib/listbox/llms.txt +0 -0
  93. /package/{dist/src → src}/lib/megamenu/llms.txt +0 -0
  94. /package/{dist/src → src}/lib/menu/llms.txt +0 -0
  95. /package/{dist/src → src}/lib/menubar/llms.txt +0 -0
  96. /package/{dist/src → src}/lib/meter-group/llms.txt +0 -0
  97. /package/{dist/src → src}/lib/order-list/llms.txt +0 -0
  98. /package/{dist/src → src}/lib/paginator/llms.txt +0 -0
  99. /package/{dist/src → src}/lib/panel/llms.txt +0 -0
  100. /package/{dist/src → src}/lib/password/llms.txt +0 -0
  101. /package/{dist/src → src}/lib/pick-list/llms.txt +0 -0
  102. /package/{dist/src → src}/lib/popover/llms.txt +0 -0
  103. /package/{dist/src → src}/lib/progress/llms.txt +0 -0
  104. /package/{dist/src → src}/lib/radio-group/llms.txt +0 -0
  105. /package/{dist/src → src}/lib/rating/llms.txt +0 -0
  106. /package/{dist/src → src}/lib/rich-text/llms.txt +0 -0
  107. /package/{dist/src → src}/lib/scroll-top/llms.txt +0 -0
  108. /package/{dist/src → src}/lib/skeleton/llms.txt +0 -0
  109. /package/{dist/src → src}/lib/slider/llms.txt +0 -0
  110. /package/{dist/src → src}/lib/speed-dial/llms.txt +0 -0
  111. /package/{dist/src → src}/lib/spinner/llms.txt +0 -0
  112. /package/{dist/src → src}/lib/split-button/llms.txt +0 -0
  113. /package/{dist/src → src}/lib/splitter/llms.txt +0 -0
  114. /package/{dist/src → src}/lib/stepper/llms.txt +0 -0
  115. /package/{dist/src → src}/lib/switch/llms.txt +0 -0
  116. /package/{dist/src → src}/lib/switch-group/llms.txt +0 -0
  117. /package/{dist/src → src}/lib/tabs/llms.txt +0 -0
  118. /package/{dist/src → src}/lib/textarea/llms.txt +0 -0
  119. /package/{dist/src → src}/lib/timeline/llms.txt +0 -0
  120. /package/{dist/src → src}/lib/toast/llms.txt +0 -0
  121. /package/{dist/src → src}/lib/tree/llms.txt +0 -0
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@konce-pt/angular",
3
- "version": "0.6.1",
3
+ "version": "0.7.5",
4
4
  "description": "Open-source Angular 22 component library on Signals & Signal Forms — 70+ components, rich data table, zoneless, fully tokenized. Selektory kpt-*, klasy Kpt*.",
5
5
  "license": "MIT",
6
6
  "author": "konce.pt",
7
- "homepage": "https://gitlab.com/konce-pt/koncept-ui#readme",
7
+ "homepage": "https://ui.konce.pt/",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "git+https://gitlab.com/konce-pt/koncept-ui.git",
@@ -26,68 +26,58 @@
26
26
  "cdk",
27
27
  "data-table",
28
28
  "kpt",
29
- "koncept-ui"
29
+ "koncept-ui",
30
+ "map",
31
+ "leaflet",
32
+ "openstreetmap"
30
33
  ],
31
34
  "sideEffects": false,
32
- "files": [
33
- "dist"
34
- ],
35
- "module": "./dist/fesm2022/konce-pt-angular.mjs",
36
- "types": "./dist/types/konce-pt-angular.d.ts",
37
- "exports": {
38
- ".": {
39
- "types": "./dist/types/konce-pt-angular.d.ts",
40
- "default": "./dist/fesm2022/konce-pt-angular.mjs"
41
- },
42
- "./icons": {
43
- "types": "./dist/types/konce-pt-angular-icons.d.ts",
44
- "default": "./dist/fesm2022/konce-pt-angular-icons.mjs"
45
- },
46
- "./charts": {
47
- "types": "./dist/types/konce-pt-angular-charts.d.ts",
48
- "default": "./dist/fesm2022/konce-pt-angular-charts.mjs"
49
- },
50
- "./grid": {
51
- "types": "./dist/types/konce-pt-angular-grid.d.ts",
52
- "default": "./dist/fesm2022/konce-pt-angular-grid.mjs"
53
- }
54
- },
55
35
  "peerDependencies": {
56
36
  "@angular/cdk": "^22.0.0",
57
37
  "@angular/common": "^22.0.0",
58
38
  "@angular/core": "^22.0.0",
59
- "@angular/forms": "^22.0.0"
39
+ "@angular/forms": "^22.0.0",
40
+ "leaflet": "^1.9.0"
41
+ },
42
+ "peerDependenciesMeta": {
43
+ "leaflet": {
44
+ "optional": true
45
+ }
60
46
  },
61
47
  "dependencies": {
62
48
  "tslib": "^2.3.0"
63
49
  },
64
- "devDependencies": {
65
- "@angular/cdk": "22.1.0",
66
- "@angular/common": "22.1.0",
67
- "@angular/compiler": "22.1.0",
68
- "@angular/compiler-cli": "22.1.0",
69
- "@angular/core": "22.1.0",
70
- "@angular/forms": "22.1.0",
71
- "@storybook/angular": "10.5.6",
72
- "@tabler/icons": "^3.46.0",
73
- "ng-packagr": "22.1.0",
74
- "rxjs": "^7.8.0",
75
- "sass": "^1.77.0",
76
- "storybook": "10.5.6",
77
- "typescript": "~6.0.3"
78
- },
79
- "nx": {
80
- "targets": {
81
- "build": {
82
- "outputs": [
83
- "{projectRoot}/dist"
84
- ],
85
- "cache": true
86
- }
50
+ "module": "fesm2022/konce-pt-angular.mjs",
51
+ "typings": "types/konce-pt-angular.d.ts",
52
+ "exports": {
53
+ "./package.json": {
54
+ "default": "./package.json"
55
+ },
56
+ ".": {
57
+ "types": "./types/konce-pt-angular.d.ts",
58
+ "default": "./fesm2022/konce-pt-angular.mjs"
59
+ },
60
+ "./charts": {
61
+ "types": "./types/konce-pt-angular-charts.d.ts",
62
+ "default": "./fesm2022/konce-pt-angular-charts.mjs"
63
+ },
64
+ "./grid": {
65
+ "types": "./types/konce-pt-angular-grid.d.ts",
66
+ "default": "./fesm2022/konce-pt-angular-grid.mjs"
67
+ },
68
+ "./icons": {
69
+ "types": "./types/konce-pt-angular-icons.d.ts",
70
+ "default": "./fesm2022/konce-pt-angular-icons.mjs"
71
+ },
72
+ "./map": {
73
+ "types": "./types/konce-pt-angular-map.d.ts",
74
+ "default": "./fesm2022/konce-pt-angular-map.mjs"
75
+ },
76
+ "./roadmap": {
77
+ "types": "./types/konce-pt-angular-roadmap.d.ts",
78
+ "default": "./fesm2022/konce-pt-angular-roadmap.mjs"
87
79
  }
88
80
  },
89
- "scripts": {
90
- "build": "ng-packagr -p ng-package.json",
91
- "clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\""
92
- }
81
+ "type": "module",
82
+ "scripts": {}
93
83
  }
@@ -0,0 +1,112 @@
1
+ # KptRoadmap (kpt-roadmap)
2
+
3
+ Roadmapa — wiersze zadań na poziomej osi czasu (widok typu Gantt). Kolumna etykiet i nagłówek osi
4
+ są przyklejone przy przewijaniu, paski pozycjonowane procentowo, zależności rysuje warstwa SVG.
5
+ Import: `import { KptRoadmap } from '@konce-pt/angular/roadmap';`
6
+
7
+ ## Selektor
8
+ `kpt-roadmap` — standalone, OnPush, zoneless. Generyk `KptRoadmap<TItem, TGroup>` typuje pole `meta`.
9
+
10
+ ## Wejścia
11
+ - `config`: KptRoadmapConfig (wymagane) — dane i wszystkie opcje
12
+ - `scrollHeight`: string | null — stała wysokość, np. '420px'; włącza przyklejony nagłówek
13
+ - `labelWidth`: string — szerokość kolumny etykiet (domyślnie '14rem')
14
+ - `cellWidthPx`: number | null — szerokość kolumny osi; brak ⇒ wartość zależna od zoomu
15
+ - `showToday`: boolean — znacznik „dziś" (domyślnie true)
16
+ - `virtual`: boolean — renderuje tylko widoczne wiersze; warto od ~100 wierszy
17
+
18
+ ## Model / zdarzenia
19
+ - `collapsedGroups`: model<string[]> — dwukierunkowe id zwiniętych grup
20
+ - `itemClick`: output<KptRoadmapItem>
21
+ - `rangeChange`: output<KptTimeRange> — wyliczony zakres osi
22
+
23
+ ## KptRoadmapConfig
24
+ - `items`: KptRoadmapItem[] (wymagane)
25
+ - `groups?`: KptRoadmapGroup[]
26
+ - `links?`: KptRoadmapLink[] — zależności podane grafowo
27
+ - `zoom?`: 'year' | 'quarter' | 'month' | 'week' | 'day' | 'hour' (domyślnie 'week')
28
+ - `range?`: { start?: number; end?: number } — brakujący kraniec wyliczany z danych
29
+ - `locale?`: string; `today?`: Date | number | string
30
+ - `timeline?`, `rows?`, `dependencies?`, `interaction?` — opcje szczegółowe
31
+
32
+ ### KptRoadmapItem
33
+ - `id`: string, `label`: string (wymagane)
34
+ - `start`: Date | number | string; `end?`: to samo — brak `end` oznacza kamień milowy
35
+ - `sublabel?`, `icon?`, `disabled?`
36
+ - `variant?`: 'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info'
37
+ - `color?`: string — dowolny kolor CSS, nadpisuje `variant`
38
+ - `progress?`: number 0..1 — wypełnienie wewnątrz paska
39
+ - `groupId?`: string; `dependsOn?`: (string | KptRoadmapLink)[] — sam string oznacza zależność 'FS'
40
+ - `milestone?`: boolean — wymusza romb
41
+ - `meta?`: TItem
42
+ - Pola `draggable`, `resizable`, `locked`, `constraints` są zarezerwowane pod edycję i dziś ignorowane.
43
+
44
+ ### KptRoadmapGroup
45
+ - `id`, `label` (wymagane); `sublabel?`, `parentId?`, `collapsed?`, `variant?`, `color?`
46
+ - `summary?`: 'auto' | 'none' — 'auto' rysuje pasek zbiorczy od min(start) do max(end) dzieci
47
+
48
+ ### KptTimelineOptions (`config.timeline`)
49
+ - `weekendDays?`: number[] (domyślnie [0, 6]); `weekPrefix?`: string (domyślnie z i18n)
50
+ - `workHours?`: { from, to, mode?: 'skip' | 'dim', skipWeekends? } — tylko przy `zoom: 'hour'`;
51
+ 'skip' wycina noce z osi, 'dim' zostawia kolumny wyszarzone
52
+ - `positionMode?`: 'uniform' (domyślnie) | 'linear'
53
+ - `bandUnit?`: jednostka górnego poziomu nagłówka; `maxCells?`: number (domyślnie 4000)
54
+
55
+ ### KptRoadmapRowOptions (`config.rows`)
56
+ - `mode?`: 'row-per-item' (domyślnie) | 'pack' — 'pack' układa nienachodzące zadania w jednym wierszu
57
+ - `itemHeight?`, `groupHeight?`, `laneHeight?`, `packMinGapMs?`
58
+ - `showUngroupedHeader?`, `ungroupedLabel?`
59
+
60
+ ## Przykład
61
+
62
+ <kpt-roadmap [config]="roadmap" scrollHeight="420px" />
63
+
64
+ roadmap: KptRoadmapConfig = {
65
+ zoom: 'week',
66
+ groups: [{ id: 'app', label: 'Aplikacja' }],
67
+ items: [
68
+ { id: 'auth', label: 'Logowanie', start: '2026-08-24', end: '2026-08-31',
69
+ groupId: 'app', variant: 'success', progress: 1 },
70
+ { id: 'ship', label: 'Wydanie', start: '2026-09-14', groupId: 'app',
71
+ variant: 'warning', dependsOn: ['auth'] },
72
+ ],
73
+ };
74
+
75
+ ## Zachowanie
76
+ - Oś liczona w czasie lokalnym; numeracja tygodni wg ISO 8601 (tydzień 1 zawiera pierwszy czwartek roku).
77
+ - Tryb 'uniform' daje kolumny równej szerokości mimo zmiany czasu i różnej długości miesięcy;
78
+ wewnątrz kolumny pozycja jest interpolowana liniowo, więc zadanie może zaczynać się w środku dnia.
79
+ - Zmiana roku: mocniejsza pionowa linia i czarny znacznik z rokiem na pierwszym paśmie danego roku.
80
+ Przy zoomie tygodniowym granica liczona po roku tygodnia ISO, więc W53 nie trafia do kolejnego roku.
81
+ - Item wystający poza zakres osi jest ścinany od strony przycięcia.
82
+ - Podpowiedzi to dyrektywa `kptTooltip` (nie natywny `title`): dymek pojawia się od razu, jest
83
+ stylowany tokenami i działa też na focusie z klawiatury.
84
+ - Zasada: dymek pokazuje to, czego nie widać. Paski, etykiety wierszy i pasma nagłówka mają go
85
+ z `kptTooltipOnlyWhenTruncated`, więc podpowiedź wyskakuje wyłącznie przy tekście uciętym
86
+ wielokropkiem — sprawdzanym przy najechaniu, więc reagującym na zmianę szerokości i zoomu.
87
+ Kamienie milowe i komórki nagłówka mają dymek bezwarunkowo: romb nie pokazuje tekstu w ogóle,
88
+ a komórka dopowiada rok, którego w „W35 / 24.08–30.08" nie widać.
89
+ - Zależności: 'FS' (domyślna), 'SS', 'FF', 'SF'; naruszone są rysowane linią przerywaną w kolorze danger.
90
+ - Elementy z niepoprawną datą lub zduplikowanym `id` są pomijane, z ostrzeżeniem w trybie deweloperskim.
91
+
92
+ ## i18n
93
+ Klucze `roadmap.*`: `empty`, `week`, `today`, `milestone`, `expandGroup`, `collapseGroup`.
94
+ Nazwy miesięcy i dni tygodnia pochodzą z `Intl` wg `config.locale` albo locale z `KptI18n`,
95
+ więc mają formę zgodną z ortografią języka (po polsku małą literą, po angielsku wielką).
96
+ W nagłówku pierwszy znak jest kapitalizowany przez `::first-letter`, żeby wygląd osi był ten sam
97
+ niezależnie od języka; sam tekst pozostaje niezmieniony, więc podpowiedzi i odczyt przez czytnik
98
+ ekranu dostają formę oryginalną.
99
+
100
+ ## Tokeny
101
+ Powierzchnie `--kpt-color-surface{,-variant,-sunken,-hover}`, obrys `--kpt-color-border{,-strong}`,
102
+ paski wg wariantu `--kpt-color-{primary,success,danger,warning,info,muted}`.
103
+ Etykieta paska jest biała, ale wariant `neutral` ma jasne tło, więc jego napis używa
104
+ `--kpt-color-on-muted`. Pasek zbiorczy grupy w wariancie `neutral` rysuje się kolorem
105
+ `--kpt-color-on-surface-muted` — `--kpt-color-muted` byłby nieodróżnialny od tła wiersza.
106
+ Dalej:
107
+ znacznik roku na inwersji `--kpt-color-on-surface` / `--kpt-color-surface`.
108
+ Rozmiary: `--kpt-roadmap-label-w`, `--kpt-roadmap-cell-w` (obie można nadpisać z zewnątrz).
109
+
110
+ ## Do zrobienia (roadmap)
111
+ Przeciąganie i zmiana zakresu pasków, rysowanie zależności myszą, dodawanie wierszy —
112
+ typy (`KptRoadmapChange`, `constraints`, `interaction`) są już częścią API.
@@ -0,0 +1,89 @@
1
+ # KptAppShell (kpt-app-shell)
2
+
3
+ Szkielet aplikacji: pasek u góry, panel boczny, treść. Responsywny bez konfiguracji.
4
+ Import: `import { KptAppShell, KptShellNavToggle } from '@konce-pt/angular';`
5
+
6
+ ## Selektor
7
+ `kpt-app-shell`
8
+
9
+ ## Wejścia / wyjścia
10
+ - `sidenavOpen`: model<boolean> (domyślnie `true`) — stan panelu ZADOKOWANEGO
11
+ (oraz wymuszonego trybu `over`); dwukierunkowe `[(sidenavOpen)]`
12
+ - `sidenavCompactOpen`: model<boolean> (domyślnie `false`) — stan NAKŁADKI w trybie `auto`
13
+ - `sidenavMode`: `'auto' | 'side' | 'over'` (domyślnie **`'auto'`**)
14
+ - `sidenavBreakpoint`: `'sm'|'md'|'lg'|'xl'|'2xl'` (domyślnie `'lg'`) — od tego progu w górę
15
+ tryb `auto` dokuje panel, poniżej robi z niego nakładkę
16
+ - `sidenavRailBreakpoint`: ten sam zbiór albo `null` (domyślnie `null`) — włącza szynę ikon
17
+ w paśmie od `sidenavBreakpoint` do tego progu; wartość musi być WYŻSZA niż `sidenavBreakpoint`
18
+ - `sidenavLabel`: string — etykieta a11y panelu; puste = `appShell.navigation` ze słownika
19
+ - `sidenavId`: readonly string — identyfikator panelu (`aria-controls`)
20
+ - `isOverlay()`, `isSidenavOpen()`: Signal<boolean> — stan efektywny dla bieżącego układu
21
+ - `toggleSidenav()`, `openSidenav()`, `closeSidenav()` — trafiają w stan właściwy dla układu
22
+
23
+ ## Sloty projekcji
24
+ - `[kptShellToolbar]` → pasek u góry
25
+ - `[kptShellSidenav]` → panel boczny
26
+ - treść domyślna → obszar główny
27
+
28
+ ## Przykład
29
+ <kpt-app-shell [(sidenavOpen)]="navOpen">
30
+ <kpt-toolbar kptShellToolbar elevated>
31
+ <kpt-icon-button kptShellNavToggle variant="text" ariaLabel="Menu">
32
+ <kpt-icon name="menu" />
33
+ </kpt-icon-button>
34
+ </kpt-toolbar>
35
+ <kpt-sidenav kptShellSidenav>
36
+ <a href="#"><kpt-icon name="list" /> <span kptNavLabel>Pulpit</span></a>
37
+ </kpt-sidenav>
38
+ <router-outlet />
39
+ </kpt-app-shell>
40
+
41
+ ## Trzy pasma trybu 'auto'
42
+ | szerokość | układ | co robi zamknięcie |
43
+ |---|---|---|
44
+ | `< sidenavBreakpoint` | nakładka + scrim | panel wyjeżdża poza krawędź (stan: `sidenavCompactOpen`) |
45
+ | `>= sidenavBreakpoint`, `< sidenavRailBreakpoint` | szyna ikon | panel zwęża się do `--kpt-sidenav-rail-width` |
46
+ | `>= sidenavRailBreakpoint` (lub brak szyny) | pełny panel | panel chowa się w całości |
47
+
48
+ ## Dlaczego DWA stany otwarcia
49
+ „Otwarty" znaczy co innego po obu stronach progu: na desktopie panel domyślnie stoi otwarty,
50
+ na telefonie domyślnie musi być schowany. Gdyby oba układy dzieliły jeden model, wejście na wąski
51
+ ekran musiałoby nadpisać stan aplikacji, a powrót na szeroki nie miałby czego przywrócić.
52
+ Rozdzielenie sprawia, że intencja z desktopu przeżywa zwężenie i rozszerzenie okna za darmo.
53
+
54
+ Przycisk `kptShellNavToggle` sam trafia we właściwy stan — nie pisz `navOpen.set(...)` ręcznie,
55
+ bo na wąskim ekranie ustawisz nie ten model.
56
+
57
+ ## Konwencja treści menu (potrzebna tylko dla szyny)
58
+ - `[kptNavLabel]` — tekst pozycji; w szynie chowany techniką „visually hidden", więc pozycja
59
+ zachowuje dostępną nazwę dla czytnika ekranu.
60
+ - `[kptNavSection]` — nagłówek grupy; chowany tak samo.
61
+
62
+ To płaskie atrybuty (jak `kptShellToolbar` czy `kptToolbarSpacer`), nie dyrektywy — nic nie trzeba
63
+ importować. Bez nich szyna pokaże ucięty tekst zamiast ikony. W szynie warto opatrzyć pozycje
64
+ `kptTooltip`, bo widać sam znak.
65
+
66
+ ## Zachowanie
67
+ - O układzie decyduje wyłącznie CSS (`@media`), więc nic nie migocze przed hydracją i całość
68
+ działa na SSR. JavaScript odpowiada tylko za to, który stan przełącza przycisk.
69
+ - Zamknięty panel wypada z kolejki Tab przez `visibility: hidden` (nie `inert`) — jest poprawny
70
+ już na pierwszej klatce.
71
+ - Otwarta nakładka nakłada `inert` na treść (`<main>`), więc Tab nie wchodzi pod scrim.
72
+ - `Escape` zamyka nakładkę; klik w scrim też.
73
+ - Kierunek wysuwu idzie za `dir` (RTL wyjeżdża z prawej).
74
+ - Wysokość: `100dvh` z fallbackiem `100vh`.
75
+ - **Nie** zamyka menu po nawigacji — shell nie wie, co w danej aplikacji nią jest.
76
+ Zrób to sam: `if (shell.isOverlay()) shell.closeSidenav();`.
77
+
78
+ ## Tryby wymuszone (zgodność wsteczna)
79
+ `sidenavMode="side"` i `"over"` ignorują szerokość okna i czytają `sidenavOpen`, dokładnie jak
80
+ przed wprowadzeniem `auto`. Ustaw `"side"`, jeśli aplikacja sama zarządza responsywnością —
81
+ inaczej dostaniesz dwie warstwy tej samej logiki.
82
+
83
+ ## Tokeny
84
+ `--kpt-sidenav-width` (16rem), `--kpt-sidenav-rail-width` (4rem), `--kpt-z-overlay`,
85
+ `--kpt-color-overlay-scrim`, `--kpt-elevation-3`, `--kpt-motion-duration-base`.
86
+
87
+ ## Odłożone
88
+ Focus trap i zwrot fokusu do przycisku po zamknięciu (spójnie z `kpt-drawer`, który też ich
89
+ nie ma — to osobne zadanie dla całego repo). `<aside>` ma już `tabindex="-1"`.
@@ -0,0 +1,45 @@
1
+ # KptBreakpointObserver
2
+
3
+ Serwis (root) zamieniający media query na sygnały. Jedyny w bibliotece sposób na zapytanie
4
+ „jak szerokie jest okno" z poziomu TypeScriptu.
5
+
6
+ ## API
7
+
8
+ inject(KptBreakpointObserver)
9
+
10
+ - `up(bp: KptBreakpoint): Signal<boolean>` — `(min-width: <próg>px)`, mobile-first.
11
+ - `down(bp: KptBreakpoint): Signal<boolean>` — `(max-width: <próg - 0.02>px)`; odjęcie 0.02px
12
+ sprawia, że pasma `up`/`down` nie nakładają się na ułamkowych szerokościach (zoom, DPI).
13
+ - `matches(query: string): Signal<boolean>` — dowolne media query.
14
+
15
+ `KptBreakpoint` = `'sm' | 'md' | 'lg' | 'xl' | '2xl'`; progi w `KPT_BREAKPOINTS`
16
+ (640 / 768 / 1024 / 1280 / 1536 px).
17
+
18
+ ## Skąd biorą się wartości
19
+
20
+ Z tokenów: `packages/tokens/tokens/primitives/breakpoint.json` → `scripts/gen-tokens.mjs`
21
+ generuje `breakpoint/breakpoints.generated.ts` (dla JS) i `styles/_breakpoints.generated.scss`
22
+ (dla `@media` w SCSS komponentów). Oba pliki są commitowane i **nie edytuje się ich ręcznie** —
23
+ zmiana progu idzie przez token i `pnpm nx build angular`. Dzięki jednemu źródłu CSS biblioteki
24
+ i jej JavaScript nie mogą rozjechać się cicho.
25
+
26
+ ## SSR
27
+
28
+ Poza przeglądarką każdy sygnał to stałe `false`. Nie buduj na nim układu strony — od tego jest
29
+ CSS (`@media`), inaczej dostaniesz migotanie przed hydracją. Serwis służy do zachowań:
30
+ w którą stronę ma zadziałać przycisk, czy zamykać panel po nawigacji, co odłożyć na później.
31
+
32
+ ## Przykład
33
+
34
+ @Component({ /* … */ })
35
+ export class Header {
36
+ private readonly breakpoints = inject(KptBreakpointObserver);
37
+ readonly isDesktop = this.breakpoints.up('lg');
38
+ readonly isCompact = this.breakpoints.down('md');
39
+ }
40
+
41
+ ## Uwagi
42
+
43
+ - Zapytania są memoizowane per string — `up('lg')` w dziesięciu komponentach to jeden
44
+ `MediaQueryList` i jeden nasłuch; nie trzeba tego cache'ować u siebie.
45
+ - Sprzątanie idzie przez `DestroyRef` root injectora, więc nie ma czego odsubskrybować.
@@ -23,6 +23,9 @@ Import: `import { KptDatepicker } from '@konce-pt/angular';`
23
23
  - `monthDisplay`: 'long' | 'number' (domyślnie 'long') — w trybie 'month' i etykietach miesięcy: słownie (styczeń) lub liczbą (01)
24
24
  - `displayFormat`: 'pl' | 'iso' (domyślnie 'pl') — format wyświetlania i domyślnego placeholdera
25
25
  - `disabled`/`invalid`/`touched`: boolean; output `touch`.
26
+ - `ariaLabel`: string|null — nazwa dostępna, gdy pola nie opisuje `<label for>`
27
+ (np. dwie godziny w jednym wierszu edytora). Bez niej czytnik ekranu ogłasza samą wartość.
28
+ - Ikona w polu: kalendarz, a w trybie 'time' zegar.
26
29
  - Panel: nawigacja (‹ ›) miesięcy/lat/dekad wg trybu; tarcza zegara z „Gotowe"; przycisk czyszczenia (×).
27
30
 
28
31
  ## i18n
@@ -0,0 +1,68 @@
1
+ # KptDialog (kpt-dialog)
2
+
3
+ Okno modalne na natywnym `<dialog>` (focus trap, Esc, backdrop w standardzie).
4
+ Import: `import { KptDialog } from '@konce-pt/angular';`
5
+
6
+ ## Selektor
7
+ `kpt-dialog`
8
+
9
+ ## Wejścia
10
+ - `open`: model<boolean> — dwukierunkowe `[(open)]`
11
+ - `header`: string; `dismissible`: boolean (Esc/× zamyka; domyślnie true)
12
+
13
+ ## Sloty
14
+ - treść domyślna → body; element z atrybutem `kptDialogFooter` → stopka
15
+
16
+ ## Przykład
17
+ <kpt-dialog [(open)]="confirmOpen" header="Usunąć?">
18
+ Nieodwracalne.
19
+ <div kptDialogFooter>
20
+ <kpt-button variant="text" (click)="confirmOpen.set(false)">Anuluj</kpt-button>
21
+ <kpt-button variant="danger" (click)="remove()">Usuń</kpt-button>
22
+ </div>
23
+ </kpt-dialog>
24
+
25
+ ## Tokeny
26
+ `--kpt-color-surface-raised`, `--kpt-color-overlay-scrim` (::backdrop), `--kpt-elevation-4`.
27
+ Uwaga: globalny reset zeruje margin — komponent przywraca `margin:auto` (centrowanie).
28
+
29
+ ## Kontrolki na CDK Overlay w środku okna
30
+
31
+ `kpt-dialog` stoi na natywnym `<dialog>` i otwiera się przez `showModal()`, co wynosi je
32
+ do **warstwy szczytowej** przeglądarki — a ta jest ponad całym drzewem dokumentu i żaden
33
+ `z-index` jej nie przebije. Kontener CDK Overlay wisi domyślnie na `<body>`, więc panele
34
+ `kpt-select`, `kpt-datepicker`, `kpt-autocomplete` i `kpt-menu` otwierałyby się w środku
35
+ okna NIEWIDOCZNE, schowane za jego tłem.
36
+
37
+ Dlatego `kpt-dialog` na czas otwarcia przenosi kontener overlayów do wnętrza `<dialog>`
38
+ i oddaje go na miejsce przy zamknięciu (również gdy komponent zostanie zniszczony
39
+ z otwartym oknem). Nie trzeba nic konfigurować — kontrolki overlayowe działają w oknie
40
+ tak samo jak poza nim.
41
+
42
+ ## Układ i przewijanie
43
+
44
+ Otwarte okno jest kolumną flex: nagłówek (`.kpt-dialog__header`) i stopka
45
+ (`[kptDialogFooter]`) stoją nieruchomo, a przewija się wyłącznie `.kpt-dialog__body`.
46
+ Pasek przewijania biegnie więc tylko wzdłuż treści, nie wzdłuż całego okna.
47
+
48
+ Treść dostaje `flex: 0 1 auto` (domyślne) + `min-height: 0`, celowo **nie** `flex: 1`
49
+ jak w `kpt-drawer`. Szuflada wypełnia wysokość ekranu, okno ma kurczyć się do treści:
50
+ krótkie (`kpt-confirm` — dwa zdania i dwa przyciski) zostaje krótkie, długie zatrzymuje się
51
+ na `max-height: calc(100vh - 4rem)` i przewija samą treść.
52
+
53
+ Deklaracja `display: flex` jest scopowana `&[open]` i musi taka zostać. Regułę
54
+ `dialog:not([open]) { display: none }` daje arkusz przeglądarki, a każda deklaracja
55
+ autorska ją bije — także z `@layer`. Niescopowane `display: flex` zostawiłoby wszystkie
56
+ zamknięte okna widoczne na stronie.
57
+
58
+ `.kpt-dialog` nie dostaje `overflow: hidden` — kontener CDK Overlay jest na czas otwarcia
59
+ przeniesiony do wnętrza `<dialog>` (patrz sekcja wyżej), więc przycięcie okna ucięłoby
60
+ panele `kpt-select` czy `kpt-datepicker`. Do samego przewijania nie jest potrzebne:
61
+ po przejściu na flex nic nie wystaje poza okno.
62
+
63
+ Przypięty pasek akcji wewnątrz treści (np. „Anuluj / Zapisz" w `kpt-map-create-dialog`)
64
+ robi się przez `position: sticky` — kontenerem przewijania jest `.kpt-dialog__body`.
65
+ Ujemne marginesy boczne muszą zgadzać się z jego paddingiem (`--kpt-space-6`),
66
+ a przesunięcie `bottom` musi być lustrem ujemnego marginesu dolnego
67
+ (`bottom: calc(var(--kpt-space-6) * -1)`) — przyklejanie liczy się dla marginesowego
68
+ pudełka, więc przy `bottom: 0` pod paskiem przesuwałby się skrawek treści.
@@ -24,12 +24,30 @@ Import: `import { KptFormField } from '@konce-pt/angular';`
24
24
  Warianty float mają animowane przejście etykiety (pozycja spoczynkowa w miejscu placeholdera →
25
25
  uniesiona). Uniesienie następuje przy focusie kontrolki **lub** gdy pole ma wartość. Wykrywanie
26
26
  wypełnienia jest po stronie komponentu (zdarzenia `input`/`change` + wartość początkowa) — **nie**
27
- wymaga ustawiania placeholdera na kontrolce. Uwaga: wzorzec działa dla kontrolek `input`/`textarea`.
27
+ wymaga ustawiania placeholdera na kontrolce.
28
28
 
29
29
  <kpt-form-field label="E-mail" labelType="over">
30
30
  <kpt-input />
31
31
  </kpt-form-field>
32
32
 
33
+ ### Kontrolki bez natywnego `input`/`textarea`
34
+
35
+ Wartości `kpt-select` nie da się odczytać z DOM (panel żyje w overlayu), więc taka kontrolka
36
+ zgłasza wypełnienie sama — dostarcza token `KPT_FORM_FIELD_CONTROL` z sygnałem `filled`.
37
+ `kpt-select` robi to z pudełka; własna kontrolka wymaga:
38
+
39
+ import { KPT_FORM_FIELD_CONTROL, type KptFormFieldControl } from '@konce-pt/angular';
40
+
41
+ @Component({
42
+ providers: [{ provide: KPT_FORM_FIELD_CONTROL, useExisting: forwardRef(() => MyControl) }],
43
+ })
44
+ export class MyControl implements KptFormFieldControl {
45
+ readonly filled = computed(() => this.value() != null);
46
+ }
47
+
48
+ Gdy kontrolka dostarczy token, `kpt-form-field` przestaje zaglądać do DOM i ufa wyłącznie
49
+ sygnałowi `filled` — dlatego etykieta unosi się natychmiast po zmianie wartości.
50
+
33
51
  ## Projekcja
34
52
  Kontrolkę umieszcza się w treści (ng-content):
35
53
 
@@ -45,6 +63,11 @@ Kontrolkę umieszcza się w treści (ng-content):
45
63
  return s.touched() && s.invalid() ? s.errors()[0]?.message ?? null : null;
46
64
  });
47
65
 
66
+ Bramka `touched()` dotyczy wyłącznie komunikatu — walidatorów nie warunkuj (`when:` na
67
+ `state.touched()` sprawia, że `valid()` kłamie na nietkniętym formularzu). Kontrolki `kpt-*`
68
+ same bramkują swój stan wizualny tak samo. Pełny przepływ submit: sekcja
69
+ `## Formularz od zera (Signal Forms)` w głównym llms.txt.
70
+
48
71
  ## Tokeny
49
72
  `--kpt-form-field-label`, `--kpt-form-field-hint`, `--kpt-form-field-error`, `--kpt-color-danger`.
50
73
  Warianty float dodatkowo: `--kpt-form-field-placeholder` (etykieta spoczynkowa),
@@ -14,7 +14,8 @@ kolor z `currentColor`. Import: `import { KptIcon } from '@konce-pt/angular';`
14
14
  menu, x, chevron-up, chevron-down, chevron-left, chevron-right, check, search,
15
15
  grip-vertical, info, alert-triangle, circle-check, circle-x, calendar, copy, link, code,
16
16
  star, phone, map-pin, world, clock, align-left, align-center, align-right, align-justified,
17
- palette, highlight, clipboard, clipboard-text, table (pełna lista w `icons.ts`).
17
+ palette, highlight, clipboard, clipboard-text, table, mail, share, external-link, crosshair
18
+ (pełna lista w `icons.ts`).
18
19
 
19
20
  ## Pełny zestaw (5130 ikon Tabler)
20
21
  Opcjonalny entry point `@konce-pt/angular/icons` (pobierany tylko przy imporcie):
@@ -17,11 +17,18 @@ Bez `ControlValueAccessor`. Import: `import { KptInput } from '@konce-pt/angular
17
17
  email(p.email, { message: 'Podaj poprawny adres e-mail' });
18
18
  });
19
19
 
20
- // szablon (imports: [KptInput, FormField])
21
- <kpt-input [formField]="loginForm.email" type="email" id="f-email" />
20
+ // szablon (imports: [KptInput, FormField, FormRoot, KptButton])
21
+ <form [formRoot]="loginForm" (submit)="onSubmit()">
22
+ <kpt-input [formField]="loginForm.email" type="email" id="f-email" />
23
+ <kpt-button type="submit" [disabled]="loginForm().invalid()">Zaloguj</kpt-button>
24
+ </form>
25
+
26
+ `[formRoot]` sam ustawia `novalidate` i woła `submit()`; `submit()` sam robi `markAsTouched()`.
27
+ Nie warunkuj walidatorów przez `when: state.touched()` — psuje to `valid()`.
28
+ Pełny przepływ: sekcja `## Formularz od zera (Signal Forms)` w głównym llms.txt.
22
29
 
23
30
  ## Wejścia prezentacyjne
24
- - `type`: 'text'|'email'|'password'|'number'|'search'|'tel'|'url' (domyślnie 'text')
31
+ - `type`: 'text'|'email'|'password'|'number'|'search'|'tel'|'url'|'time' (domyślnie 'text')
25
32
  - `placeholder`: string
26
33
  - `id`: string — trafia na wewnętrzny `<input>` (do `label[for]`); host go nie nosi
27
34
  - `ariaLabel`: string | null
@@ -34,5 +41,8 @@ Bez `ControlValueAccessor`. Import: `import { KptInput } from '@konce-pt/angular
34
41
  `--kpt-form-field-{bg,text,placeholder,border,border-hover,border-focus,border-error,radius}`.
35
42
 
36
43
  ## Dostępność
37
- - `aria-invalid="true"` przy nieprawidłowym stanie; `blur` oznacza pole jako dotknięte.
44
+ - `aria-invalid="true"` dopiero gdy pole jest nieprawidłowe **i** dotknięte (`blur`) — świeży,
45
+ pusty formularz nie jest malowany na czerwono.
46
+ - `aria-required="true"` przy `required` — celowo nie natywny atrybut `required`, który
47
+ blokowałby zdarzenie submit i uruchamiał walidację przeglądarki obok Signal Forms.
38
48
  - Komunikaty błędów wyświetla zwykle `kpt-form-field` (`role="alert"`).
@@ -0,0 +1,61 @@
1
+ # KptInputNumber (kpt-input-number)
2
+
3
+ Pole liczbowe ze strzałkami krokowania na Signal Forms. Wartość = number | null.
4
+ `showButtons="false"` daje wariant bez strzałek — do zakresów „od–do".
5
+ Import: `import { KptInputNumber } from '@konce-pt/angular';`
6
+
7
+ ## Wejścia / model
8
+ - `value`: model<number | null> (lub `formField`)
9
+ - `min`/`max`: number | undefined; `step`: number (domyślnie 1)
10
+ - `suffix`: string (np. ' %'); `placeholder`: string
11
+ - `showButtons`: boolean (domyślnie `true`) — `false` chowa strzałki `−`/`+`; treść pola
12
+ wyrównuje się wtedy do lewej, jak w `kpt-input` (modyfikator `.kpt-input-number--plain`)
13
+ - `disabled`/`invalid`/`touched`: boolean; `touch`: output
14
+
15
+ ## Przykład
16
+ <kpt-input-number [formField]="f.qty" [min]="0" [max]="99" [step]="1" />
17
+ <kpt-input-number [(value)]="qty" suffix=" szt." />
18
+ <kpt-input-number [formField]="f.priceFrom" [showButtons]="false" suffix=" zł" />
19
+
20
+ ## Zakres „od–do" (walidacja między polami)
21
+
22
+ Dwa osobne pola formularza; regułę „do ≥ od" wpina się przez `validateTree` na korzeniu.
23
+ Błąd celuje się w konkretne pole właściwością `fieldTree` — inaczej wylądowałby na formularzu
24
+ i nie pokazałby się pod żadną kontrolką.
25
+
26
+ import { form, min, validateTree } from '@angular/forms/signals';
27
+
28
+ model = signal({ priceFrom: null as number | null, priceTo: null as number | null });
29
+
30
+ rangeForm = form(this.model, (path) => {
31
+ min(path.priceFrom, 0, { message: 'Wartość nie może być ujemna' });
32
+ min(path.priceTo, 0, { message: 'Wartość nie może być ujemna' });
33
+
34
+ validateTree(path, (ctx) => {
35
+ const from = ctx.valueOf(path.priceFrom);
36
+ const to = ctx.valueOf(path.priceTo);
37
+ if (from === null || to === null || from <= to) return null;
38
+ return {
39
+ kind: 'range',
40
+ message: 'Wartość „do" nie może być mniejsza niż „od"',
41
+ fieldTree: ctx.fieldTreeOf(path.priceTo), // błąd ląduje na polu „do"
42
+ };
43
+ });
44
+ });
45
+
46
+ // szablon — dwie kolumny od md (klasy utility z @konce-pt/grid)
47
+ <form class="kpt-grid" [formRoot]="rangeForm" (submit)="onSubmit()">
48
+ <kpt-form-field class="kpt-col-12 kpt-col-md-6" label="Cena od" [error]="fromError()">
49
+ <kpt-input-number [formField]="rangeForm.priceFrom" [min]="0" [showButtons]="false" suffix=" zł" />
50
+ </kpt-form-field>
51
+ <kpt-form-field class="kpt-col-12 kpt-col-md-6" label="Cena do" [error]="toError()">
52
+ <kpt-input-number [formField]="rangeForm.priceTo" [min]="0" [showButtons]="false" suffix=" zł" />
53
+ </kpt-form-field>
54
+ </form>
55
+
56
+ `ctx.valueOf(path.x)` czyta wartość innego pola, `ctx.fieldTreeOf(path.x)` wskazuje pole
57
+ docelowe błędu. Komunikaty podaje się przez `errorFor()` z bramką `touched()` — walidatorów
58
+ nie warunkuj. Pełny przepływ submit: `## Formularz od zera (Signal Forms)` w głównym llms.txt.
59
+
60
+ ## Tokeny
61
+ Pole `--kpt-form-field-*`; przyciski `--kpt-color-muted`.
@@ -18,6 +18,15 @@ Wymaga stylów overlay CDK w aplikacji: `import '@angular/cdk/overlay-prebuilt.c
18
18
  - `disabled`/`invalid`/`touched`: boolean; output `touch`.
19
19
  - Klawiatura: Enter/↓ otwiera, ↑/↓ nawigacja, Enter wybiera, Esc zamyka.
20
20
 
21
+ ## Float Label
22
+ W `kpt-form-field` z `labelType` `over`/`in`/`on` etykieta unosi się także po wybraniu opcji —
23
+ select dostarcza token `KPT_FORM_FIELD_CONTROL` z sygnałem `filled` (wartości w overlayu nie da
24
+ się odczytać z DOM). Nic nie trzeba konfigurować:
25
+
26
+ <kpt-form-field label="Kraj" labelType="on">
27
+ <kpt-select [formField]="f.country" [options]="countries" />
28
+ </kpt-form-field>
29
+
21
30
  ## i18n
22
31
  Etykiety „Szukaj…", „Brak wyników" i aria usuwania chipa z i18n (namespace `select`).
23
32
  Domyślnie EN; konfiguracja przez `provideKptI18n` — patrz `i18n/llms.txt`.
@@ -0,0 +1,29 @@
1
+ # KptSidenav (kpt-sidenav)
2
+
3
+ Panel boczny — stylowany kontener nawigacji, zwykle w slocie `kptShellSidenav`
4
+ komponentu `kpt-app-shell`. Import: `import { KptSidenav } from '@konce-pt/angular';`
5
+
6
+ ## Selektor
7
+ `kpt-sidenav`
8
+
9
+ ## Treść
10
+ Dowolna zawartość (ng-content). Elementy `<a>` mają wbudowane style pozycji nawigacji
11
+ (hover z `--kpt-color-muted`).
12
+
13
+ ## Przykład
14
+ <kpt-sidenav kptShellSidenav>
15
+ <a href="#">Pulpit</a>
16
+ <a href="#">Ustawienia</a>
17
+ </kpt-sidenav>
18
+
19
+ ## Szyna ikon (kpt-app-shell)
20
+ Jeśli shell ma włączone `sidenavRailBreakpoint`, opatrz tekst pozycji atrybutem `kptNavLabel`,
21
+ a nagłówek grupy `kptNavSection` — w zwiniętej szynie zostaje sama ikona, a etykieta jest
22
+ chowana technicznie (visually hidden), więc czytnik ekranu wciąż zna nazwę pozycji:
23
+
24
+ <a href="#"><kpt-icon name="list" /> <span kptNavLabel>Pulpit</span></a>
25
+
26
+ To płaskie atrybuty, nie dyrektywy — nic nie trzeba importować. Bez ikony szyna będzie pusta.
27
+
28
+ ## Tokeny
29
+ `--kpt-sidenav-{bg,fg,border,width,rail-width}` (szerokość ustawia `kpt-app-shell`).