@konce-pt/angular 0.9.1 → 0.10.0

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 (73) hide show
  1. package/CHANGELOG.md +307 -0
  2. package/fesm2022/konce-pt-angular.mjs +5429 -1758
  3. package/fesm2022/konce-pt-angular.mjs.map +1 -1
  4. package/package.json +11 -11
  5. package/src/lib/accordion/llms.txt +6 -0
  6. package/src/lib/alert/llms.txt +7 -0
  7. package/src/lib/app-shell/llms.txt +4 -3
  8. package/src/lib/autocomplete/llms.txt +13 -0
  9. package/src/lib/avatar/llms.txt +6 -3
  10. package/src/lib/avatar-group/llms.txt +6 -0
  11. package/src/lib/badge/llms.txt +11 -2
  12. package/src/lib/bottom-sheet/llms.txt +8 -1
  13. package/src/lib/breadcrumb/llms.txt +5 -0
  14. package/src/lib/button/llms.txt +3 -0
  15. package/src/lib/card/llms.txt +8 -0
  16. package/src/lib/carousel/llms.txt +13 -1
  17. package/src/lib/checkbox/llms.txt +10 -0
  18. package/src/lib/chip/llms.txt +6 -0
  19. package/src/lib/chips-input/llms.txt +12 -0
  20. package/src/lib/color-picker/llms.txt +14 -0
  21. package/src/lib/confirm/llms.txt +5 -0
  22. package/src/lib/context-menu/llms.txt +8 -0
  23. package/src/lib/data-table/llms.txt +5 -4
  24. package/src/lib/date-range/llms.txt +24 -2
  25. package/src/lib/datepicker/llms.txt +25 -5
  26. package/src/lib/dialog/llms.txt +18 -0
  27. package/src/lib/drawer/llms.txt +7 -1
  28. package/src/lib/empty/llms.txt +6 -0
  29. package/src/lib/fab/llms.txt +5 -2
  30. package/src/lib/file-upload/llms.txt +12 -1
  31. package/src/lib/form-field/llms.txt +24 -4
  32. package/src/lib/galleria/llms.txt +13 -1
  33. package/src/lib/i18n/llms.txt +2 -2
  34. package/src/lib/icon/llms.txt +9 -1
  35. package/src/lib/icon-button/llms.txt +3 -1
  36. package/src/lib/image/llms.txt +10 -1
  37. package/src/lib/input/llms.txt +6 -0
  38. package/src/lib/input-mask/llms.txt +11 -0
  39. package/src/lib/input-number/llms.txt +18 -0
  40. package/src/lib/input-otp/llms.txt +14 -0
  41. package/src/lib/knob/llms.txt +8 -0
  42. package/src/lib/listbox/llms.txt +16 -1
  43. package/src/lib/megamenu/llms.txt +21 -1
  44. package/src/lib/menu/llms.txt +14 -4
  45. package/src/lib/menubar/llms.txt +21 -0
  46. package/src/lib/meter-group/llms.txt +10 -0
  47. package/src/lib/order-list/llms.txt +11 -2
  48. package/src/lib/panel/llms.txt +7 -0
  49. package/src/lib/password/llms.txt +9 -1
  50. package/src/lib/pick-list/llms.txt +12 -2
  51. package/src/lib/popover/llms.txt +11 -0
  52. package/src/lib/radio-group/llms.txt +11 -0
  53. package/src/lib/rating/llms.txt +18 -4
  54. package/src/lib/rich-text/llms.txt +18 -0
  55. package/src/lib/scroll-top/llms.txt +12 -0
  56. package/src/lib/select/llms.txt +23 -5
  57. package/src/lib/sidenav/llms.txt +6 -0
  58. package/src/lib/skeleton/llms.txt +2 -1
  59. package/src/lib/slider/llms.txt +13 -0
  60. package/src/lib/speed-dial/llms.txt +8 -0
  61. package/src/lib/spinner/llms.txt +10 -1
  62. package/src/lib/split-button/llms.txt +11 -2
  63. package/src/lib/splitter/llms.txt +10 -1
  64. package/src/lib/stepper/llms.txt +8 -0
  65. package/src/lib/switch/llms.txt +11 -0
  66. package/src/lib/switch-group/llms.txt +11 -0
  67. package/src/lib/tabs/llms.txt +7 -0
  68. package/src/lib/textarea/llms.txt +12 -0
  69. package/src/lib/toast/llms.txt +19 -1
  70. package/src/lib/tooltip/llms.txt +12 -0
  71. package/src/lib/tree/llms.txt +21 -0
  72. package/types/konce-pt-angular.d.ts +1047 -73
  73. package/types/konce-pt-angular.d.ts.map +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konce-pt/angular",
3
- "version": "0.9.1",
3
+ "version": "0.10.0",
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",
@@ -46,16 +46,16 @@
46
46
  },
47
47
  "dependencies": {
48
48
  "tslib": "^2.3.0",
49
- "@konce-pt/backdrop": "0.9.1",
50
- "@konce-pt/chart": "0.9.1",
51
- "@konce-pt/i18n": "0.9.1",
52
- "@konce-pt/icons": "0.9.1",
53
- "@konce-pt/map": "0.9.1",
54
- "@konce-pt/table": "0.9.1",
55
- "@konce-pt/datetime": "0.9.1",
56
- "@konce-pt/roadmap": "0.9.1",
57
- "@konce-pt/mention": "0.9.1",
58
- "@konce-pt/chat": "0.9.1"
49
+ "@konce-pt/backdrop": "0.10.0",
50
+ "@konce-pt/map": "0.10.0",
51
+ "@konce-pt/chat": "0.10.0",
52
+ "@konce-pt/roadmap": "0.10.0",
53
+ "@konce-pt/icons": "0.10.0",
54
+ "@konce-pt/chart": "0.10.0",
55
+ "@konce-pt/mention": "0.10.0",
56
+ "@konce-pt/datetime": "0.10.0",
57
+ "@konce-pt/table": "0.10.0",
58
+ "@konce-pt/i18n": "0.10.0"
59
59
  },
