@konce-pt/react 0.8.1 → 0.8.3

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 (123) hide show
  1. package/README.md +381 -27
  2. package/dist/accordion/llms.txt +56 -0
  3. package/dist/alert/llms.txt +45 -0
  4. package/dist/app-shell/app-shell.d.ts +20 -0
  5. package/dist/app-shell/app-shell.js +24 -0
  6. package/dist/app-shell/llms.txt +59 -0
  7. package/dist/auth/auth.d.ts +1 -1
  8. package/dist/auth/llms.txt +65 -0
  9. package/dist/autocomplete/autocomplete.d.ts +1 -1
  10. package/dist/autocomplete/llms.txt +44 -0
  11. package/dist/avatar/llms.txt +42 -0
  12. package/dist/avatar-group/avatar-group.d.ts +1 -1
  13. package/dist/avatar-group/llms.txt +38 -0
  14. package/dist/badge/llms.txt +38 -0
  15. package/dist/bottom-sheet/llms.txt +43 -0
  16. package/dist/breadcrumb/breadcrumb.d.ts +1 -1
  17. package/dist/breadcrumb/llms.txt +35 -0
  18. package/dist/button/llms.txt +56 -0
  19. package/dist/button-group/button-group.d.ts +1 -1
  20. package/dist/button-group/llms.txt +40 -0
  21. package/dist/card/llms.txt +60 -0
  22. package/dist/carousel/carousel.d.ts +1 -1
  23. package/dist/carousel/llms.txt +47 -0
  24. package/dist/charts/chart-legend.d.ts +1 -1
  25. package/dist/charts/llms.txt +57 -0
  26. package/dist/checkbox/llms.txt +39 -0
  27. package/dist/chip/llms.txt +41 -0
  28. package/dist/chips-input/llms.txt +40 -0
  29. package/dist/clock/llms.txt +50 -0
  30. package/dist/color-picker/color-picker.d.ts +1 -1
  31. package/dist/color-picker/llms.txt +40 -0
  32. package/dist/confirm/llms.txt +44 -0
  33. package/dist/context-menu/context-menu.d.ts +1 -1
  34. package/dist/context-menu/llms.txt +39 -0
  35. package/dist/data-table/data-table-types.d.ts +1 -1
  36. package/dist/data-table/data-table.d.ts +2 -10
  37. package/dist/data-table/data-table.js +17 -9
  38. package/dist/data-table/llms.txt +79 -0
  39. package/dist/data-view/data-view.d.ts +1 -1
  40. package/dist/data-view/llms.txt +49 -0
  41. package/dist/date-range/llms.txt +54 -0
  42. package/dist/datepicker/llms.txt +74 -0
  43. package/dist/dialog/llms.txt +51 -0
  44. package/dist/divider/llms.txt +28 -0
  45. package/dist/drawer/llms.txt +47 -0
  46. package/dist/empty/llms.txt +35 -0
  47. package/dist/fab/llms.txt +37 -0
  48. package/dist/fieldset/llms.txt +43 -0
  49. package/dist/file-upload/llms.txt +48 -0
  50. package/dist/form-field/llms.txt +55 -0
  51. package/dist/galleria/galleria.d.ts +1 -1
  52. package/dist/galleria/llms.txt +46 -0
  53. package/dist/grid/llms.txt +110 -0
  54. package/dist/icon/icon-registry.d.ts +5 -2
  55. package/dist/icon/icon-registry.js +5 -3
  56. package/dist/icon/llms.txt +66 -0
  57. package/dist/icon-button/llms.txt +38 -0
  58. package/dist/icons-entry/public-api.d.ts +5 -1
  59. package/dist/icons-entry/public-api.js +7 -1
  60. package/dist/image/llms.txt +46 -0
  61. package/dist/input/llms.txt +54 -0
  62. package/dist/input-mask/llms.txt +37 -0
  63. package/dist/input-number/llms.txt +44 -0
  64. package/dist/input-otp/llms.txt +43 -0
  65. package/dist/internal/use-breakpoint.js +18 -10
  66. package/dist/knob/llms.txt +46 -0
  67. package/dist/listbox/listbox.d.ts +1 -1
  68. package/dist/listbox/llms.txt +39 -0
  69. package/dist/map/llms.txt +108 -0
  70. package/dist/megamenu/llms.txt +48 -0
  71. package/dist/megamenu/megamenu.d.ts +1 -1
  72. package/dist/menu/llms.txt +56 -0
  73. package/dist/menu/menu-item.d.ts +1 -1
  74. package/dist/menu/menu-rows.d.ts +1 -1
  75. package/dist/menu/menu.d.ts +1 -1
  76. package/dist/menu/menu.js +12 -1
  77. package/dist/menubar/llms.txt +45 -0
  78. package/dist/menubar/menubar.d.ts +1 -1
  79. package/dist/meter-group/llms.txt +47 -0
  80. package/dist/meter-group/meter-group.d.ts +1 -1
  81. package/dist/order-list/llms.txt +41 -0
  82. package/dist/paginator/llms.txt +48 -0
  83. package/dist/paginator/paginator.d.ts +1 -1
  84. package/dist/paginator/paginator.js +7 -1
  85. package/dist/panel/llms.txt +55 -0
  86. package/dist/password/llms.txt +45 -0
  87. package/dist/pick-list/llms.txt +52 -0
  88. package/dist/popover/llms.txt +42 -0
  89. package/dist/progress/llms.txt +47 -0
  90. package/dist/public-api.d.ts +2 -1
  91. package/dist/public-api.js +1 -1
  92. package/dist/radio-group/llms.txt +40 -0
  93. package/dist/radio-group/radio-group.d.ts +1 -1
  94. package/dist/rating/llms.txt +43 -0
  95. package/dist/rich-text/llms.txt +61 -0
  96. package/dist/rich-text/rich-text.d.ts +1 -1
  97. package/dist/roadmap/llms.txt +82 -0
  98. package/dist/scroll-top/llms.txt +41 -0
  99. package/dist/select/llms.txt +56 -0
  100. package/dist/select/select.d.ts +1 -1
  101. package/dist/sidenav/llms.txt +53 -0
  102. package/dist/skeleton/llms.txt +33 -0
  103. package/dist/slider/llms.txt +50 -0
  104. package/dist/speed-dial/llms.txt +46 -0
  105. package/dist/speed-dial/speed-dial.d.ts +1 -1
  106. package/dist/spinner/llms.txt +33 -0
  107. package/dist/split-button/llms.txt +54 -0
  108. package/dist/split-button/split-button.d.ts +1 -1
  109. package/dist/splitter/llms.txt +44 -0
  110. package/dist/stepper/llms.txt +64 -0
  111. package/dist/switch/llms.txt +42 -0
  112. package/dist/switch-group/llms.txt +43 -0
  113. package/dist/switch-group/switch-group.d.ts +1 -1
  114. package/dist/tabs/llms.txt +48 -0
  115. package/dist/textarea/llms.txt +40 -0
  116. package/dist/timeline/llms.txt +53 -0
  117. package/dist/timeline/timeline.d.ts +1 -1
  118. package/dist/toast/llms.txt +52 -0
  119. package/dist/toolbar/llms.txt +45 -0
  120. package/dist/tooltip/llms.txt +42 -0
  121. package/dist/tree/llms.txt +45 -0
  122. package/dist/tree/tree.d.ts +2 -2
  123. package/package.json +11 -11
