@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
@@ -1,4 +1,4 @@
1
- export { KptAppShell, useKptAppShell, useKptShellNavToggle } from './app-shell/app-shell.tsx';
1
+ export { KptAppShell, KptNavLabel, KptNavSection, useKptAppShell, useKptShellNavToggle } from './app-shell/app-shell.tsx';
2
2
  export type { KptAppShellContextValue, KptAppShellProps, KptSidenavMode } from './app-shell/app-shell.tsx';
3
3
  export { KptToolbar, KptToolbarSpacer } from './toolbar/toolbar.tsx';
4
4
  export type { KptToolbarProps } from './toolbar/toolbar.tsx';
@@ -31,6 +31,7 @@ export type { KptSkeletonProps, KptSkeletonVariant } from './skeleton/skeleton.t
31
31
  export { KptIcon } from './icon/icon.tsx';
32
32
  export type { KptIconProps } from './icon/icon.tsx';
33
33
  export { getKptIcon, hasKptIcon, registerKptIcons } from './icon/icon-registry.ts';
34
+ export type { KptIconDef, KptIconInput } from '@konce-pt/icons';
34
35
  export { KptAvatar } from './avatar/avatar.tsx';
35
36
  export type { KptAvatarProps, KptAvatarShape, KptAvatarSize } from './avatar/avatar.tsx';
36
37
  export { KptBadge } from './badge/badge.tsx';
@@ -6,7 +6,7 @@
6
6
  * jest wspólna i nie ma tu własnych stylów.
7
7
  */
8
8
  // Komponenty — układ
9
- export { KptAppShell, useKptAppShell, useKptShellNavToggle } from "./app-shell/app-shell.js";
9
+ export { KptAppShell, KptNavLabel, KptNavSection, useKptAppShell, useKptShellNavToggle } from "./app-shell/app-shell.js";
10
10
  export { KptToolbar, KptToolbarSpacer } from "./toolbar/toolbar.js";
11
11
  export { KptSidenav, KptSidenavFooter } from "./sidenav/sidenav.js";
12
12
  // Komponenty — panele