60
60
  "module": "fesm2022/konce-pt-angular.mjs",
61
61
  "typings": "types/konce-pt-angular.d.ts",
@@ -18,3 +18,9 @@ Import: `import { KptAccordion, KptAccordionPanel } from '@konce-pt/angular';`
18
18
  </kpt-accordion>
19
19
 
20
20
  Single/multi coordination: a panel calls its parent through inject(KptAccordion).
21
+
22
+ ## Accessibility
23
+ Each header is a native button with `aria-expanded` and `aria-controls`; the body is a
24
+ `role="region"` named by its header (`aria-labelledby`), so a screen reader announces both the state
25
+ and what it belongs to. A collapsed body is `inert` and `aria-hidden`, skipped by the keyboard and
26
+ the screen reader alike.
@@ -9,6 +9,7 @@ Import: `import { KptAlert } from '@konce-pt/angular';`
9
9
  ## Inputs / outputs
10
10
  - `variant`: 'info'|'success'|'warning'|'danger' (default 'info')
11
11
  - `title`: string; `dismissible`: boolean (a × button)
12
+ - `visible`: model<boolean> (default true) — shown or closed, two-way; × sets `false`
12
13
  - `closed`: output<void>
13
14
 
14
15
  ## Example
@@ -17,3 +18,9 @@ Import: `import { KptAlert } from '@konce-pt/angular';`
17
18
 
18
19
  ## Tokens
19
20
  The accent comes from `--kpt-color-{info,success,warning,danger}`; the background is a color-mix over `--kpt-color-surface`.
21
+
22
+ ## Accessibility
23
+ The role follows the weight of the message: `info` and `success` are `role="status"` (read
24
+ politely, without interrupting), `warning` and `danger` are `role="alert"` (read at once). The icon
25
+ is decorative; the × button is labelled from `common.close`. After closing, focus falls back to the
26
+ page — move it yourself in the close handler when the alert was reached with the keyboard.
@@ -90,6 +90,7 @@ otherwise you end up with two layers of the same logic.
90
90
  `--kpt-sidenav-width` (16rem), `--kpt-sidenav-rail-width` (4rem), `--kpt-z-overlay`,
91
91
  `--kpt-color-overlay-scrim`, `--kpt-elevation-3`, `--kpt-motion-duration-base`.
92
92
 
93
- ## Deferred
94
- A focus trap and returning focus to the button after closing (consistent with `kpt-drawer`, which does not
95
- have them either — that is a separate task for the whole repo). The `<aside>` already carries `tabindex="-1"`.
93
+ ## Focus
94
+ Opening the overlay moves focus into the panel (its first focusable element, or the `<aside>`
95
+ itself); closing it returns focus to where it came from — usually the menu button — unless the user
96
+ has already moved it elsewhere. An overlay that is open when the page loads does not take focus.
@@ -12,5 +12,18 @@ Import: `import { KptAutocomplete } from '@konce-pt/angular';`
12
12
  ## Example
13
13
  <kpt-autocomplete [formField]="f.city" [options]="cities" placeholder="City…" />
14
14
 
15
+ ## Screen reader and keyboard
16
+ The WAI-ARIA combobox-with-list pattern: focus stays in the field, `aria-autocomplete="list"`,
17
+ `aria-controls` and `aria-activedescendant` point at the active suggestion, and a polite live region
18
+ says how many suggestions there are (`autocomplete.results`) or that there are none
19
+ (`autocomplete.noResults`). Matching ignores case and diacritics ("lodz" finds "Łódź"). `↑` from the
20
+ field goes to the last suggestion; the first `Escape` closes the list, the second clears the field.
21
+
22
+ ## Label and description
23
+ `id` goes to the native field — the host never carries it; without one it is generated. Inside
24
+ `kpt-form-field` the control links itself: the wrapper's `label[for]` points at it and the hint or
25
+ error is added to `aria-describedby`, so `controlId` is not needed. Without a wrapper, name it with
26
+ `ariaLabel`.
27
+
15
28
  ## Tokens
16
29
  `--kpt-form-field-*`, the panel `--kpt-color-surface-raised`.