@@ -0,0 +1,48 @@
1
+ # KptMegamenu (@konce-pt/react)
2
+
3
+ A mega menu — a horizontal bar with a wide, multi-column panel.
4
+ Import: `import { KptMegamenu } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-megamenu-host">
8
+ <nav class="kpt-megamenu" role="menubar">
9
+ <button class="kpt-megamenu__top is-open" role="menuitem">Products …caret…</button>
10
+ </nav>
11
+ </div>
12
+ <!-- while open, in a portal: -->
13
+ <div class="kpt-megamenu__panel" role="menu">
14
+ <div class="kpt-megamenu__column">
15
+ <div class="kpt-megamenu__col-title">Components</div>
16
+ <button class="kpt-megamenu__link">Forms</button>
17
+ </div>
18
+ </div>
19
+
20
+ ## Props
21
+ - `items`: `KptMenuItem<T>[]` — three levels: top item → `items` (columns) → column `items` (links)
22
+ - `onSelect(link)` — a picked link from a column
23
+ - `className`, `ref` and every other `<div>` prop go to the host
24
+
25
+ ## The panel is anchored to the whole bar
26
+ Not to the clicked button: the panel is wide, so it should start at the edge of the menu rather
27
+ than at whichever item happened to be pressed. Switching to another top item swaps the columns
28
+ without closing the panel, so browsing across sections costs one click each.
29
+
30
+ ## Examples
31
+ <KptMegamenu items={items} onSelect={onSelect} />
32
+
33
+ // top → columns → links
34
+ const items: KptMenuItem[] = [{
35
+ label: 'Products',
36
+ items: [
37
+ { label: 'Components', items: [{ label: 'Forms' }, { label: 'Tables' }] },
38
+ { label: 'Templates', items: [{ label: 'Dashboard' }] },
39
+ ],
40
+ }];
41
+
42
+ ## Tokens
43
+ `--kpt-color-surface-raised`, `--kpt-color-border`, `--kpt-elevation-3`,
44
+ `--kpt-color-on-surface-muted` (the column titles).
45
+
46
+ ## Accessibility
47
+ The bar is `role="menubar"` with `role="menuitem"` buttons; the panel is `role="menu"`. Column
48
+ titles are plain text, not headings, so they do not disturb the page outline.
@@ -1,7 +1,7 @@
1
1
  import { type ComponentPropsWithRef } from 'react';
2
2
  import type { KptMenuItem } from '../menu/menu-item.ts';
3
3
  export interface KptMegamenuProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onSelect'> {
4
- items?: KptMenuItem<T>[];
4
+ items?: readonly KptMenuItem<T>[];
5
5
  onSelect?: (item: KptMenuItem<T>) => void;
6
6
  }
7
7
  /**
@@ -0,0 +1,56 @@
1
+ # KptMenu (@konce-pt/react)
2
+
3
+ A dropdown menu. Items come from `items`, the trigger from the `trigger` prop.
4
+ Import: `import { KptMenu, type KptMenuItem } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <span class="kpt-menu-host"><span class="kpt-menu__trigger">…trigger…</span></span>
8
+ <!-- while open, in a portal on document.body: -->
9
+ <div class="kpt-menu__panel" role="menu">
10
+ <div class="kpt-menu__header" role="presentation">…</div>
11
+ <div class="kpt-menu__separator" role="separator"></div>
12
+ <button class="kpt-menu__item" role="menuitem">…</button>
13
+ </div>
14
+
15
+ ## Props
16
+ - `items`: `KptMenuItem<T>[]`
17
+ - `trigger`: ReactNode — the element that opens the menu, rendered in place
18
+ - `onSelect(item)` — the picked item; headers, separators and disabled items never arrive here
19
+ - `open` / `defaultOpen` / `onOpenChange` — controlled or uncontrolled
20
+ - `className`, `ref` and every other `<span>` prop go to the host
21
+
22
+ ## KptMenuItem
23
+ `label`, `value`, `icon`, `description` (a second line), `badge` + `badgeVariant`,
24
+ `avatar` (`{ src?, name?, icon? }` — the header row of a user menu), `header` (a non-clickable
25
+ block instead of an item), `disabled`, `danger`, `separator`, plus `items` and `url` for the
26
+ menubar and megamenu that build on the same shape.
27
+
28
+ ## The panel is a portal
29
+ It renders through the internal `KptOverlay`, so no overlay stylesheet is required — unlike the
30
+ Angular port, which stands on CDK. Position, backdrop and Escape behave the same.
31
+
32
+ ## Examples
33
+ <KptMenu items={items} onSelect={onSelect} trigger={<KptButton variant="outline">Options</KptButton>} />
34
+
35
+ const items: KptMenuItem[] = [
36
+ { header: true, avatar: { src: '/u/admin.jpg' }, label: 'Admin', description: 'admin@konce.pt' },
37
+ { separator: true },
38
+ { label: 'Edit', value: 'edit', icon: 'copy' },
39
+ { label: 'Notifications', value: 'notif', icon: 'bell', badge: 4, badgeVariant: 'success' },
40
+ { separator: true },
41
+ { label: 'Delete', value: 'del', icon: 'x', danger: true },
42
+ ];
43
+
44
+ ## Tokens
45
+ `--kpt-color-surface-raised`, `--kpt-color-border`, `--kpt-elevation-3`, `--kpt-color-danger`
46
+ (the `danger` item), `--kpt-z-overlay`.
47
+
48
+ ## Accessibility
49
+ The panel is `role="menu"`, items are native buttons with `role="menuitem"`, separators carry
50
+ `role="separator"` and header rows `role="presentation"`, so a screen reader skips them instead of
51
+ announcing them as actions.
52
+
53
+ The trigger itself gets `aria-haspopup="menu"` and a live `aria-expanded`. They are placed on the
54
+ interactive control INSIDE the slot (the projected `<button>`/`<a>`), never on the
55
+ `.kpt-menu__trigger` wrapper — giving that wrapper a role would create a nested control and a second
56
+ tab stop, and state attributes on a roleless element violate `aria-allowed-attr`.
@@ -27,7 +27,7 @@ export interface KptMenuItem<T = unknown> {
27
27
  danger?: boolean;
28
28
  separator?: boolean;
29
29
  /** Pozycje podrzędne (menubar / megamenu). */
30
- items?: KptMenuItem<T>[];
30
+ items?: readonly KptMenuItem<T>[];
31
31
  /** Adres odnośnika (menubar / megamenu). */
32
32
  url?: string;
33
33
  }
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { KptMenuItem } from './menu-item.ts';
3
3
  export interface MenuRowsProps<T> {
4
- items: KptMenuItem<T>[];
4
+ items: readonly KptMenuItem<T>[];
5
5
  /** Prefiks bloku BEM: `kpt-menu` albo `kpt-context-menu`. */
6
6
  block: string;
7
7
  onPick: (item: KptMenuItem<T>) => void;
@@ -1,7 +1,7 @@
1
1
  import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
2
  import type { KptMenuItem } from './menu-item.ts';
3
3
  export interface KptMenuProps<T> extends Omit<ComponentPropsWithRef<'span'>, 'onSelect'> {
4
- items?: KptMenuItem<T>[];
4
+ items?: readonly KptMenuItem<T>[];
5
5
  /** Element otwierający menu — renderowany w miejscu komponentu. */
6
6
  trigger: ReactNode;
7
7
  /** Wybrana pozycja; pozycje `header`, `separator` i wyłączone nigdy tu nie trafiają. */
package/dist/menu/menu.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useCallback, useRef } from 'react';
2
+ import { useCallback, useEffect, useRef } from 'react';
3
3
  import { cn } from "../internal/cn.js";
4
4
  import { KptOverlay } from "../internal/overlay.js";
5
5
  import { useControllableState } from "../internal/use-controllable-state.js";
@@ -21,6 +21,17 @@ export function KptMenu({ items = [], trigger, onSelect, open, defaultOpen = fal
21
21
  onChange: onOpenChange,
22
22
  });
23
23
  const close = useCallback(() => setOpen(false), [setOpen]);
24
+ // ARIA idzie na kontrolkę wewnątrz slotu, nie na `.kpt-menu__trigger`. Trigger to zwykły
25
+ // `<span>` opakowujący dowolny węzeł z propa `trigger`: nadanie mu `role="button"` zrobiłoby
26
+ // zagnieżdżoną kontrolkę i drugi tab stop. `cloneElement` też odpada — `trigger` bywa
27
+ // komponentem, który nie przekazuje nieznanych propsów dalej na DOM.
28
+ useEffect(() => {
29
+ const control = triggerRef.current?.querySelector('button, a, [role="button"]');
30
+ if (!control)
31
+ return;
32
+ control.setAttribute('aria-haspopup', 'menu');
33
+ control.setAttribute('aria-expanded', String(isOpen));
34
+ }, [isOpen, trigger]);
24
35
  const pick = (item) => {
25
36
  if (item.disabled)
26
37
  return;
@@ -0,0 +1,45 @@
1
+ # KptMenubar (@konce-pt/react)
2
+
3
+ A horizontal menu bar with dropdowns. An item without `items` acts as an action or a link.
4
+ Import: `import { KptMenubar } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-menubar-host">
8
+ <nav class="kpt-menubar" role="menubar">
9
+ <div class="kpt-menubar__group">
10
+ <button class="kpt-menubar__top is-open" role="menuitem">File …caret…</button>
11
+ </div>
12
+ </nav>
13
+ </div>
14
+ <!-- while open, in a portal: -->
15
+ <div class="kpt-menubar__dropdown" role="menu">…items and separators…</div>
16
+
17
+ ## Props
18
+ - `items`: `KptMenuItem<T>[]` — a top item's `items` become its dropdown
19
+ - `onSelect(item)` — an action item, or a pick from a dropdown
20
+ - `className`, `ref` and every other `<div>` prop go to the host
21
+
22
+ ## The dropdown is a portal
23
+ It renders outside the bar, so a parent with `overflow: hidden` cannot clip it — the same benefit
24
+ the Angular port gets from CDK Overlay, without CDK. Each dropdown is anchored to its own top
25
+ button, so it opens directly under the label it belongs to.
26
+
27
+ ## Top items do double duty
28
+ With `items` a top item toggles its dropdown; without them it fires `onSelect` straight away, so a
29
+ bar can mix menus and plain actions with no extra flag.
30
+
31
+ ## Examples
32
+ <KptMenubar items={items} onSelect={onSelect} />
33
+
34
+ const items: KptMenuItem[] = [
35
+ { label: 'File', items: [{ label: 'New' }, { separator: true }, { label: 'Close', danger: true }] },
36
+ { label: 'Help' },
37
+ ];
38
+
39
+ ## Tokens
40
+ `--kpt-color-surface`, `--kpt-color-muted` (the open top item), `--kpt-color-surface-raised` and
41
+ `--kpt-elevation-3` for the dropdown, `--kpt-color-danger`.
42
+
43
+ ## Accessibility
44
+ The bar is `role="menubar"`, top items and dropdown rows are `role="menuitem"`, separators carry
45
+ `role="separator"`.
@@ -1,7 +1,7 @@
1
1
  import { type ComponentPropsWithRef } from 'react';
2
2
  import type { KptMenuItem } from '../menu/menu-item.ts';
3
3
  export interface KptMenubarProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onSelect'> {
4
- items?: KptMenuItem<T>[];
4
+ items?: readonly KptMenuItem<T>[];
5
5
  onSelect?: (item: KptMenuItem<T>) => void;
6
6
  }
7
7
  /**
@@ -0,0 +1,47 @@
1
+ # KptMeterGroup (@konce-pt/react)
2
+
3
+ A multi-segment meter with an optional legend.
4
+ Import: `import { KptMeterGroup } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-meter-group-host">
8
+ <div class="kpt-meter-group">
9
+ <div class="kpt-meter-group__track" role="meter" aria-valuenow="100">
10
+ <span class="kpt-meter-group__segment" style="width:45%" title="Documents"></span>…
11
+ </div>
12
+ <ul class="kpt-meter-group__legend">
13
+ <li class="kpt-meter-group__legend-item">
14
+ <span class="kpt-meter-group__dot"></span><span>Documents</span>
15
+ <span class="kpt-meter-group__val">45%</span>
16
+ </li>…
17
+ </ul>
18
+ </div>
19
+ </div>
20
+
21
+ ## Props
22
+ - `values`: `KptMeterItem[]` — `{ label, value, color? }`
23
+ - `max`: number — the reference total; without it the values' sum is 100%
24
+ - `showLegend`: boolean (default true)
25
+ - `className`, `ref` and every other `<div>` prop go to the host
26
+
27
+ ## Percentages come from the sum, not from 100
28
+ Without `max` the reference is the sum of the values, so `[45, 25, 15, 15]` and `[9, 5, 3, 3]`
29
+ draw the same picture. Pass `max` when the segments are meant to leave a gap — a quota that is
30
+ not full yet. All-zero values fall back to a divisor of 1 instead of producing `NaN%`.
31
+
32
+ ## Colours
33
+ `color` per item, otherwise the next one from the semantic palette
34
+ (`primary → info → success → warning → danger`, cycled), so a group of any length stays readable
35
+ without picking colours by hand.
36
+
37
+ ## Examples
38
+ <KptMeterGroup values={[{ label: 'Used', value: 70 }, { label: 'Free', value: 30 }]} />
39
+ <KptMeterGroup values={values} max={200} showLegend={false} />
40
+
41
+ ## Tokens
42
+ The palette `--kpt-color-{primary,info,success,warning,danger}`, the track
43
+ `--kpt-color-surface-sunken`.
44
+
45
+ ## Accessibility
46
+ The track is `role="meter"` with `aria-valuenow`; every segment carries a native `title`, and the
47
+ legend repeats the same values as text.
@@ -6,7 +6,7 @@ export interface KptMeterItem {
6
6
  color?: string;
7
7
  }
8
8
  export interface KptMeterGroupProps extends ComponentPropsWithRef<'div'> {
9
- values?: KptMeterItem[];
9
+ values?: readonly KptMeterItem[];
10
10
  /** Suma odniesienia; domyślnie suma wartości, czyli segmenty wypełniają całość. */
11
11
  max?: number;
12
12
  showLegend?: boolean;
@@ -0,0 +1,41 @@
1
+ # KptOrderList (@konce-pt/react)
2
+
3
+ A list with manual reordering. Click selects an item, the buttons move it up and down.
4
+ Import: `import { KptOrderList } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-order-list-host">
8
+ <div class="kpt-order-list">
9
+ <div class="kpt-order-list__controls">…up, down…</div>
10
+ <div class="kpt-order-list__panel">
11
+ <div class="kpt-order-list__header">Order</div>
12
+ <ul class="kpt-order-list__items">
13
+ <li class="kpt-order-list__item is-selected">…</li>…
14
+ </ul>
15
+ </div>
16
+ </div>
17
+ </div>
18
+
19
+ ## Props
20
+ - `items` / `defaultItems` / `onItemsChange` — the list; the callback receives the new order
21
+ - `header`: string
22
+ - `renderItem(item, index)` — required; the equivalent of `<ng-template let-item>`
23
+ - `className`, `ref` and every other `<div>` prop go to the host
24
+
25
+ ## The selection follows the item
26
+ After a move the selection jumps to the new index, so pressing the button again moves the same
27
+ entry — with the selection pinned to a position, the second press would move its neighbour.
28
+
29
+ ## Examples
30
+ <KptOrderList items={tasks} onItemsChange={setTasks} header="Order" renderItem={(item) => item} />
31
+ <KptOrderList defaultItems={steps} renderItem={(step) => step.name} />
32
+
33
+ ## i18n
34
+ The buttons use `orderList.up` and `orderList.down`.
35
+
36
+ ## Tokens
37
+ The selection `--kpt-color-primary`, the buttons `--kpt-color-surface-raised`.
38
+
39
+ ## Accessibility
40
+ Both buttons are labelled from the dictionary and go disabled while nothing is selected, so the
41
+ control never looks broken.
@@ -0,0 +1,48 @@
1
+ # KptPaginator (@konce-pt/react)
2
+
3
+ Page-size selector, item range and navigation.
4
+ Import: `import { KptPaginator } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-paginator">
8
+ <div class="kpt-paginator__size"><label>Rows: <select class="kpt-paginator__select">…</select></label></div>
9
+ <span class="kpt-paginator__range">1–10 of 120</span>
10
+ <div class="kpt-paginator__nav">…two KptButton…</div>
11
+ </div>
12
+
13
+ ## Props
14
+ - `length`: number — the total number of items (required)
15
+ - `pageIndex` / `defaultPageIndex` / `onPageIndexChange` — the 0-based page
16
+ - `pageSize` / `defaultPageSize` / `onPageSizeChange` — the page size (default 10)
17
+ - `pageSizeOptions`: readonly number[] (default [5, 10, 20, 50])
18
+
19
+ The select always offers the current `pageSize` even when it is absent from this list: without
20
+ that, `pageSize={8}` against the defaults left no matching option, so the control displayed the
21
+ first entry while the table paged by eight.
22
+ - `prevIcon`, `nextIcon`: ReactNode — the navigation button content
23
+ - `locale`, `dictionary` — i18n overrides for this component only
24
+ - `className`, `ref` and every other `<div>` prop go to the paginator root
25
+
26
+ ## Behaviour
27
+ Works controlled and uncontrolled. Changing the page size returns to the first page. The index is
28
+ clamped whenever `length` or `pageSize` shrinks it out of range, so the component never shows an
29
+ empty page after the data changes underneath it.
30
+
31
+ ## i18n
32
+ Labels come from the dictionary: `paginator.rowsPerPage`, `paginator.prevPage`,
33
+ `paginator.nextPage` and `paginator.range` with `{start}`, `{end}` and `{total}` interpolation.
34
+
35
+ ## Icons
36
+ The default arrows are `KptIcon` with `chevron-left` / `chevron-right` from the built-in set, so
37
+ they work without registering the full Tabler set. Pass `prevIcon` / `nextIcon` to swap in your own.
38
+
39
+ ## Examples
40
+ <KptPaginator length={120} pageIndex={page} onPageIndexChange={setPage} />
41
+ <KptPaginator length={total} defaultPageSize={20} pageSizeOptions={[20, 50, 100]} />
42
+
43
+ ## Tokens
44
+ `--kpt-form-field-{bg,text,border,border-focus}` for the select, plus the button tokens.
45
+
46
+ ## Accessibility
47
+ The navigation buttons carry `aria-label` from the dictionary and go `disabled` at the ends of the
48
+ range, so the keyboard never lands on a dead control.
@@ -12,7 +12,7 @@ export interface KptPaginatorProps extends Omit<ComponentPropsWithRef<'div'>, 'c
12
12
  defaultPageIndex?: number;
13
13
  onPageIndexChange?: (pageIndex: number) => void;
14
14
  /** Dostępne rozmiary strony. */
15
- pageSizeOptions?: number[];
15
+ pageSizeOptions?: readonly number[];
16
16
  /** Treść przycisków nawigacji; domyślnie strzałki z wbudowanego zestawu ikon. */
17
17
  prevIcon?: ReactNode;
18
18
  nextIcon?: ReactNode;
@@ -41,5 +41,11 @@ export function KptPaginator({ length, pageSize, defaultPageSize = 10, onPageSiz
41
41
  setSize(Number(event.target.value));
42
42
  setIndex(0);
43
43
  };
44
- return (_jsxs("div", { className: cn('kpt-paginator', className), ...rest, children: [_jsx("div", { className: "kpt-paginator__size", children: _jsxs("label", { children: [t('paginator.rowsPerPage'), _jsx("select", { className: "kpt-paginator__select", value: size, onChange: onSizeChange, children: pageSizeOptions.map((option) => (_jsx("option", { value: option, children: option }, option))) })] }) }), _jsx("span", { className: "kpt-paginator__range", children: t('paginator.range', { start: rangeStart, end: rangeEnd, total: length }) }), _jsxs("div", { className: "kpt-paginator__nav", children: [_jsx(KptButton, { variant: "outline", size: "sm", disabled: !canPrev, onClick: () => setIndex(index - 1), "aria-label": t('paginator.prevPage'), children: prevIcon }), _jsx(KptButton, { variant: "outline", size: "sm", disabled: !canNext, onClick: () => setIndex(index + 1), "aria-label": t('paginator.nextPage'), children: nextIcon })] })] }));
44
+ // Opcje selecta uzupełnione o bieżący rozmiar. Bez tego `pageSize` spoza listy nie ma
45
+ // odpowiadającej opcji: React ostrzega o `value` bez dopasowania, a select pokazuje
46
+ // pierwszą pozycję, choć stronicowanie idzie po zupełnie innej liczbie.
47
+ const sizeOptions = pageSizeOptions.includes(size)
48
+ ? pageSizeOptions
49
+ : [...pageSizeOptions, size].sort((a, b) => a - b);
50
+ return (_jsxs("div", { className: cn('kpt-paginator', className), ...rest, children: [_jsx("div", { className: "kpt-paginator__size", children: _jsxs("label", { children: [t('paginator.rowsPerPage'), _jsx("select", { className: "kpt-paginator__select", value: size, onChange: onSizeChange, children: sizeOptions.map((option) => (_jsx("option", { value: option, children: option }, option))) })] }) }), _jsx("span", { className: "kpt-paginator__range", children: t('paginator.range', { start: rangeStart, end: rangeEnd, total: length }) }), _jsxs("div", { className: "kpt-paginator__nav", children: [_jsx(KptButton, { variant: "outline", size: "sm", disabled: !canPrev, onClick: () => setIndex(index - 1), "aria-label": t('paginator.prevPage'), children: prevIcon }), _jsx(KptButton, { variant: "outline", size: "sm", disabled: !canNext, onClick: () => setIndex(index + 1), "aria-label": t('paginator.nextPage'), children: nextIcon })] })] }));
45
51
  }
@@ -0,0 +1,55 @@
1
+ # KptPanel (@konce-pt/react)
2
+
3
+ A panel with a header and optional collapsing.
4
+ Import: `import { KptPanel } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-panel-host" style="--kpt-anim-duration: 500ms">
8
+ <div class="kpt-panel">
9
+ <div class="kpt-panel__header">
10
+ <span class="kpt-panel__title">Settings</span>
11
+ <span class="kpt-panel__actions">…actions…</span>
12
+ <button class="kpt-panel__toggle" aria-expanded="true" aria-label="Collapse / expand">…</button>
13
+ </div>
14
+ <div class="kpt-panel__collapse is-open">
15
+ <div class="kpt-panel__collapse-inner">
16
+ <div class="kpt-panel__body">…children…</div>
17
+ </div>
18
+ </div>
19
+ </div>
20
+ </div>
21
+
22
+ ## Props
23
+ - `header`: string
24
+ - `toggleable`: boolean — adds the collapse button to the header
25
+ - `collapsed` / `defaultCollapsed` / `onCollapsedChange` — controlled or uncontrolled
26
+ - `animated`: boolean (default true), `animationDuration`: number (ms, default 500)
27
+ - `locale`, `dictionary` — i18n overrides for this component only
28
+ - `className`, `ref` and every other `<div>` prop go to the host
29
+
30
+ ## Sub-components
31
+ - `KptPanel.Actions` — lifted into the header, next to the title, before the collapse button.
32
+
33
+ ## Collapsed content stays mounted
34
+ It gets `inert` and `aria-hidden` rather than being removed, so the height is animatable while
35
+ nothing inside can take focus or be read out. That is also why a collapsed panel keeps the state of
36
+ whatever lives in it — a half-filled form inside survives a collapse.
37
+
38
+ ## i18n
39
+ The toggle's label comes from `panel.toggle` in the dictionary.
40
+
41
+ ## Examples
42
+ <KptPanel header="Settings" toggleable>Panel content…</KptPanel>
43
+
44
+ <KptPanel header="Filters" toggleable collapsed={collapsed} onCollapsedChange={setCollapsed}>
45
+ <KptPanel.Actions><KptIconButton aria-label="Reset"><KptIcon name="x" /></KptIconButton></KptPanel.Actions>
46
+ …
47
+ </KptPanel>
48
+
49
+ ## Tokens
50
+ `--kpt-color-surface`, `--kpt-color-border`, `--kpt-radius-lg`, `--kpt-motion-easing-standard`.
51
+
52
+ ## Accessibility
53
+ The toggle is a native button with `aria-expanded` and a label from the dictionary. The header
54
+ title is a `<span>`, not a heading — give the panel your own heading when it needs one in the
55
+ document outline.
@@ -0,0 +1,45 @@
1
+ # KptPassword (@konce-pt/react)
2
+
3
+ A password field with a reveal toggle and an optional strength meter.
4
+ Import: `import { KptPassword } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-password-host">
8
+ <div class="kpt-password">
9
+ <input class="kpt-password__input" type="password" autocomplete="current-password">
10
+ <button class="kpt-password__toggle" type="button" aria-label="Show password">…</button>
11
+ </div>
12
+ <div class="kpt-password__meter" data-score="3">
13
+ <div class="kpt-password__bars"><span class="kpt-password__bar is-on"></span>…</div>
14
+ <span class="kpt-password__hint">Good</span>
15
+ </div>
16
+ </div>
17
+
18
+ ## Props
19
+ - `value` / `defaultValue` / `onValueChange`
20
+ - `feedback`: boolean — shows the strength meter once something is typed
21
+ - `autoComplete`: string | null (default 'current-password')
22
+ - `placeholder`, `id`, `disabled`, `invalid`, `touched`, `onTouch()`
23
+ - `locale`, `dictionary` — i18n overrides for this component only
24
+
25
+ ## autoComplete is not a detail
26
+ Sign-up and password reset need `autoComplete="new-password"`. With the default, a password manager
27
+ fills in the OLD password instead of offering a new one, and the user ends up saving the wrong
28
+ thing.
29
+
30
+ ## How the score is computed
31
+ Four independent criteria, one point each: at least 8 characters, both letter cases, a digit, a
32
+ non-alphanumeric character. The label comes from `password.strength` — the only array-valued key in
33
+ the dictionary — indexed by the score, so a translation controls the wording without touching code.
34
+
35
+ ## Examples
36
+ <KptPassword value={pass} onValueChange={setPass} feedback />
37
+ <KptPassword value={pass} onValueChange={setPass} autoComplete="new-password" feedback />
38
+
39
+ ## Tokens
40
+ `--kpt-form-field-*` for the field, `--kpt-color-danger` / `-warning` / `-success` for the meter
41
+ bars by score.
42
+
43
+ ## Accessibility
44
+ The toggle's label swaps between `password.show` and `password.hide`, so a screen reader knows what
45
+ pressing it will do rather than just that a button exists.
@@ -0,0 +1,52 @@
1
+ # KptPickList (@konce-pt/react)
2
+
3
+ Transfers items between two lists. Click to select, the middle buttons move the selection or
4
+ everything.
5
+ Import: `import { KptPickList } from '@konce-pt/react';`
6
+
7
+ ## DOM
8
+ <div class="kpt-pick-list-host">
9
+ <div class="kpt-pick-list">
10
+ <div class="kpt-pick-list__col">
11
+ <div class="kpt-pick-list__header">Available</div>
12
+ <ul class="kpt-pick-list__items">
13
+ <li class="kpt-pick-list__item is-selected">…</li>…
14
+ </ul>
15
+ </div>
16
+ <div class="kpt-pick-list__controls">…four buttons…</div>
17
+ <div class="kpt-pick-list__col">…</div>
18
+ </div>
19
+ </div>
20
+
21
+ ## Props
22
+ - `source` / `defaultSource` / `onSourceChange` — the left list
23
+ - `target` / `defaultTarget` / `onTargetChange` — the right list
24
+ - `sourceHeader`, `targetHeader` — without them `pickList.available` / `pickList.selected`
25
+ - `renderItem(item, index)` — required; the equivalent of `<ng-template let-item>`
26
+ - `className`, `ref` and every other `<div>` prop go to the host
27
+
28
+ ## The selection is kept by reference
29
+ Selected items live in a `Set` of references, not of indexes: after a move the indexes on both
30
+ sides shift, while a reference stays the same. That is also why a moved item never carries its
31
+ selection over — the selection is cleared on every move.
32
+
33
+ ## Two lists, two controlled values
34
+ Both sides are independent controllable values, so the component works uncontrolled (`default*`),
35
+ half-controlled, or fully controlled by the form.
36
+
37
+ ## Examples
38
+ <KptPickList
39
+ source={available} onSourceChange={setAvailable}
40
+ target={selected} onTargetChange={setSelected}
41
+ renderItem={(item) => item.name}
42
+ />
43
+
44
+ ## i18n
45
+ The headers and the four move buttons come from the `pickList` namespace.
46
+
47
+ ## Tokens
48
+ The selection `--kpt-color-primary`, the headers `--kpt-color-surface-variant`.
49
+
50
+ ## Accessibility
51
+ Every move button is labelled from the dictionary, so "move all right" is distinguishable from
52
+ "move right" without seeing the double chevron.
@@ -0,0 +1,42 @@
1
+ # KptPopover (@konce-pt/react)
2
+
3
+ Any content in a bubble pinned to its trigger — richer than a tooltip.
4
+ Import: `import { KptPopover } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <span class="kpt-popover-host">
8
+ <span class="kpt-popover__trigger">…trigger…</span>
9
+ </span>
10
+ <!-- while open, in a portal on document.body: -->
11
+ <div class="kpt-popover__panel" role="dialog">…children…</div>
12
+
13
+ ## Props
14
+ - `trigger`: ReactNode — the element that opens the bubble, rendered in place
15
+ - `children`: ReactNode — the panel content
16
+ - `open` / `defaultOpen` / `onOpenChange` — controlled or uncontrolled
17
+ - `className`, `ref` and every other `<span>` prop go to the host
18
+
19
+ ## The panel is a portal
20
+ The Angular port stands on CDK Overlay. Here the panel renders into a portal on `document.body`
21
+ with the same behaviour: positioned below the trigger, flipping above when there is no room, closed
22
+ by a click outside or by Escape, and following scroll and resize.
23
+
24
+ Clicking the trigger while the bubble is open closes it and does not reopen it — the transparent
25
+ backdrop takes that click, exactly as the CDK backdrop does.
26
+
27
+ ## Examples
28
+ <KptPopover trigger={<KptButton variant="outline">Details</KptButton>}>
29
+ <div>Richer content in the bubble.</div>
30
+ </KptPopover>
31
+
32
+ <KptPopover open={open} onOpenChange={setOpen} trigger={<KptButton>Filters</KptButton>}>
33
+ <FilterForm onDone={() => setOpen(false)} />
34
+ </KptPopover>
35
+
36
+ ## Tokens
37
+ `--kpt-color-surface-raised`, `--kpt-color-border`, `--kpt-radius-md`, `--kpt-elevation-3`,
38
+ `--kpt-z-overlay`.
39
+
40
+ ## Accessibility
41
+ The panel is `role="dialog"` and Escape closes it. Focus is not trapped — the popover is meant for
42
+ supporting content, so for a real modal reach for a dialog instead.
@@ -0,0 +1,47 @@
1
+ # KptProgress (@konce-pt/react)
2
+
3
+ A progress indicator — linear or circular, determinate (0–100) or indeterminate (`value` = null).
4
+ Import: `import { KptProgress } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <!-- linear -->
8
+ <div class="kpt-progress-host">
9
+ <div class="kpt-progress__linear" data-variant="primary" role="progressbar" aria-valuenow="65">
10
+ <div class="kpt-progress__bar" style="width: 65%"></div>
11
+ </div>
12
+ </div>
13
+
14
+ <!-- circular -->
15
+ <svg class="kpt-progress__circular" data-variant="success" viewBox="0 0 40 40" role="progressbar" aria-valuenow="75">
16
+ <circle class="kpt-progress__track" cx="20" cy="20" r="16"></circle>
17
+ <circle class="kpt-progress__bar" cx="20" cy="20" r="16" style="stroke-dasharray: 100.531; stroke-dashoffset: 25.1327"></circle>
18
+ </svg>
19
+
20
+ ## Props
21
+ - `value`: number | null (default null) — 0–100, or null for indeterminate
22
+ - `variant`: 'primary' | 'success' | 'danger' | 'warning' | 'info' (default 'primary')
23
+ - `type`: 'linear' | 'circular' (default 'linear')
24
+ - `diameter`: number (default 40) — the circular variant's size in pixels
25
+ - `className`, `ref` and every other `<div>` prop go to the host
26
+
27
+ ## How the arc is drawn
28
+ The circle lives in a fixed `viewBox="0 0 40 40"` with `r=16`, so the circumference is computed
29
+ from that radius, not from `diameter` — the SVG scales, the maths does not change. The arc is the
30
+ dash offset: full circumference means empty, zero means complete. An indeterminate circle is pinned
31
+ at a quarter of the circumference and spun by CSS.
32
+
33
+ Values outside 0–100 are clamped rather than rejected, so a computed percentage that briefly
34
+ overshoots cannot break the drawing.
35
+
36
+ ## Examples
37
+ <KptProgress value={65} />
38
+ <KptProgress value={null} variant="info" />
39
+ <KptProgress type="circular" value={75} variant="success" diameter={64} />
40
+
41
+ ## Tokens
42
+ The semantic colour of each variant (`--kpt-color-primary` / `-success` / `-danger` / `-warning` /
43
+ `-info`), `--kpt-color-muted` for the track.
44
+
45
+ ## Accessibility
46
+ `role="progressbar"` with `aria-valuenow`; an indeterminate bar leaves the value out, which is how
47
+ a screen reader learns the progress is unknown rather than zero.