@@ -0,0 +1,40 @@
1
+ # KptRadioGroup (@konce-pt/react)
2
+
3
+ A group of radio buttons, driven by `options`.
4
+ Import: `import { KptRadioGroup } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-radio-group-host">
8
+ <div class="kpt-radio-group" role="radiogroup">
9
+ <label class="kpt-radio">
10
+ <input type="radio" class="kpt-radio__input" name="kpt-radio-r1" checked>
11
+ <span class="kpt-radio__dot" aria-hidden="true"></span>
12
+ <span class="kpt-radio__label">Pro</span>
13
+ </label>
14
+ </div>
15
+ </div>
16
+
17
+ ## Props
18
+ - `options`: `KptOption<T>[]` — `{ label, value, disabled? }`
19
+ - `value` / `defaultValue` / `onValueChange` — controlled or uncontrolled
20
+ - `name`: string — the form group name; omitted means one is generated
21
+ - `disabled`, `invalid`, `touched`, `onTouch()`
22
+ - `className`, `ref` and every other `<div>` prop go to the host
23
+
24
+ ## The shared name does the work
25
+ All inputs share one `name`, and that — not any code in the component — is what makes the browser
26
+ treat them as one group: arrow keys move between them, only one can be checked, and a native form
27
+ submits a single value. The generated name is unique per instance, so two groups on one page never
28
+ interfere.
29
+
30
+ ## Examples
31
+ <KptRadioGroup options={plans} value={plan} onValueChange={setPlan} />
32
+ <KptRadioGroup name="plan" options={plans} defaultValue="pro" />
33
+
34
+ ## Tokens
35
+ `--kpt-color-primary` (the checked dot), `--kpt-form-field-border`,
36
+ `--kpt-form-field-border-error`.
37
+
38
+ ## Accessibility
39
+ The container is `role="radiogroup"` with `aria-invalid` when the error shows; every option is a
40
+ native radio inside a `<label>`, so the label text is clickable and is the accessible name.
@@ -1,7 +1,7 @@
1
1
  import type { ComponentPropsWithRef } from 'react';
2
2
  import type { KptOption } from '../shared/types.ts';
3
3
  export interface KptRadioGroupProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'defaultValue'> {
4
- options?: KptOption<T>[];
4
+ options?: readonly KptOption<T>[];
5
5
  value?: T;
6
6
  defaultValue?: T;
7
7
  onValueChange?: (value: T) => void;
@@ -0,0 +1,43 @@
1
+ # KptRating (@konce-pt/react)
2
+
3
+ A star rating.
4
+ Import: `import { KptRating } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-rating-host">
8
+ <div class="kpt-rating" role="slider" aria-valuenow="3" aria-valuemax="5">
9
+ <button class="kpt-rating__star is-filled" aria-label="1 of 5">…</button>
10
+ …count buttons…
11
+ </div>
12
+ </div>
13
+
14
+ ## Props
15
+ - `value` / `defaultValue` / `onValueChange` — the score as a number, `0` means unrated
16
+ - `count`: number (default 5)
17
+ - `readOnly`: boolean — display only, no clicking and no hover preview
18
+ - `disabled`: boolean
19
+ - `onTouch()` — fired together with a pick
20
+ - `className`, `ref` and every other `<div>` prop go to the host
21
+
22
+ ## Clicking a lit star clears the score
23
+ Picking the star that already holds the value writes `0`, so a rating can be taken back without a
24
+ separate "clear" button — the same contract as the Angular port.
25
+
26
+ ## Hover beats the value, but only while the pointer is there
27
+ The lit count comes from `hover || value`, so the row previews the score under the cursor and
28
+ falls back to the real value on `mouseleave`. `readOnly` and `disabled` freeze both.
29
+
30
+ ## i18n
31
+ Each star is labelled from `rating.star` (`{value}`, `{max}`) — EN `1 of 5`, PL `1 z 5`. Override
32
+ per instance with the `locale` / `dictionary` props.
33
+
34
+ ## Examples
35
+ <KptRating value={score} onValueChange={setScore} count={5} />
36
+ <KptRating value={4} readOnly />
37
+
38
+ ## Tokens
39
+ Lit stars `--kpt-color-warning`, empty ones `--kpt-color-border-strong`.
40
+
41
+ ## Accessibility
42
+ `role="slider"` with `aria-valuenow` / `aria-valuemax`; every star is a real `<button>`, so the
43
+ row is reachable with Tab and each value can be picked from the keyboard.
@@ -0,0 +1,61 @@
1
+ # KptRichText (@konce-pt/react)
2
+
3
+ A lightweight rich text editor (contenteditable) with a configurable, sectioned toolbar and table
4
+ editing. The value is HTML.
5
+ Import: `import { KptRichText, type KptRichTool } from '@konce-pt/react';`
6
+
7
+ ## Props
8
+ - `value` / `defaultValue` / `onValueChange` — the HTML
9
+ - `toolbar`: `KptRichTool[] | KptRichTool[][]` — a flat list, or groups = sections separated by a
10
+ divider. Leaving a tool or a group out disables it; the full toolbar in 5 sections by default.
11
+ - `placeholder`, `maxListLevel` (6), `disabled`, `invalid`, `touched`, `onTouch()`
12
+ - `className`, `ref` and every other `<div>` prop go to the host
13
+
14
+ ## Tools (KptRichTool)
15
+ Clipboard: `copy`, `paste` (sanitized), `pasteText`. Style: `heading` (a panel: Normal + H1–H6).
16
+ Format: `bold`, `italic`, `underline`, `strike`, `ul`, `ol`, `indent`, `outdent`.
17
+ Colours: `foreColor`, `backColor` (a palette + a native colour input). Alignment: `alignLeft`,
18
+ `alignCenter`, `alignRight`, `alignJustify`. Plus `link`, `table`, `clear`, `html`.
19
+
20
+ ## The editor is not rendered by React
21
+ `contentEditable` cannot be a React-rendered subtree: re-rendering would wipe the selection and the
22
+ caret on every keystroke. The value is written into the DOM by hand, only when it differs from what
23
+ is already there — so typing never triggers a rewrite, and sanitization runs solely on writes
24
+ coming from the application or the HTML source view.
25
+
26
+ ## Everything that enters the DOM is sanitized
27
+ Not just paste: a `value` from a database, a CMS or another user is untrusted too. Tags outside the
28
+ allowlist are unwrapped (the text survives), `on*` handlers and `javascript:` URLs are dropped,
29
+ `style` is filtered declaration by declaration. `sanitize.ts` knows nothing about React.
30
+
31
+ ## Lists are indented by our own DOM code
32
+ `execCommand('indent')` produces invalid `ul > ul` in Chrome, so nesting goes through `lists.ts`
33
+ (`li > ul > li`, a sublist inherits the parent's type). Tab and Shift+Tab indent and outdent, but
34
+ only when the operation actually changed something — otherwise Tab stays native and the editor
35
+ never becomes a keyboard trap (WCAG 2.1.2). In a table cell Tab moves to the next cell; a list
36
+ inside the cell takes precedence.
37
+
38
+ ## Tables
39
+ Insert from an 8×8 grid popover. Dragging across cells makes a rectangular selection that grows
40
+ until it fully covers merged cells on its edges. Right-click opens the menu: insert and delete rows
41
+ and columns, header row and column (td↔th), cell background, alignment, borders, merge and split,
42
+ delete the table. Dragging a column's right edge changes its width. `tables.ts` holds the grid
43
+ math — also framework-free.
44
+
45
+ ## Point-anchored panels
46
+ The table menu and its popovers have no trigger element, so they do not go through `KptOverlay`:
47
+ they are portalled at the cursor coordinates and clamped to the viewport, because CDK's automatic
48
+ repositioning is not there to do it.
49
+
50
+ ## Examples
51
+ <KptRichText value={body} onValueChange={setBody} />
52
+ <KptRichText value={body} onValueChange={setBody} toolbar={[['bold', 'italic'], ['ul', 'ol'], ['link']]} />
53
+
54
+ ## i18n
55
+ Every label comes from the `richText` namespace, including `richText.menu.*` and
56
+ `richText.border.*`.
57
+
58
+ ## Note
59
+ Formatting goes through `document.execCommand`. The API is formally deprecated, but it is the only
60
+ route into the browser's native undo stack (Ctrl+Z); replacing it would mean writing our own
61
+ history, that is, a different editor.
@@ -2,7 +2,7 @@ import { type ComponentPropsWithRef } from 'react';
2
2
  import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
3
  export type KptRichTool = 'copy' | 'paste' | 'pasteText' | 'heading' | 'bold' | 'italic' | 'underline' | 'strike' | 'ul' | 'ol' | 'indent' | 'outdent' | 'foreColor' | 'backColor' | 'alignLeft' | 'alignCenter' | 'alignRight' | 'alignJustify' | 'link' | 'table' | 'clear' | 'html';
4
4
  /** Pasek: płaska lista narzędzi albo grupy — sekcje rozdzielone separatorem. */
5
- export type KptRichToolbar = KptRichTool[] | KptRichTool[][];
5
+ export type KptRichToolbar = readonly KptRichTool[] | readonly (readonly KptRichTool[])[];
6
6
  export interface KptRichTextProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'children'>, KptI18nOverrides {
7
7
  /** Wartość jako HTML. */
8
8
  value?: string;
@@ -0,0 +1,82 @@
1
+ # KptRoadmap (@konce-pt/react/roadmap)
2
+
3
+ Rows of tasks on a horizontal timeline (a Gantt-style view). The label column and the axis header
4
+ stay stuck while scrolling, the bars are positioned as percentages, and dependencies are drawn by
5
+ an SVG layer.
6
+ Import: `import { KptRoadmap, type KptRoadmapConfig } from '@konce-pt/react/roadmap';`
7
+
8
+ A separate subpath, because the geometry, the styles and the data model are heavy next to the
9
+ library core and not every app needs them.
10
+
11
+ ## Props
12
+ - `config`: `KptRoadmapConfig` (required) — the data and every option
13
+ - `scrollHeight`: string | null — a fixed height, e.g. '420px'; enables the sticky header
14
+ - `labelWidth`: string — the width of the label column (default '14rem')
15
+ - `cellWidthPx`: number | null — the width of an axis column; without it the value depends on the zoom
16
+ - `showToday`: boolean — the "today" marker (default true)
17
+ - `virtual`: boolean — renders only the visible rows; worth it from roughly 100 rows up
18
+ - `collapsedGroups` / `defaultCollapsedGroups` / `onCollapsedGroupsChange` — the ids of collapsed
19
+ groups, controlled or uncontrolled
20
+ - `onItemClick(item)`, `onRangeChange(range)` — the click on a bar and the computed axis range
21
+ - `className`, `ref` and every other `<div>` prop go to the host
22
+ - `locale`, `dictionary` — the per-component i18n overrides
23
+
24
+ ## The config is the API
25
+ `{ items, groups?, links?, zoom?, range?, locale?, today?, timeline?, rows?, dependencies?,
26
+ interaction? }` — the same shape the Angular port takes, because both read it from
27
+ `@konce-pt/roadmap`. An item is `{ id, label, start, end?, sublabel?, variant?, color?, progress?,
28
+ groupId?, dependsOn?, milestone?, meta? }`; no `end` means a milestone diamond, and a bare string in
29
+ `dependsOn` is an 'FS' dependency.
30
+
31
+ ## The geometry lives in a package
32
+ The calendar arithmetic, the timeline bands and cells, the row layout, lane packing and the
33
+ dependency polylines come from `@konce-pt/roadmap` — pure functions with `node --test` coverage,
34
+ shared with the Angular port. The component only turns them into DOM and SVG.
35
+
36
+ ## Collapsing has two sources
37
+ `group.collapsed` in the data and the `collapsedGroups` prop are kept apart, so an app that controls
38
+ the state keeps control while a group collapsed declaratively still works. Expanding removes the
39
+ group from both — otherwise `group.collapsed` would immediately collapse it again. The declarative
40
+ set is recomputed during render whenever the `groups` array identity changes; an effect would do it
41
+ one render too late, that is after the group flashed open.
42
+
43
+ ## Measuring, not guessing
44
+ The SVG dependency layer works in pixels, so the lane width and the scroll viewport are measured
45
+ with a `ResizeObserver` in a layout effect. Before the first measurement no link is drawn — half a
46
+ frame without arrows beats arrows in the wrong place.
47
+
48
+ ## Examples
49
+ <KptRoadmap config={{ zoom: 'week', items }} scrollHeight="420px" />
50
+
51
+ const [collapsed, setCollapsed] = useState<string[]>(['analytics']);
52
+
53
+ <KptRoadmap
54
+ config={roadmap}
55
+ collapsedGroups={collapsed}
56
+ onCollapsedGroupsChange={setCollapsed}
57
+ onItemClick={(item) => open(item.id)}
58
+ />
59
+
60
+ ## Behavior
61
+ - The axis is computed in local time; week numbering follows ISO 8601.
62
+ - The 'uniform' position mode gives columns of equal width despite DST changes and months of
63
+ different lengths; inside a column the position is interpolated linearly.
64
+ - An item extending past the axis range is cut off on the side where it is clipped.
65
+ - Tooltips use `KptTooltip`, mostly with `onlyWhenTruncated`: a tooltip shows what cannot be seen.
66
+ Milestones and header cells carry one unconditionally — a diamond shows no text at all.
67
+ - Dependencies: 'FS' (the default), 'SS', 'FF', 'SF'; violated ones are drawn as a dashed line in
68
+ the danger color.
69
+ - Entries with an invalid date or a duplicate `id` are skipped, with a warning in a development build.
70
+
71
+ ## i18n
72
+ The `roadmap.*` keys: `empty`, `week`, `today`, `milestone`, `expandGroup`, `collapseGroup`.
73
+ Month and weekday names come from `Intl` per `config.locale` or the locale from `KptI18nProvider`.
74
+
75
+ ## Tokens
76
+ Surfaces `--kpt-color-surface{,-variant,-sunken,-hover}`, outlines `--kpt-color-border{,-strong}`,
77
+ bars per variant `--kpt-color-{primary,success,danger,warning,info,muted}`.
78
+ Sizes: `--kpt-roadmap-label-w`, `--kpt-roadmap-cell-w` (both can be overridden from outside).
79
+
80
+ ## Accessibility
81
+ Group toggles are real buttons with `aria-expanded`; bars and milestones are focusable and answer
82
+ Enter and Space like a click. The background grid and the dependency layer are `aria-hidden`.
@@ -0,0 +1,41 @@
1
+ # KptScrollTop (@konce-pt/react)
2
+
3
+ A "back to top" button — appears once the scroll passes `threshold` px.
4
+ Import: `import { KptScrollTop } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-scroll-top-host">
8
+ <button class="kpt-scroll-top is-visible" tabindex="0" aria-label="Scroll to top">…</button>
9
+ </div>
10
+
11
+ ## Props
12
+ - `threshold`: number (px, default 300)
13
+ - `target`: string | null — a selector for the scrolled element; the window by default
14
+ - `className`, `ref` and every other `<div>` prop go to the host
15
+
16
+ ## `target` is not optional in a shell
17
+ Whenever the app scrolls a container rather than the page — an `KptAppShell` layout, for instance —
18
+ the window never scrolls and the button would never appear. Point it at the container:
19
+ `target=".kpt-app-shell__content"`.
20
+
21
+ ## The element is found in an effect
22
+ The scrolled container is queried after mount, not during render: it is often mounted after this
23
+ component, and on the server it does not exist at all. The listener is removed on cleanup, and the
24
+ position is read once on mount, because the page may already be scrolled (arriving at an anchor).
25
+
26
+ ## The hidden button stays in the DOM
27
+ It fades in and out, so hiding it is `tabindex="-1"` plus the CSS class, not a conditional render —
28
+ otherwise the animation would have nothing to run on.
29
+
30
+ ## Examples
31
+ <KptScrollTop threshold={300} />
32
+ <KptScrollTop target="#panel" />
33
+
34
+ ## i18n
35
+ The label comes from `scrollTop.label`.
36
+
37
+ ## Tokens
38
+ `--kpt-color-primary` / `--kpt-color-on-primary`, `--kpt-elevation-3`.
39
+
40
+ ## Accessibility
41
+ A real `<button>` with a label from the dictionary; while hidden it is out of the tab order.
@@ -0,0 +1,56 @@
1
+ # KptSelect (@konce-pt/react)
2
+
3
+ A select on its own panel. Variants: single, with a search box (`filter`) and multiple
4
+ (`multiple`, chips). Import: `import { KptSelect } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <span class="kpt-select-host">
8
+ <div class="kpt-select" role="combobox" tabindex="0" aria-expanded="false">
9
+ <div class="kpt-select__value"><span class="kpt-select__placeholder">Choose…</span></div>
10
+ <span class="kpt-icon-host kpt-select__chevron">…</span>
11
+ </div>
12
+ </span>
13
+ <!-- while open, in a portal on document.body: -->
14
+ <div class="kpt-select__panel"><ul class="kpt-select__list" role="listbox">…</ul></div>
15
+
16
+ ## Props
17
+ - `options`: `KptOption<T>[]` — `{ label, value, disabled? }`
18
+ - `value` / `defaultValue` / `onValueChange` — a single `T`, or `T[]` in `multiple` mode
19
+ - `open` / `defaultOpen` / `onOpenChange` — the panel state, so the list can be opened from outside
20
+ - `placeholder`, `multiple`, `filter`, `disabled`, `invalid`, `touched`
21
+ - `onTouch()` — fires when the panel closes or the trigger loses focus
22
+ - `locale`, `dictionary` — i18n overrides for this component only
23
+ - `className`, `ref` and every other `<div>` prop go to the trigger
24
+
25
+ ## The panel is a portal
26
+ The Angular port stands on CDK Overlay, which React has no equivalent of. The panel renders into a
27
+ portal on `document.body` with the same behaviour: the trigger's width, a position below it that
28
+ flips above when there is no room, a transparent backdrop that closes on click, and Escape. It
29
+ follows scrolling and resizing, so the panel never drifts away from its trigger.
30
+
31
+ ## Keyboard
32
+ On the trigger: ArrowDown, Enter or Space open the list; Escape closes it. In the panel: ArrowUp and
33
+ ArrowDown move the active option, Enter picks it, Escape closes. Hovering an option makes it active,
34
+ so the mouse and the keyboard share one highlight.
35
+
36
+ ## Inside KptFormField
37
+ There is no native field for the wrapper to read, so the select reports its filled state with
38
+ `useKptFormFieldFilled` — the float label then floats over the chosen value.
39
+
40
+ ## i18n
41
+ `select.search` (the search placeholder), `select.noResults` (the empty list),
42
+ `select.removeChip` (the chip's remove button).
43
+
44
+ ## Examples
45
+ <KptSelect options={roles} value={role} onValueChange={setRole} placeholder="Choose…" />
46
+ <KptSelect options={roles} value={role} onValueChange={setRole} filter />
47
+ <KptSelect options={tags} value={tags} onValueChange={setTags} multiple filter />
48
+
49
+ ## Tokens
50
+ `--kpt-form-field-{bg,text,placeholder,border,border-hover,border-focus,border-error,radius}`,
51
+ `--kpt-color-surface-raised` and `--kpt-elevation-3` for the panel, `--kpt-z-overlay` for the layer.
52
+
53
+ ## Accessibility
54
+ The trigger is `role="combobox"` with `aria-expanded` and `tabindex="0"`; the list is
55
+ `role="listbox"` with `aria-multiselectable`, and each option is `role="option"` with
56
+ `aria-selected`.
@@ -2,7 +2,7 @@ import { type ComponentPropsWithRef } from 'react';
2
2
  import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
3
  import type { KptOption } from '../shared/types.ts';
4
4
  export interface KptSelectProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'children' | 'onChange' | 'defaultValue'>, KptI18nOverrides {
5
- options?: KptOption<T>[];
5
+ options?: readonly KptOption<T>[];
6
6
  placeholder?: string;
7
7
  /** Wybór wielokrotny — wartością jest tablica, a wybrane opcje pokazują się jako chipy. */
8
8
  multiple?: boolean;
@@ -0,0 +1,53 @@
1
+ # KptSidenav (@konce-pt/react)
2
+
3
+ The side panel — a styled navigation container, usually handed to the `sidenav` slot of
4
+ `<KptAppShell>`. Import: `import { KptSidenav } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-sidenav">
8
+ <div class="kpt-sidenav__scroll">…children…</div>
9
+ <div kptsidenavfooter="">…footer…</div>
10
+ </div>
11
+
12
+ ## Props
13
+ - `className`, `ref` and every other `<div>` prop go to the panel root
14
+
15
+ ## Sub-components
16
+ - `KptSidenav.Footer` — lifted OUT of the scrolling area, so it stays pinned to the bottom of the
17
+ panel however long the navigation gets (a user block, an app version, a theme switch). It carries
18
+ the `kptsidenavfooter` attribute the shared SCSS targets.
19
+
20
+ Default children land in the scrolling area. Plain `<a>` elements inside it are styled by the
21
+ stylesheet already — padding, radius, a hover background — so a simple link list needs no classes.
22
+
23
+ ## Examples
24
+ <KptSidenav>
25
+ <a href="/">Dashboard</a>
26
+ <a href="/settings">Settings</a>
27
+ <KptSidenav.Footer>v0.7.12</KptSidenav.Footer>
28
+ </KptSidenav>
29
+
30
+ <KptAppShell sidenav={<KptSidenav>…</KptSidenav>} toolbar={…}>…</KptAppShell>
31
+
32
+ ## Rail mode
33
+ When `<KptAppShell sidenavRailBreakpoint>` is on, a closed panel narrows instead of hiding. Mark the
34
+ labels inside your menu items with `<KptNavLabel>` (and group headings with `<KptNavSection>`) and
35
+ the shell will clip them the accessible way (visually hidden, still in the accessibility tree).
36
+
37
+ import { KptNavLabel, KptNavSection } from '@konce-pt/react';
38
+
39
+ <KptNavSection>Reports</KptNavSection>
40
+ <a href="/dashboard"><KptIcon name="layout-dashboard" /> <KptNavLabel>Dashboard</KptNavLabel></a>
41
+
42
+ Both render the lowercase attribute the shared SCSS targets (`kptnavlabel` / `kptnavsection`);
43
+ attribute names in CSS selectors are case-insensitive in HTML, so one rule serves both ports. Use
44
+ the components rather than writing the attribute by hand — JSX rejects an unknown camelCase
45
+ attribute, and a hand-written one is easy to misspell.
46
+
47
+ ## Tokens
48
+ `--kpt-sidenav-bg`, `--kpt-sidenav-fg`, `--kpt-sidenav-border`, plus `--kpt-sidenav-width` and
49
+ `--kpt-sidenav-rail-width`, which are read by `KptAppShell`.
50
+
51
+ ## Accessibility
52
+ The panel itself is a plain container — the `role="navigation"` and the label live on the shell's
53
+ `<aside>` around it, so a sidenav used outside `KptAppShell` needs its own landmark.
@@ -0,0 +1,33 @@
1
+ # KptSkeleton (@konce-pt/react)
2
+
3
+ A loading placeholder with a shimmer animation.
4
+ Import: `import { KptSkeleton } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <span class="kpt-skeleton-host" aria-hidden="true">
8
+ <span class="kpt-skeleton kpt-skeleton--text" style="width: 100%"></span>
9
+ <span class="kpt-skeleton kpt-skeleton--text" style="width: 60%"></span>
10
+ </span>
11
+
12
+ ## Props
13
+ - `variant`: 'text' | 'circle' | 'rect' (default 'rect')
14
+ - `width`: string (default '100%'), `height`: string (default '1rem')
15
+ - `lines`: number (default 3) — the number of lines in the `text` variant
16
+ - `className`, `ref` and every other `<span>` prop go to the host
17
+
18
+ ## The last line is shorter
19
+ In the `text` variant the last line is 60% wide. A stack of full-width rectangles does not read as
20
+ a paragraph, and a paragraph is exactly what it stands in for.
21
+
22
+ ## Examples
23
+ <KptSkeleton variant="text" lines={3} />
24
+ <KptSkeleton variant="circle" width="3rem" height="3rem" />
25
+ <KptSkeleton variant="rect" width="100%" height="8rem" />
26
+
27
+ ## Tokens
28
+ `--kpt-color-muted` and `--kpt-color-surface` for the shimmer gradient, `--kpt-radius-md`.
29
+
30
+ ## Accessibility
31
+ The host is `aria-hidden="true"` — a placeholder has nothing to announce, and reading out empty
32
+ boxes only adds noise. Announce the wait with `KptSpinner` or `KptProgress` next to it when it
33
+ matters.
@@ -0,0 +1,50 @@
1
+ # KptSlider (@konce-pt/react)
2
+
3
+ A value slider. In `range` mode it exposes two handles and the value becomes a `[min, max]` pair.
4
+ Import: `import { KptSlider } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <!-- single -->
8
+ <div class="kpt-slider-host">
9
+ <input class="kpt-slider__input" type="range" style="--_pct: 40%">
10
+ <span class="kpt-slider__value">40</span>
11
+ </div>
12
+
13
+ <!-- range -->
14
+ <div class="kpt-slider-host">
15
+ <div class="kpt-slider__range">
16
+ <div class="kpt-slider__rail"></div>
17
+ <div class="kpt-slider__fill" style="left: 20%; right: 20%"></div>
18
+ <input class="kpt-slider__thumb kpt-slider__thumb--low" type="range" aria-label="Minimum">
19
+ <input class="kpt-slider__thumb kpt-slider__thumb--high" type="range" aria-label="Maksimum">
20
+ </div>
21
+ <span class="kpt-slider__value">20–80</span>
22
+ </div>
23
+
24
+ ## Props
25
+ - `value` / `defaultValue` / `onValueChange` — `number`, or `[number, number]` in `range` mode
26
+ - `range`: boolean — two handles
27
+ - `min` (default 0), `max` (default 100), `step` (default 1)
28
+ - `showValue`: boolean — prints the current value next to the slider
29
+ - `disabled`, `onTouch()`
30
+ - `className`, `ref` and every other `<div>` prop go to the host
31
+
32
+ ## Native inputs all the way down
33
+ Both handles are native `<input type="range">` stacked on each other, so the keyboard, touch
34
+ gestures and screen readers work with no handling of our own — there is no custom drag logic to get
35
+ wrong. The rail and the fill are decoration underneath them.
36
+
37
+ ## The handles cannot cross
38
+ Moving the low handle above the high one clamps it to the high value, and the other way round. The
39
+ pair therefore always stays ordered, so the fill never inverts.
40
+
41
+ ## Examples
42
+ <KptSlider value={volume} onValueChange={(v) => setVolume(v as number)} showValue />
43
+ <KptSlider range value={span} onValueChange={(v) => setSpan(v as [number, number])} showValue />
44
+
45
+ ## Tokens
46
+ `--kpt-color-primary` (the fill and the handles), `--kpt-color-muted` (the rail).
47
+
48
+ ## Accessibility
49
+ Native range inputs carry their own role and value semantics. In `range` mode each handle gets an
50
+ `aria-label` telling the two apart, because "slider" twice would say nothing.
@@ -0,0 +1,46 @@
1
+ # KptSpeedDial (@konce-pt/react)
2
+
3
+ A speed dial — a FAB that fans out a set of actions. Built on `KptFab`.
4
+ Import: `import { KptSpeedDial } from '@konce-pt/react';`
5
+
6
+ ## DOM
7
+ <div class="kpt-speed-dial-host">
8
+ <div class="kpt-speed-dial is-open" data-direction="up">
9
+ <div class="kpt-speed-dial__actions">
10
+ <button class="kpt-speed-dial__action" aria-label="Upload file">…</button>…
11
+ </div>
12
+ <span class="kpt-fab-host"><button class="kpt-fab">…</button></span>
13
+ </div>
14
+ <div class="kpt-speed-dial__backdrop"></div>
15
+ </div>
16
+
17
+ ## Props
18
+ - `items`: `KptMenuItem<T>[]` — the actions (`label`, `icon`, `disabled`)
19
+ - `direction`: `'up'` (default) | `'down'` | `'left'` | `'right'`
20
+ - `icon`: string (default `'plus'`) — the SCSS rotates it 45° when open
21
+ - `ariaLabel`: string — the closed-state label; without it `speedDial.actions`
22
+ - `onSelect(item)` — fired on pick; a disabled item fires nothing
23
+ - `className`, `ref` and every other `<div>` prop go to the host
24
+
25
+ ## The label follows the state
26
+ Closed, the FAB is named "actions"; open, it is `common.close`, because that is what pressing it
27
+ does then. One button, two meanings, and a screen reader hears the current one.
28
+
29
+ ## The backdrop exists only while open
30
+ It is rendered conditionally, not hidden with CSS: a transparent, full-screen layer that is always
31
+ present would swallow clicks meant for the page underneath.
32
+
33
+ ## Examples
34
+ <KptSpeedDial items={actions} onSelect={onAction} />
35
+ <KptSpeedDial items={actions} direction="left" icon="dots" ariaLabel="More" />
36
+
37
+ ## i18n
38
+ `speedDial.actions` and `common.close`; `locale` and `dictionary` override them per instance.
39
+
40
+ ## Tokens
41
+ The main button comes from `KptFab`; the actions use `--kpt-color-surface-raised` and
42
+ `--kpt-elevation-2`.
43
+
44
+ ## Accessibility
45
+ Every action is a `<button>` labelled with its own `label`, so the fan works from the keyboard even
46
+ when the actions show icons only.
@@ -3,7 +3,7 @@ import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
3
  import type { KptMenuItem } from '../menu/menu-item.ts';
4
4
  export type KptSpeedDialDirection = 'up' | 'down' | 'left' | 'right';
5
5
  export interface KptSpeedDialProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onSelect'>, KptI18nOverrides {
6
- items?: KptMenuItem<T>[];
6
+ items?: readonly KptMenuItem<T>[];
7
7
  direction?: KptSpeedDialDirection;
8
8
  /** Ikona głównego przycisku; SCSS obraca ją o 45° po otwarciu. */
9
9
  icon?: string;
@@ -0,0 +1,33 @@
1
+ # KptSpinner (@konce-pt/react)
2
+
3
+ A loading indicator. Import: `import { KptSpinner } from '@konce-pt/react';`
4
+
5
+ ## DOM
6
+ <span class="kpt-spinner-host">
7
+ <span class="kpt-spinner" role="status" aria-label="Loading" style="width: 1.75rem; height: 1.75rem"></span>
8
+ </span>
9
+
10
+ ## Props
11
+ - `size`: string (default '1.5rem') — a CSS length, applied to width and height
12
+ - `label`: string — the accessibility label; omitted falls back to `spinner.label`
13
+ - `locale`, `dictionary` — i18n overrides for this component only
14
+ - `className`, `ref` and every other `<span>` prop go to the host
15
+
16
+ ## The colour is inherited
17
+ The spinner draws itself in `currentColor`, so it takes the colour of the text around it. Put it
18
+ inside a button and it matches the button; put it on a card and it matches the card. There is no
19
+ colour prop, on purpose.
20
+
21
+ ## Examples
22
+ <KptSpinner />
23
+ <KptSpinner size="2rem" label="Loading data" />
24
+ <KptButton disabled><KptSpinner size="1em" /> Saving…</KptButton>
25
+
26
+ ## Tokens
27
+ None of its own — the size comes from the prop, the colour from `currentColor`, the speed from
28
+ `--kpt-motion-duration-*`.
29
+
30
+ ## Accessibility
31
+ `role="status"` with a label, so a screen reader announces the wait politely. For a longer
32
+ operation prefer `KptProgress` — a spinner says "something is happening", a progress bar says how
33
+ much is left.