@@ -5,6 +5,7 @@ An avatar — an image, initials (from `name`) or an icon. Import: `import { Kpt
5
5
  ## Inputs
6
6
  - `src`: string|null (an image); `name`: string (initials, up to 2 letters); `icon`: string|null
7
7
  - `size`: 'sm'|'md'|'lg'|'xl'; `shape`: 'circle'|'square'
8
+ - `decorative`: boolean — hides the avatar from screen readers (the name is written next to it)
8
9
 
9
10
  ## Examples
10
11
  <kpt-avatar src="/u/anna.jpg" />
@@ -12,9 +13,11 @@ An avatar — an image, initials (from `name`) or an icon. Import: `import { Kpt
12
13
  <kpt-avatar icon="user" shape="square" />
13
14
 
14
15
  ## Accessibility
15
- `name` goes into the native `title` (a tooltip with the full name — initials on their own say nothing).
16
- Without `src`: `role="img"` + `aria-label="name"`, and the initials are `aria-hidden`. With `src` the label
17
- is carried by the image's `alt` — it is not duplicated in `aria-label`.
16
+ `name` goes into the native `title` (initials alone say nothing). With a photo the name is the
17
+ image's `alt`; without one the avatar is `role="img"` with `aria-label`, and the initials are
18
+ `aria-hidden`. A photo that fails to load falls back to the initials (or the icon); a new `src` is
19
+ tried again. `decorative` removes the avatar from the accessibility tree — use it when the name is
20
+ already written next to it.
18
21
 
19
22
  ## Tokens
20
23
  `--kpt-color-muted`, `--kpt-color-on-muted`, `--kpt-radius-full`/`--kpt-radius-md`.
@@ -7,6 +7,7 @@ Import: `import { KptAvatarGroup } from '@konce-pt/angular';`
7
7
  - `avatars`: KptAvatarItem[] — { name?, src?, icon? }
8
8
  - `max`: number (default 4) — how many to show before "+N"
9
9
  - `size`: 'sm' | 'md' | 'lg' | 'xl'
10
+ - `label`: string — the group's name; with it the row is `role="group"`
10
11
 
11
12
  Every avatar in the group shows its `name` in a tooltip (the `title` from `kpt-avatar`), so
12
13
  the initials stay readable even at `size="sm"`.
@@ -16,3 +17,8 @@ the initials stay readable even at `size="sm"`.
16
17
 
17
18
  ## Tokens
18
19
  The overlap uses a `--kpt-color-surface` ring; "+N" uses `--kpt-color-muted`.
20
+
21
+ ## Accessibility
22
+ Every avatar keeps its own name. With `label` the row is `role="group"` with that name. The “+N”
23
+ counter is `role="img"` named from `avatarGroup.more` (`{count}` — “2 more”), with the hidden names
24
+ in its `title`. The overlap uses `margin-inline-start`, so it mirrors in RTL.
@@ -4,11 +4,13 @@ A badge — a counter or a status dot; standalone or overlaid on content (`overl
4
4
  Import: `import { KptBadge } from '@konce-pt/angular';`
5
5
 
6
6
  ## Inputs
7
- - `value`: string|number|null; `variant`: 'neutral'|'primary'|'success'|'danger'|'warning'|'info'
7
+ - `value`: string|number|null; `variant`: 'neutral'|'primary'|'success'|'danger'|'warning'|'info' (default 'primary')
8
8
  - `size`: 'sm'|'md'|'lg' (default 'md') — height 1rem / 1.25rem / 1.5rem. The type size, the side inset
9
9
  and the dot diameter are derived from the height, so the proportions hold at every size.
10
10
  `sm` is meant for a badge sitting inside a line of text (a menu entry, a label, a table cell).
11
11
  - `dot`: boolean (a dot with no number); `overlay`: boolean (the corner of the content); `max`: number (default 99 → '99+')
12
+ - `label`: string — the meaning for screen readers (“3 unread”, “online”); the visible text is then `aria-hidden`
13
+ - `hideZero`: boolean — hides the badge when `value` is `0` or `null` (not with `dot`)
12
14
 
13
15
  ## Examples
14
16
  <kpt-badge [value]="3" variant="danger" />
@@ -17,4 +19,11 @@ Import: `import { KptBadge } from '@konce-pt/angular';`
17
19
  <kpt-badge dot variant="success" overlay><kpt-avatar name="AK" /></kpt-badge>
18
20
 
19
21
  ## Tokens
20
- `--kpt-color-{primary,muted,success,danger,warning,info}`, the overlay ring from `--kpt-color-surface`.
22
+ Background `--kpt-color-{primary,success,danger,warning,info}` with the text in the matching `*-contrast` token (`--kpt-color-on-primary` for `primary`) — the same pairs as `kpt-button`; `neutral` is `--kpt-color-muted` / `--kpt-color-on-muted`; the overlay ring comes from `--kpt-color-surface`.
23
+
24
+ ## Accessibility
25
+ On its own a badge is just a number, and a `dot` is nothing. `label` gives it a meaning — a visually
26
+ hidden `.kpt-badge__label` that screen readers read instead of the visible text. Without `label`, put
27
+ the meaning into the name of the control the badge sits on. Count changes are not announced. The
28
+ `success`, `warning` and `info` variants draw the text in `--kpt-color-surface`; check the contrast
29
+ in your theme, especially for `warning`.
@@ -18,5 +18,12 @@ The sheet is always in the DOM (no `@if`), hidden with `transform` **and** `visi
18
18
  out of the tab order and out of the accessibility tree without `inert`, and it does so on the very first frame,
19
19
  without waiting for JavaScript. `prefers-reduced-motion: reduce` drops the transitions.
20
20
 
21
+ ## Focus and keyboard
22
+ Opening moves focus into the panel (`cdkFocusInitial`, else its first focusable element, else the
23
+ panel itself) and traps it there — `Tab` / `Shift+Tab` wrap inside, as `aria-modal="true"` promises.
24
+ Closing returns focus to the element that had it before. `Escape` closes the panel. The panel
25
+ is named by its `header` through `aria-labelledby`. The shared helper is `shared/modal-focus.ts` (on the CDK focus trap; the React port has a twin hook).
26
+
21
27
  ## Tokens
22
- The panel `--kpt-color-surface-raised`, the top radius `--kpt-radius-lg`, `--kpt-elevation-4`.
28
+ The panel `--kpt-color-surface-raised`, the top radius `--kpt-radius-lg`, `--kpt-elevation-4`; the backdrop
29
+ `--kpt-color-overlay-scrim`.
@@ -10,3 +10,8 @@ A navigation trail. Import: `import { KptBreadcrumb, KptBreadcrumbItem } from '@
10
10
 
11
11
  ## Tokens
12
12
  The separator is a `chevron-right` icon; links `--kpt-color-on-surface-muted` → hover `--kpt-color-primary`.
13
+
14
+ ## Accessibility
15
+ A `<nav>` landmark labelled from `breadcrumb.label`, holding an ordered list (`<ol>`/`<li>`), so a
16
+ screen reader announces how many levels the trail has. The current page carries
17
+ `aria-current="page"`; separators are icons hidden from assistive technology.
@@ -26,6 +26,9 @@ you pass `href`. Standalone, OnPush, signals. Import: `import { KptButton } from
26
26
  - `iconClass` / `iconEndClass`: string — an extra class on that icon
27
27
  - `href`: string — renders an `<a>` instead of a `<button>`
28
28
  - `target` / `rel`: string — only meaningful together with `href`
29
+ - `ariaLabel`: string | null (default null) — the accessible name for an icon-only button; it lands on
30
+ the inner `<button>`/`<a>`. Do not use `[attr.aria-label]` on `<kpt-button>`: that puts it on the host,
31
+ which has no button role, and a screen reader announces a nameless button
29
32
 
30
33
  ## Events
31
34
  None of its own — the native `click` bubbles out of the inner `<button>`; bind `(click)` on `<kpt-button>`.
@@ -9,6 +9,8 @@ Import: `import { KptCard } from '@konce-pt/angular';`
9
9
  ## Inputs
10
10
  - `variant`: 'elevated' | 'outlined' (default 'elevated')
11
11
  - `header`: string — optional header text
12
+ - `headingLevel`: 1–6 | null (default null) — makes `header` a heading of that level
13
+ - `headingLevel`: 1–6 | null (default null) — makes `header` a heading of that level
12
14
  - `flush`: boolean — a body with no padding (for rich layouts that manage their own sections)
13
15
 
14
16
  ## Content projection
@@ -49,3 +51,9 @@ than a placement one. Put the wrapper inside the footer, not the footer inside t
49
51
 
50
52
  ## Tokens
51
53
  `--kpt-card-{bg,fg,border,radius,padding,shadow}`.
54
+
55
+ ## Accessibility
56
+ The card is a plain container with no role of its own. `header` is styled text by default — set
57
+ `headingLevel` (1–6) to make it a heading (`role="heading"` + `aria-level`) when the card should
58
+ appear in the page outline; leave it off for tiles that would only clutter it. Give media images a
59
+ meaningful `alt`, or `alt=""` when decorative.
@@ -6,6 +6,7 @@ Data through `items`, the slide template through projection: `<ng-template let-i
6
6
  ## Inputs / model
7
7
  - `items`: T[] — the slide data
8
8
  - `activeIndex`: model<number> (default 0) — the two-way index of the active slide
9
+ - `label`: string — the region name; empty = `carousel.label`
9
10
 
10
11
  ## Content projection
11
12
  - `<ng-template let-item let-i="index">` — the template for a single slide; context: `$implicit` = the item, `index`.
@@ -21,4 +22,15 @@ Data through `items`, the slide template through projection: `<ng-template let-i
21
22
  </kpt-carousel>
22
23
 
23
24
  ## Tokens
24
- Navigation and dots `--kpt-color-primary`; the arrow background `--kpt-color-surface-raised`.
25
+ The active dot `--kpt-color-primary`; the arrows `--kpt-color-surface` (80% via `color-mix`, solid on hover) with `--kpt-elevation-2`; the slide transition `--kpt-motion-duration-base`.
26
+
27
+ ## Accessibility
28
+ The WAI-ARIA carousel pattern without autoplay. The root is `role="region"` with
29
+ `aria-roledescription` from `carousel.roleCarousel` (“carousel”) and a name from `label` or
30
+ `carousel.label`. Each slide is `role="group"` with `aria-roledescription` from `carousel.roleSlide`
31
+ and a name from `carousel.slideOf` (“Slide 2 of 4”); slides outside the view are `inert` and
32
+ `aria-hidden`, so Tab never lands on an invisible link. The track is `aria-live="polite"`, so the
33
+ slide that comes in is announced. The arrows use `aria-disabled` at the ends instead of `disabled`,
34
+ so they keep the focus; the active dot carries `aria-current`, and every dot has a 24 px target
35
+ (WCAG 2.5.8) with an 8 px visible dot. The transition is off under `prefers-reduced-motion`; in RTL
36
+ the track and the chevrons follow the reading direction (`:dir(rtl)`).
@@ -11,5 +11,15 @@ Import: `import { KptCheckbox } from '@konce-pt/angular';`
11
11
  - `label`: string
12
12
  - `disabled` / `invalid` / `touched`: boolean (bound by FormField); the `touch` output (blur)
13
13
 
14
+ ## Screen reader and keyboard
15
+ `indeterminate`: model<boolean> — the "some selected" state for a "select all" box (a dash in the
16
+ box; screen readers say "partially checked"). A click clears it and sets `checked`.
17
+
18
+ ## Label and description
19
+ `id` goes to the native field — the host never carries it; without one it is generated. Inside
20
+ `kpt-form-field` the control links itself: the wrapper's `label[for]` points at it and the hint or
21
+ error is added to `aria-describedby`, so `controlId` is not needed. Without a wrapper, name it with
22
+ `ariaLabel`. Inside `kpt-form-field` the box gets both names: the wrapper label and its own `label`.
23
+
14
24
  ## Tokens
15
25
  `--kpt-color-primary`, `--kpt-color-on-primary`, `--kpt-form-field-border`, `--kpt-form-field-border-error`.
@@ -20,3 +20,9 @@ word ends. For labels with a hyphen, spelling it out in the content is the exact
20
20
 
21
21
  ## Tokens
22
22
  A color-mix background over the variant, `--kpt-color-muted` (neutral).
23
+
24
+ ## Accessibility
25
+ The label sits in `.kpt-chip__label`, and the remove button is named by `aria-labelledby` from
26
+ itself plus that label — “Remove Angular” — so with several chips a screen reader user hears which
27
+ one goes. `Backspace` and `Delete` on the button work like a click. After removal focus falls back
28
+ to the page; move it to the next chip yourself.
@@ -14,5 +14,17 @@ Import: `import { KptChipsInput } from '@konce-pt/angular';`
14
14
  <kpt-chips-input [formField]="f.tags" placeholder="Add a tag…" />
15
15
  <kpt-chips-input [(value)]="tags" />
16
16
 
17
+ ## Screen reader and keyboard
18
+ The tags are a list (`role="list"`/`listitem`), so a screen reader hears how many there are. Adding,
19
+ removing (also with `Backspace`) and a rejected duplicate are announced by a polite live region
20
+ (`chipsInput.added`/`removed`/`duplicate`); a duplicate stays in the field to be corrected instead
21
+ of vanishing. After removing a tag with its `×`, focus returns to the text field.
22
+
23
+ ## Label and description
24
+ `id` goes to the native field — the host never carries it; without one it is generated. Inside
25
+ `kpt-form-field` the control links itself: the wrapper's `label[for]` points at it and the hint or
26
+ error is added to `aria-describedby`, so `controlId` is not needed. Without a wrapper, name it with
27
+ `ariaLabel`. New: `id`, `ariaLabel`, `required` and `aria-invalid` on the text field.
28
+
17
29
  ## Tokens
18
30
  The field uses `--kpt-form-field-*`; the tags inherit from `kpt-chip`.
@@ -14,5 +14,19 @@ Import: `import { KptColorPicker } from '@konce-pt/angular';`
14
14
 
15
15
  color = signal('#3b82f6');
16
16
 
17
+ ## Screen reader and keyboard
18
+ `presets` accepts codes or `{ value, label }` (the `KptColorPreset` type): the label names the
19
+ swatch, because a hex code says little to a screen reader; the default palette is named from i18n
20
+ (`colorPicker.red`…). The active swatch has `aria-pressed`. The hex field changes the value only on
21
+ a full `#rrggbb` code (a missing `#` is added); an incomplete code stays visible with
22
+ `aria-invalid`.
23
+
24
+ ## Label and description
25
+ `id` goes to the native field — the host never carries it; without one it is generated. Inside
26
+ `kpt-form-field` the control links itself: the wrapper's `label[for]` points at it and the hint or
27
+ error is added to `aria-describedby`, so `controlId` is not needed. Without a wrapper, name it with
28
+ `ariaLabel`. `id` and the label go to the hex field; the native colour well is named "Pick a colour"
29
+ (`colorPicker.picker`), and the hex field falls back to "Hex code" (`colorPicker.hex`).
30
+
17
31
  ## Tokens
18
32
  The border `--kpt-form-field-border`; the active preset `--kpt-color-primary`.
@@ -23,3 +23,8 @@ English by default; configured through `provideKptI18n` — see `i18n/llms.txt`.
23
23
 
24
24
  ## Tokens
25
25
  Inherited from `kpt-dialog`; the icon follows the variant (`--kpt-color-danger` / `--kpt-color-primary`).
26
+
27
+ ## Accessibility
28
+ The window is `role="alertdialog"` named by its header, with the message tied to it through
29
+ `aria-describedby`, so a screen reader reads the question as soon as it opens. Focus starts on the
30
+ reject button — the safe answer, so a stray `Enter` deletes nothing. Escape and × reject.
@@ -15,5 +15,13 @@ Import: `import { KptContextMenu } from '@konce-pt/angular';`
15
15
  <div class="area">Right-click here</div>
16
16
  </kpt-context-menu>
17
17
 
18
+ ## Keyboard
19
+ The same model as `kpt-menu` (the shared `menu-keys.ts`): opening moves focus to the first item, arrows /
20
+ `Home` / `End` move between items (disabled ones and separators are skipped), `Escape` and `Tab` close
21
+ it and focus returns to where it was. `Shift+F10` and the context-menu key on a focused element inside
22
+ the area open it too — the browser then sends `contextmenu` without mouse coordinates, so the panel is
23
+ placed at that element. The panel is kept inside the viewport (8px from the edges). Touch screens have
24
+ no right click, so still offer the same actions through a visible button with `kpt-menu`.
25
+
18
26
  ## Tokens
19
27
  The panel `--kpt-color-surface-raised`, `--kpt-elevation-3`.
@@ -121,10 +121,11 @@ swaps its value for a control from `column.edit.type`. How it commits depends on
121
121
  the way — the panel stays open until the user clicks outside it, and then a single event fires with the full list.
122
122
 
123
123
  The table **never commits on `touch`** — and that must not be reinstated. `touch` in these
124
- controls does not mean "the user is done": it fires on the trigger's blur (and the panel lives in a CDK Overlay
125
- container next to `<body>`, so pressing the mouse on an option/day blurs the trigger) and, on top of that, from `step_()`
126
- in `kpt-input-number`. Committing on `touch` destroyed the editor together with the panel before the click
127
- had a chance to pick a value. Instead: overlay editors bind to `open` (`[open]`/`(openChange)`),
124
+ controls does not mean "the user is done": it fires on the trigger's blur and, on top of that, from `step_()`
125
+ in `kpt-input-number`. Committing on `touch` once destroyed the editor together with the panel before the click
126
+ had a chance to pick a value (the panel lives in a CDK Overlay container next to `<body>`, and pressing the mouse
127
+ on an option used to blur the trigger). The select and date pickers no longer emit `touch` while their panel
128
+ is open, but `open` remains the only signal that says "the choice is over". Instead: overlay editors bind to `open` (`[open]`/`(openChange)`),
128
129
  and the rest to `focusout` on the whole editor (focus moved within the editor does not commit).
129
130
 
130
131
  **A limitation**: for overlay editors Escape **commits** (it closes the panel) rather than discarding —
@@ -17,7 +17,10 @@ Requires `import '@angular/cdk/overlay-prebuilt.css';`
17
17
  - `minuteStep`: number (default 1) — minute snapping on the dial
18
18
  - `placeholder`: string — with no value it uses i18n (`dateRange.placeholder`); the input takes priority
19
19
  - `displayFormat`: 'pl' | 'iso' (default 'pl') — the display format for start/end
20
- - `disabled`/`invalid`/`touched`: boolean; `touch`: output
20
+ - `minDate`/`maxDate`: string|null — 'YYYY-MM-DD' bounds (inclusive); days outside are disabled
21
+ - `ariaLabel`: string|null — the accessible name when no `<label for>` describes the field
22
+ - `disabled`/`invalid`/`touched`: boolean; `touch`: output — fires when the panel closes and when
23
+ focus leaves the closed trigger
21
24
 
22
25
  ## Behavior
23
26
  The first click sets `start`, the second `end` (the order is normalized). The "×" clears it.
@@ -25,6 +28,18 @@ The range highlights one continuous band running across every panel: the end day
25
28
  blob, and the band leaves their center, rounding off at the ends of a grid row.
26
29
  The datetime/time modes: a "From / To" toggle + the clock dial, confirmed with the "Done" button.
27
30
 
31
+ ## Keyboard
32
+ As in the date picker: the trigger has `aria-haspopup="dialog"` and `aria-expanded`; `Enter`, `Space`
33
+ and `↓` open the panel (a `role="dialog"` named "Choose a date range") with focus on the range start,
34
+ or today. The arrows, `Home`/`End` and `PageUp`/`PageDown` (with `Shift` — a year) walk the days across
35
+ every panel, shifting the set of months when focus leaves it. `Tab` cycles inside the panel, `Escape`
36
+ closes it, and picking the end (or "Done") returns focus to the trigger. `Delete`/`Backspace` on the
37
+ trigger clears the range.
38
+
39
+ Each day is named with the full date and its role in the range ("…, start of range", "…, end of range",
40
+ "…, in range") — the band colour is not the only carrier. The ends have `aria-pressed`, today has
41
+ `aria-current="date"`. After the first pick a polite live region says "Start: … Choose the end date.".
42
+
28
43
  ## Example
29
44
  <kpt-date-range [formField]="f.period" />
30
45
  <kpt-date-range [(value)]="period" />
@@ -34,7 +49,14 @@ The datetime/time modes: a "From / To" toggle + the clock dial, confirmed with t
34
49
 
35
50
  ## i18n
36
51
  Day and month names come from `Intl` per locale; the labels ("From/To", navigation, "Done", the placeholder) come from i18n
37
- (the `dateRange` namespace + `datepicker`/`common`). English by default — see `i18n/llms.txt`.
52
+ (the `dateRange` namespace + `datepicker`/`common`), and so do the dialog name, the range roles of
53
+ the days and the live announcements. English by default — see `i18n/llms.txt`.
54
+
55
+ ## Label and description
56
+ `id` goes to the focusable element — the host never carries it; without one it is generated. A `div`
57
+ with a role is not named by `label[for]`, so inside `kpt-form-field` it gets `aria-labelledby`
58
+ pointing at the wrapper's label (unless `ariaLabel` is set), and the hint or error is added to
59
+ `aria-describedby`. No `controlId` needed. New: `id`; the trigger is the element that carries it.
38
60
 
39
61
  ## Tokens
40
62
  The field `--kpt-form-field-*`; the calendar `--kpt-color-surface-raised`, the range `--kpt-color-primary`.
@@ -33,15 +33,29 @@ Import: `import { KptDatepicker } from '@konce-pt/angular';`
33
33
  - `displayFormat`: 'pl' | 'iso' (default 'pl') — the display format and the default placeholder
34
34
  - `disabled`/`invalid`/`touched`: boolean; the `touch` output.
35
35
  - `open`: model (two-way `[(open)]`, the `(openChange)` output) — the calendar state. It lets you open
36
- it from outside and know when the user is done choosing. For the latter **do not use `touch`**:
37
- it also fires on the trigger's blur, that is, the moment the mouse goes down on a day in the panel (the panel
38
- lives in a CDK Overlay container next to `<body>`, outside the control's DOM). That is what inline editing
39
- in `kpt-data-table` does — see `data-table/llms.txt`.
36
+ it from outside and know when the user is done choosing — that is what inline editing
37
+ in `kpt-data-table` does, see `data-table/llms.txt`. `touch` fires when the panel closes and when
38
+ focus leaves the closed trigger; focus moving into the calendar does not count as leaving.
40
39
  - `ariaLabel`: string|null — the accessible name when no `<label for>` describes the field
41
40
  (two times in one editor row, for instance). Without it a screen reader announces the value alone.
42
41
  - The icon in the field: a calendar, and a clock in 'time' mode.
43
42
  - The panel: a clear button (×), the clock dial with "Done".
44
43
 
44
+ ## Keyboard
45
+ The date picker dialog pattern. The trigger has `aria-haspopup="dialog"` and `aria-expanded`;
46
+ `Enter`, `Space` and `↓` open the panel — a `role="dialog"` named "Choose a date" — and move focus to
47
+ the selected day, or today, clamped to `minDate`/`maxDate`.
48
+ - Day grid: `←`/`→` one day, `↑`/`↓` one week, `Home`/`End` Monday and Sunday of the week,
49
+ `PageUp`/`PageDown` one month, with `Shift` one year (the day is clamped to the month length).
50
+ Crossing a month edge turns the page. Each day is named with the full date from `Intl`
51
+ ("Thursday, October 8, 2026"), today has `aria-current="date"`, and only the focused day is
52
+ a Tab stop. In RTL the horizontal arrows are mirrored.
53
+ - Month, year and decade grids: the arrows move between cells (three columns), `Home`/`End` to the ends.
54
+ Clicking a title moves focus to the new grid.
55
+ - `Tab` cycles inside the panel; `Escape` closes it. Picking a value (or "Done") closes the panel
56
+ and returns focus to the trigger. `Delete`/`Backspace` on the trigger clears the value; the "×" button
57
+ sits outside the Tab order.
58
+
45
59
  ## Behavior (the view stack)
46
60
  The panel header always has the shape `‹ title ›`; the arrows move the current level's page,
47
61
  and the title is a button that goes one level up:
@@ -58,7 +72,7 @@ An arrow dims (`disabled`) when the whole neighboring page falls outside `minDat
58
72
 
59
73
  ## i18n
60
74
  Weekday and month names are derived from `Intl` per the active i18n locale (not from the dictionary).
61
- The navigation/aria labels ("previous decades", "choose a year"…) and "Done" come from i18n
75
+ The navigation/aria labels ("previous decades", "choose a year", the dialog name…) and "Done" come from i18n
62
76
  (the `datepicker` + `common` namespaces). English by default;
63
77
  configured through `provideKptI18n` — see `i18n/llms.txt`. Note: `displayFormat` ('pl'/'iso')
64
78
  controls the date format only and is independent of the label language.
@@ -67,5 +81,11 @@ controls the date format only and is independent of the label language.
67
81
  The grids, bounds, paging and formats come from `@konce-pt/datetime` — the same framework-free
68
82
  package the React port uses, with its own tests. The component holds signals and markup only.
69
83
 
84
+ ## Label and description
85
+ `id` goes to the focusable element — the host never carries it; without one it is generated. A `div`
86
+ with a role is not named by `label[for]`, so inside `kpt-form-field` it gets `aria-labelledby`
87
+ pointing at the wrapper's label (unless `ariaLabel` is set), and the hint or error is added to
88
+ `aria-describedby`. No `controlId` needed. New: `id`; the trigger is the element that carries it.
89
+
70
90
  ## Tokens
71
91
  `--kpt-form-field-{bg,text,border,border-focus,border-error,radius}`.
@@ -12,6 +12,18 @@ Import: `import { KptDialog } from '@konce-pt/angular';`
12
12
  - `size`: 'sm' | 'md' | 'lg' (default 'md') — 24rem / 32rem / 48rem, always capped at the viewport
13
13
  (`min(var(--_width), calc(100vw - 2rem))`). Reach for `lg` when the content cannot sensibly be
14
14
  narrowed: code, a table, two columns side by side.
15
+ - `ariaLabel`: string — the name of a dialog with no `header` (with one, the header names it)
16
+ - `ariaDescribedby`: string | null — the `id` of the element that describes the dialog
17
+ - `alert`: boolean — `role="alertdialog"`, for a window that interrupts and demands an answer
18
+ - `ariaLabel`: string — the name of a dialog with no `header` (with one, the header names it)
19
+ - `ariaDescribedby`: string | null — the `id` of the element that describes the dialog
20
+ - `alert`: boolean — `role="alertdialog"`, for a window that interrupts and demands an answer
21
+ - `ariaLabel`: string — the name of a dialog with no `header` (with one, the header names it)
22
+ - `ariaDescribedby`: string | null — the `id` of the element that describes the dialog
23
+ - `alert`: boolean — `role="alertdialog"`, for a window that interrupts and demands an answer
24
+ - `ariaLabel`: string — the name of a dialog with no `header` (with one, the header names it)
25
+ - `ariaDescribedby`: string | null — the `id` of the element that describes the dialog
26
+ - `alert`: boolean — `role="alertdialog"`, for a window that interrupts and demands an answer
15
27
 
16
28
  ## Slots
17
29
  - the default content → the body; an element with the `kptDialogFooter` attribute → the footer
@@ -76,3 +88,9 @@ The negative side margins have to match its padding (`--kpt-space-6`),
76
88
  and the `bottom` offset has to mirror the negative bottom margin
77
89
  (`bottom: calc(var(--kpt-space-6) * -1)`) — stickiness is computed for the margin
78
90
  box, so with `bottom: 0` a sliver of content would slide underneath the bar.
91
+
92
+ ## Accessibility
93
+ `showModal()` gives the focus trap, Escape and the inert page; focus returns to the opener on
94
+ close. With `header` the dialog is named by its `<h2>` (`aria-labelledby`); without it pass
95
+ `ariaLabel`. `alert` + `ariaDescribedby` make it an alert dialog whose message is read out on
96
+ open — `kpt-confirm-container` uses exactly that.
@@ -22,5 +22,11 @@ without waiting for JavaScript. Both closed-state declarations live in the **bas
22
22
  attribute would flash on screen and then animate away. `prefers-reduced-motion: reduce`
23
23
  drops the transitions.
24
24
 
25
+ ## Focus and keyboard
26
+ Opening moves focus into the panel (`cdkFocusInitial`, else its first focusable element, else the
27
+ panel itself) and traps it there — `Tab` / `Shift+Tab` wrap inside, as `aria-modal="true"` promises.
28
+ Closing returns focus to the element that had it before. `Escape` closes the panel — only when `dismissible`, like the `×` button. The panel
29
+ is named by its `header` through `aria-labelledby`. The shared helper is `shared/modal-focus.ts` (on the CDK focus trap; the React port has a twin hook).
30
+
25
31
  ## Tokens
26
- The panel `--kpt-color-surface-raised`, `--kpt-elevation-4`; a semi-transparent backdrop.
32
+ The panel `--kpt-color-surface-raised`, `--kpt-elevation-4`; the backdrop `--kpt-color-overlay-scrim`.
@@ -6,6 +6,7 @@ Import: `import { KptEmpty } from '@konce-pt/angular';`
6
6
  ## Inputs
7
7
  - `icon`: string | null (default 'info-circle')
8
8
  - `title`: string; `description`: string
9
+ - `headingLevel`: 1–6 | null (default null) — makes the title a heading (`role="heading"` + `aria-level`)
9
10
  - Actions: `<ng-content>` (buttons, for instance).
10
11
 
11
12
  ## Example
@@ -15,3 +16,8 @@ Import: `import { KptEmpty } from '@konce-pt/angular';`
15
16
 
16
17
  ## Tokens
17
18
  The icon sits in a `--kpt-color-muted` circle; text `--kpt-color-on-surface(-muted)`.
19
+
20
+ ## Accessibility
21
+ The icon is decorative. The title is a styled paragraph unless `headingLevel` makes it a heading —
22
+ use that when the empty state stands in for a whole section. Replacing results with an empty state
23
+ is not announced; report “0 results” in a live region of your own.
@@ -1,6 +1,6 @@
1
1
  # KptFab (kpt-fab)
2
2
 
3
- A floating action button — a round, raised action button. Import: `import { KptFab } from '@konce-pt/angular';`
3
+ A floating action button — a raised action button (a rounded square; `extended` is a pill). Import: `import { KptFab } from '@konce-pt/angular';`
4
4
 
5
5
  ## Inputs
6
6
  - `variant`: 'filled' | 'tonal' (default 'filled')
@@ -8,6 +8,8 @@ A floating action button — a round, raised action button. Import: `import { Kp
8
8
  - `extended`: boolean (a pill with text)
9
9
  - `disabled`: boolean; `type`: 'button' | 'submit' | 'reset'
10
10
  - `ariaLabel`: string (required for the round, textless variant)
11
+ - `ariaExpanded`: `boolean | null` = `null`, `ariaControls`: `string | null` = `null` — for a FAB that opens
12
+ a panel (`kpt-speed-dial` uses them); they land on the inner `<button>`, the host has no button role
11
13
 
12
14
  ## Example
13
15
  <kpt-fab ariaLabel="Add"><kpt-icon name="plus" /></kpt-fab>
@@ -15,4 +17,5 @@ A floating action button — a round, raised action button. Import: `import { Kp
15
17
  <kpt-fab variant="tonal" size="mini" ariaLabel="Edit"><kpt-icon name="copy" /></kpt-fab>
16
18
 
17
19
  ## Tokens
18
- Background `--kpt-color-primary` / `--kpt-color-primary-container` (tonal); shadow `--kpt-elevation-3`.
20
+ Background `--kpt-color-primary` / `--kpt-color-muted` (tonal); shadow `--kpt-elevation-3`, `--kpt-elevation-4` on hover;
21
+ shape `--kpt-radius-lg` (md), `--kpt-radius-md` (mini), `--kpt-radius-full` (extended).
@@ -19,5 +19,16 @@ Import: `import { KptFileUpload } from '@konce-pt/angular';`
19
19
  The zone responds both to a click and to files dragged onto it. With `multiple=false` it keeps only the first file.
20
20
  The file list shows the name, the size and a remove button.
21
21
 
22
+ ## Keyboard and states
23
+ - The zone is `role="button"` with a single Tab stop: `Enter` and `Space` open the file picker,
24
+ the same as a click. The native `<input type="file">` is hidden, so without this a keyboard user
25
+ could not pick a file at all.
26
+ - `disabled` takes the zone out of the Tab order (`tabindex="-1"`, `aria-disabled`) and blocks
27
+ both picking and dropping.
28
+ - The error state (`aria-invalid`, a `--kpt-color-danger` border via `[data-invalid]`) shows once
29
+ the field is invalid and touched.
30
+ - List items get an icon by type: `photo` for `image/*`, `paperclip` for anything else.
31
+
22
32
  ## Tokens
23
- The zone uses `--kpt-form-field-border` (dashed), the dragover state `--kpt-color-primary`.
33
+ The zone `--kpt-color-border-strong` (dashed), hover / dragover `--kpt-color-primary`, error `--kpt-color-danger`,
34
+ focus ring `--kpt-color-focus-ring`.