@konce-pt/react 0.8.3 → 0.9.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 (65) hide show
  1. package/README.md +4 -4
  2. package/dist/backdrop/backdrop.d.ts +79 -0
  3. package/dist/backdrop/backdrop.js +195 -0
  4. package/dist/backdrop/llms.txt +132 -0
  5. package/dist/button/button.d.ts +23 -7
  6. package/dist/button/button.js +33 -9
  7. package/dist/button/llms.txt +48 -12
  8. package/dist/button-group/button-group.d.ts +7 -1
  9. package/dist/button-group/button-group.js +9 -4
  10. package/dist/button-group/llms.txt +30 -5
  11. package/dist/chat/chat.d.ts +53 -0
  12. package/dist/chat/chat.js +160 -0
  13. package/dist/chat/llms.txt +78 -0
  14. package/dist/chat-composer/chat-composer.d.ts +41 -0
  15. package/dist/chat-composer/chat-composer.js +81 -0
  16. package/dist/chat-composer/llms.txt +56 -0
  17. package/dist/chat-dock/chat-dock.d.ts +40 -0
  18. package/dist/chat-dock/chat-dock.js +67 -0
  19. package/dist/chat-dock/llms.txt +71 -0
  20. package/dist/chat-entry/public-api.d.ts +12 -0
  21. package/dist/chat-entry/public-api.js +10 -0
  22. package/dist/chat-message/chat-message.d.ts +53 -0
  23. package/dist/chat-message/chat-message.js +112 -0
  24. package/dist/chat-message/llms.txt +73 -0
  25. package/dist/chat-typing/chat-typing.d.ts +23 -0
  26. package/dist/chat-typing/chat-typing.js +30 -0
  27. package/dist/chat-typing/llms.txt +41 -0
  28. package/dist/chip/chip.d.ts +10 -1
  29. package/dist/chip/chip.js +3 -2
  30. package/dist/chip/llms.txt +9 -0
  31. package/dist/data-view/data-view.d.ts +15 -3
  32. package/dist/data-view/data-view.js +22 -5
  33. package/dist/data-view/llms.txt +20 -7
  34. package/dist/dialog/dialog.d.ts +9 -1
  35. package/dist/dialog/dialog.js +2 -2
  36. package/dist/internal/dev.d.ts +1 -0
  37. package/dist/internal/dev.js +3 -0
  38. package/dist/internal/overlay.d.ts +6 -1
  39. package/dist/internal/overlay.js +5 -3
  40. package/dist/mention/llms.txt +60 -0
  41. package/dist/mention/mention.d.ts +38 -0
  42. package/dist/mention/mention.js +29 -0
  43. package/dist/mention/mentions.d.ts +31 -0
  44. package/dist/mention/mentions.js +24 -0
  45. package/dist/order-list/llms.txt +16 -5
  46. package/dist/order-list/order-list.d.ts +5 -3
  47. package/dist/order-list/order-list.js +69 -4
  48. package/dist/peek/llms.txt +42 -0
  49. package/dist/peek/peek.d.ts +35 -0
  50. package/dist/peek/peek.js +127 -0
  51. package/dist/pick-list/llms.txt +19 -5
  52. package/dist/pick-list/pick-list.d.ts +7 -2
  53. package/dist/pick-list/pick-list.js +123 -17
  54. package/dist/progress/llms.txt +70 -22
  55. package/dist/progress/progress.d.ts +34 -7
  56. package/dist/progress/progress.js +46 -9
  57. package/dist/public-api.d.ts +15 -3
  58. package/dist/public-api.js +6 -0
  59. package/dist/rich-text/llms.txt +10 -0
  60. package/dist/rich-text/rich-text.d.ts +11 -1
  61. package/dist/rich-text/rich-text.js +157 -5
  62. package/dist/rich-text/sanitize.js +10 -1
  63. package/dist/roadmap/roadmap.js +1 -3
  64. package/dist/shared/types.d.ts +2 -0
  65. package/package.json +16 -9
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../internal/cn.js";
3
+ import { useKptMessages } from "../i18n/i18n-context.js";
4
+ /**
5
+ * Wskaźnik pisania — trzy kropki i informacja, kto pisze.
6
+ *
7
+ * Pusta lista autorów nie renderuje niczego, więc można go trzymać w drzewie na stałe
8
+ * i sterować wyłącznie danymi.
9
+ *
10
+ * Element jest `role="status"` z `aria-live="polite"`: czytnik ogłasza wejście i zniknięcie
11
+ * wskaźnika, ale nie przerywa czytania wiadomości. Sama animacja kropek nic nie mówi —
12
+ * informację niesie etykieta.
13
+ *
14
+ * @example
15
+ * <KptChatTyping authors={typing} />
16
+ */
17
+ export function KptChatTyping({ authors = [], label = '', locale, dictionary, className, ...rest }) {
18
+ const { t } = useKptMessages({ locale, dictionary });
19
+ if (authors.length === 0 && !label)
20
+ return null;
21
+ /*
22
+ * Jedna osoba jest wymieniona z imienia, przy większej liczbie liczy się głowy —
23
+ * lista nazwisk rozjeżdża wiersz i i tak nikt jej nie czyta.
24
+ */
25
+ const text = label ||
26
+ (authors.length === 1
27
+ ? t('chat.typing', { name: authors[0].name })
28
+ : t('chat.typingMany', { count: authors.length }));
29
+ return (_jsx("div", { className: cn('kpt-chat-typing-host', className), role: "status", "aria-live": "polite", ...rest, children: _jsxs("div", { className: "kpt-chat-typing", children: [_jsxs("span", { className: "kpt-chat-typing__bubble", "aria-hidden": "true", children: [_jsx("span", { className: "kpt-chat-typing__dot" }), _jsx("span", { className: "kpt-chat-typing__dot" }), _jsx("span", { className: "kpt-chat-typing__dot" })] }), text ? _jsx("span", { className: "kpt-chat-typing__label", children: text }) : null] }) }));
30
+ }
@@ -0,0 +1,41 @@
1
+ # KptChatTyping (@konce-pt/react/chat)
2
+
3
+ The typing indicator — three dots and a line saying who is typing.
4
+ Import: `import { KptChatTyping } from '@konce-pt/react/chat';`
5
+
6
+ ## DOM
7
+ <div class="kpt-chat-typing-host" role="status" aria-live="polite">
8
+ <div class="kpt-chat-typing">
9
+ <span class="kpt-chat-typing__bubble" aria-hidden="true">
10
+ <span class="kpt-chat-typing__dot"></span>
11
+ <span class="kpt-chat-typing__dot"></span>
12
+ <span class="kpt-chat-typing__dot"></span>
13
+ </span>
14
+ <span class="kpt-chat-typing__label">Anna is typing…</span>
15
+ </div>
16
+ </div>
17
+
18
+ ## Props
19
+ - `authors`: `KptChatAuthor[]` — an empty list renders nothing at all
20
+ - `label`: string — your own wording instead of the dictionary's
21
+ - `className`, `ref` and every other `<div>` prop go to the host
22
+
23
+ ## One name, then a headcount
24
+ One person is named; from two up the component counts heads. A list of names breaks the line and
25
+ nobody reads it anyway.
26
+
27
+ ## Examples
28
+ <KptChatTyping authors={[anna]} />
29
+ <KptChatTyping authors={typing} />
30
+ <KptChatTyping label="The assistant is thinking…" />
31
+
32
+ ## i18n
33
+ `typing` (`{name}`) and `typingMany` (`{count}`) from the `chat` namespace.
34
+
35
+ ## Tokens
36
+ The bubble `--kpt-color-surface-variant`, the dots `--kpt-color-text-muted`.
37
+
38
+ ## Accessibility
39
+ `role="status"` with `aria-live="polite"` announces the indicator without interrupting a message
40
+ being read. Under `prefers-reduced-motion` the dots stop bouncing and pulse instead — they are the
41
+ only carrier of "someone is typing", so switching them off entirely would remove the message.
@@ -2,8 +2,16 @@ import type { ComponentPropsWithRef } from 'react';
2
2
  import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
3
  import type { KptHostProps } from '../internal/types.ts';
4
4
  export type KptChipVariant = 'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info';
5
+ /** Wielkość liter etykiety. */
6
+ export type KptChipTextTransform = 'none' | 'capitalize' | 'uppercase' | 'lowercase';
5
7
  export interface KptChipProps extends ComponentPropsWithRef<'span'>, KptI18nOverrides {
6
8
  variant?: KptChipVariant;
9
+ /**
10
+ * Wielkość liter etykiety. `capitalize` podnosi pierwszą literę każdego słowa — także po
11
+ * dywizie („Agent-Ready"), bo CSS nie wie, gdzie kończy się wyraz złożony; przy takich
12
+ * napisach pewniejszy jest zapis wprost w treści.
13
+ */
14
+ textTransform?: KptChipTextTransform;
7
15
  /** Dokłada przycisk usuwania. */
8
16
  removable?: boolean;
9
17
  disabled?: boolean;
@@ -18,5 +26,6 @@ export interface KptChipProps extends ComponentPropsWithRef<'span'>, KptI18nOver
18
26
  * @example
19
27
  * <KptChip>Angular</KptChip>
20
28
  * <KptChip variant="success" removable onRemove={remove}>UI</KptChip>
29
+ * <KptChip textTransform="capitalize">nowość · zestaw startowy</KptChip>
21
30
  */
22
- export declare function KptChip({ variant, removable, disabled, onRemove, locale, dictionary, hostProps, className, children, ...rest }: Readonly<KptChipProps>): import("react").JSX.Element;
31
+ export declare function KptChip({ variant, textTransform, removable, disabled, onRemove, locale, dictionary, hostProps, className, children, ...rest }: Readonly<KptChipProps>): import("react").JSX.Element;
package/dist/chip/chip.js CHANGED
@@ -8,9 +8,10 @@ import { useKptMessages } from "../i18n/i18n-context.js";
8
8
  * @example
9
9
  * <KptChip>Angular</KptChip>
10
10
  * <KptChip variant="success" removable onRemove={remove}>UI</KptChip>
11
+ * <KptChip textTransform="capitalize">nowość · zestaw startowy</KptChip>
11
12
  */
12
- export function KptChip({ variant = 'neutral', removable = false, disabled = false, onRemove, locale, dictionary, hostProps, className, children, ...rest }) {
13
+ export function KptChip({ variant = 'neutral', textTransform = 'none', removable = false, disabled = false, onRemove, locale, dictionary, hostProps, className, children, ...rest }) {
13
14
  const { t } = useKptMessages({ locale, dictionary });
14
15
  const { className: hostClassName, ...hostRest } = hostProps ?? {};
15
- return (_jsx("span", { className: cn('kpt-chip-host', hostClassName), ...hostRest, children: _jsxs("span", { className: cn('kpt-chip', disabled && 'kpt-chip--disabled', className), "data-variant": variant, ...rest, children: [children, removable ? (_jsx("button", { type: "button", className: "kpt-chip__remove", disabled: disabled, onClick: onRemove, "aria-label": t('common.remove'), children: _jsx(KptIcon, { name: "x" }) })) : null] }) }));
16
+ return (_jsx("span", { className: cn('kpt-chip-host', hostClassName), ...hostRest, children: _jsxs("span", { className: cn('kpt-chip', disabled && 'kpt-chip--disabled', className), "data-variant": variant, "data-text-transform": textTransform === 'none' ? undefined : textTransform, ...rest, children: [children, removable ? (_jsx("button", { type: "button", className: "kpt-chip__remove", disabled: disabled, onClick: onRemove, "aria-label": t('common.remove'), children: _jsx(KptIcon, { name: "x" }) })) : null] }) }));
16
17
  }
@@ -13,6 +13,7 @@ Import: `import { KptChip } from '@konce-pt/react';`
13
13
 
14
14
  ## Props
15
15
  - `variant`: 'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info' (default 'neutral')
16
+ - `textTransform`: 'none' | 'capitalize' | 'uppercase' | 'lowercase' (default 'none') — the label's letter case
16
17
  - `removable`: boolean — adds the remove button
17
18
  - `disabled`: boolean
18
19
  - `onRemove()` — fired by the remove button
@@ -31,6 +32,14 @@ The remove button's label comes from `common.remove` in the dictionary.
31
32
  <KptChip>React</KptChip>
32
33
  <KptChip variant="success" removable onRemove={() => drop(tag)}>UI</KptChip>
33
34
  <KptCard.Tags><KptChip variant="info">Daily</KptChip></KptCard.Tags>
35
+ <KptChip textTransform="capitalize">new · starter kit</KptChip>
36
+
37
+ ## Letter case
38
+ `textTransform` lands as `data-text-transform` on `.kpt-chip` and sets `text-transform` there, so
39
+ the label can stay in the application's own wording while the chip decides how it is displayed.
40
+ `capitalize` raises the first letter of every word — **including after a hyphen**
41
+ ("Agent-Ready"), because CSS does not know where a compound word ends. For labels with a hyphen,
42
+ spelling it out in the content is the exact route.
34
43
 
35
44
  ## Tokens
36
45
  `--kpt-color-muted`, `--kpt-color-on-muted` and the semantic colour pairs of each variant
@@ -6,8 +6,20 @@ export interface KptDataViewProps<T> extends Omit<ComponentPropsWithRef<'div'>,
6
6
  layout?: KptDataViewLayout;
7
7
  defaultLayout?: KptDataViewLayout;
8
8
  onLayoutChange?: (layout: KptDataViewLayout) => void;
9
- /** Rozmiar strony; 0 wyłącza stronicowanie. */
9
+ /** Rozmiar strony; 0 wyłącza stronicowanie. Sterowalny — select paginatora go zmienia. */
10
10
  pageSize?: number;
11
+ defaultPageSize?: number;
12
+ onPageSizeChange?: (pageSize: number) => void;
13
+ /** Rozmiary do wyboru w paginatorze. Pusta lista = select z jedną, bieżącą wartością. */
14
+ pageSizeOptions?: readonly number[];
15
+ /** Liczba kolumn siatki jako SUFIT, nie sztywna liczba; 0 = tyle, ile się zmieści. */
16
+ gridColumns?: number;
17
+ defaultGridColumns?: number;
18
+ onGridColumnsChange?: (columns: number) => void;
19
+ /** Wartości w pasku gęstości. Mniej niż dwie = paska nie ma po co pokazywać. */
20
+ gridColumnsOptions?: readonly number[];
21
+ /** Najwęższa sensowna karta — poniżej tego siatka zdejmuje kolumnę, zamiast ściskać. */
22
+ gridMinWidth?: string;
11
23
  paginated?: boolean;
12
24
  /** Szablon elementu — odpowiednik `<ng-template let-item>` z Angulara. */
13
25
  renderItem: (item: T, index: number) => ReactNode;
@@ -16,6 +28,6 @@ export interface KptDataViewProps<T> extends Omit<ComponentPropsWithRef<'div'>,
16
28
  * DataView — lista elementów w układzie listy albo siatki, z opcjonalnym stronicowaniem.
17
29
  *
18
30
  * @example
19
- * <KptDataView items={products} pageSize={6} renderItem={(p) => <div>{p.name}</div>} />
31
+ * <KptDataView items={products} defaultPageSize={6} renderItem={(p) => <div>{p.name}</div>} />
20
32
  */
21
- export declare function KptDataView<T>({ items, layout, defaultLayout, onLayoutChange, pageSize, paginated, renderItem, locale, dictionary, className, ...rest }: Readonly<KptDataViewProps<T>>): import("react").JSX.Element;
33
+ export declare function KptDataView<T>({ items, layout, defaultLayout, onLayoutChange, pageSize, defaultPageSize, onPageSizeChange, pageSizeOptions, gridColumns, defaultGridColumns, onGridColumnsChange, gridColumnsOptions, gridMinWidth, paginated, renderItem, locale, dictionary, className, ...rest }: Readonly<KptDataViewProps<T>>): import("react").JSX.Element;
@@ -9,17 +9,34 @@ import { KptPaginator } from "../paginator/paginator.js";
9
9
  * DataView — lista elementów w układzie listy albo siatki, z opcjonalnym stronicowaniem.
10
10
  *
11
11
  * @example
12
- * <KptDataView items={products} pageSize={6} renderItem={(p) => <div>{p.name}</div>} />
12
+ * <KptDataView items={products} defaultPageSize={6} renderItem={(p) => <div>{p.name}</div>} />
13
13
  */
14
- export function KptDataView({ items = [], layout, defaultLayout = 'grid', onLayoutChange, pageSize = 0, paginated = true, renderItem, locale, dictionary, className, ...rest }) {
14
+ export function KptDataView({ items = [], layout, defaultLayout = 'grid', onLayoutChange, pageSize, defaultPageSize = 0, onPageSizeChange, pageSizeOptions = [], gridColumns, defaultGridColumns = 0, onGridColumnsChange, gridColumnsOptions = [], gridMinWidth = '10rem', paginated = true, renderItem, locale, dictionary, className, ...rest }) {
15
15
  const { t } = useKptMessages({ locale, dictionary });
16
16
  const [currentLayout, setLayout] = useControllableState({
17
17
  value: layout,
18
18
  defaultValue: defaultLayout,
19
19
  onChange: onLayoutChange,
20
20
  });
21
+ const [size, setSize] = useControllableState({
22
+ value: pageSize,
23
+ defaultValue: defaultPageSize,
24
+ onChange: onPageSizeChange,
25
+ });
26
+ const [columns, setColumns] = useControllableState({
27
+ value: gridColumns,
28
+ defaultValue: defaultGridColumns,
29
+ onChange: onGridColumnsChange,
30
+ });
21
31
  const [pageIndex, setPageIndex] = useState(0);
22
- const showPager = paginated && pageSize > 0 && items.length > pageSize;
23
- const pageItems = !paginated || pageSize <= 0 ? items : items.slice(pageIndex * pageSize, pageIndex * pageSize + pageSize);
24
- return (_jsx("div", { className: cn('kpt-data-view-host', className), ...rest, children: _jsxs("div", { className: "kpt-data-view", children: [_jsxs("div", { className: "kpt-data-view__toolbar", children: [_jsx("div", { className: "kpt-data-view__count", children: t('dataView.count', { count: items.length }) }), _jsxs("div", { className: "kpt-data-view__switch", children: [_jsx("button", { type: "button", className: cn(currentLayout === 'list' && 'is-active'), "aria-label": t('dataView.list'), onClick: () => setLayout('list'), children: _jsx(KptIcon, { name: "list" }) }), _jsx("button", { type: "button", className: cn(currentLayout === 'grid' && 'is-active'), "aria-label": t('dataView.grid'), onClick: () => setLayout('grid'), children: _jsx(KptIcon, { name: "menu" }) })] })] }), _jsx("div", { className: "kpt-data-view__content", "data-layout": currentLayout, children: pageItems.length ? (pageItems.map((item, index) => (_jsx("div", { className: "kpt-data-view__item", children: renderItem(item, index) }, index)))) : (_jsx("div", { className: "kpt-data-view__empty", children: t('dataView.empty') })) }), showPager ? (_jsx(KptPaginator, { length: items.length, pageIndex: pageIndex, onPageIndexChange: setPageIndex, pageSize: pageSize, pageSizeOptions: [pageSize] })) : null] }) }));
32
+ // Opcje selecta: własna lista albo — gdy pusta — sam bieżący rozmiar.
33
+ const pagerSizeOptions = pageSizeOptions.length ? pageSizeOptions : [size];
34
+ // Pager zostaje na ekranie także wtedy, gdy wszystko mieści się na jednej stronie, o ile jest
35
+ // w czym wybierać. Bez tego wybranie największego rozmiaru chowa select, którym użytkownik
36
+ // właśnie się posłużył — i nie ma jak wrócić do mniejszego.
37
+ // Pasek gęstości ma sens tylko w siatce i tylko wtedy, gdy jest w czym wybierać.
38
+ const showColumns = currentLayout === 'grid' && gridColumnsOptions.length > 1;
39
+ const showPager = paginated && size > 0 && (items.length > size || pagerSizeOptions.length > 1);
40
+ const pageItems = !paginated || size <= 0 ? items : items.slice(pageIndex * size, pageIndex * size + size);
41
+ return (_jsx("div", { className: cn('kpt-data-view-host', className), ...rest, children: _jsxs("div", { className: "kpt-data-view", children: [_jsxs("div", { className: "kpt-data-view__toolbar", children: [_jsx("div", { className: "kpt-data-view__count", children: t('dataView.count', { count: items.length }) }), _jsxs("div", { className: "kpt-data-view__controls", children: [showColumns ? (_jsx("div", { className: "kpt-data-view__columns", role: "group", "aria-label": t('dataView.columns'), children: gridColumnsOptions.map((n) => (_jsxs("button", { type: "button", className: cn(columns === n && 'is-active'), "aria-pressed": columns === n, onClick: () => setColumns(n), children: [_jsx(KptIcon, { name: "grid-dots" }), n] }, n))) })) : null, _jsxs("div", { className: "kpt-data-view__switch", children: [_jsx("button", { type: "button", className: cn(currentLayout === 'list' && 'is-active'), "aria-label": t('dataView.list'), "aria-pressed": currentLayout === 'list', onClick: () => setLayout('list'), children: _jsx(KptIcon, { name: "list" }) }), _jsx("button", { type: "button", className: cn(currentLayout === 'grid' && 'is-active'), "aria-label": t('dataView.grid'), "aria-pressed": currentLayout === 'grid', onClick: () => setLayout('grid'), children: _jsx(KptIcon, { name: "layout-grid" }) })] })] })] }), _jsx("div", { className: "kpt-data-view__content", "data-layout": currentLayout, "data-columns": columns ? '' : undefined, style: { '--_min': gridMinWidth, '--_cols': columns || undefined }, children: pageItems.length ? (pageItems.map((item, index) => (_jsx("div", { className: "kpt-data-view__item", children: renderItem(item, index) }, index)))) : (_jsx("div", { className: "kpt-data-view__empty", children: t('dataView.empty') })) }), showPager ? (_jsx(KptPaginator, { length: items.length, pageIndex: pageIndex, onPageIndexChange: setPageIndex, pageSize: size, onPageSizeChange: setSize, pageSizeOptions: pagerSizeOptions })) : null] }) }));
25
42
  }
@@ -20,7 +20,11 @@ Import: `import { KptDataView } from '@konce-pt/react';`
20
20
  ## Props
21
21
  - `items`: `T[]`
22
22
  - `layout` / `defaultLayout` / `onLayoutChange` — `'list' | 'grid'` (default `'grid'`)
23
- - `pageSize`: number — 0 turns pagination off
23
+ - `pageSize` / `defaultPageSize` / `onPageSizeChange` — number; 0 turns pagination off
24
+ - `pageSizeOptions`: number[] (empty = the select offers the current size only)
25
+ - `gridColumns` / `defaultGridColumns` / `onGridColumnsChange` — number; 0 = as many as fit
26
+ - `gridColumnsOptions`: number[] (fewer than two = no density bar)
27
+ - `gridMinWidth`: string (default `10rem`) — the narrowest card worth rendering
24
28
  - `paginated`: boolean (default true)
25
29
  - `renderItem(item, index)` — required; the equivalent of `<ng-template let-item>`
26
30
  - `className`, `ref` and every other `<div>` prop go to the host
@@ -29,20 +33,29 @@ Import: `import { KptDataView } from '@konce-pt/react';`
29
33
  `data-layout` on the content switches the grid rules; the toolbar only flips it. Everything else —
30
34
  the item's markup — is the caller's, which is why there are no card props here.
31
35
 
36
+ ## The column count is a ceiling
37
+ The density bar shows up in the grid layout when `gridColumnsOptions` holds more than one value.
38
+ The chosen number caps the grid rather than pinning it: the track minimum grows to the width of
39
+ one of N columns, so a narrow container drops to two or one column instead of squeezing cards
40
+ below `gridMinWidth`.
41
+
32
42
  ## The pager appears when it is needed
33
- Only when `paginated`, `pageSize > 0` and there are more items than fit on a page — a paginator
34
- under a single page of results is noise.
43
+ Only when `paginated`, the page size is above 0, and either the items outgrow one page or
44
+ `pageSizeOptions` holds more than one size — a paginator under a single page of results is noise,
45
+ but hiding it right after someone picks the largest size would strand them there.
35
46
 
36
47
  ## Examples
37
- <KptDataView items={products} pageSize={6} renderItem={(p) => <div>{p.name}</div>} />
48
+ <KptDataView items={products} defaultPageSize={6} renderItem={(p) => <div>{p.name}</div>} />
49
+ <KptDataView items={products} defaultPageSize={6} pageSizeOptions={[3, 6, 9]} renderItem={renderCard} />
50
+ <KptDataView items={products} defaultGridColumns={2} gridColumnsOptions={[2, 3, 4]} gridMinWidth="14rem" renderItem={renderCard} />
38
51
  <KptDataView items={products} layout="list" paginated={false} renderItem={renderCard} />
39
52
 
40
53
  ## i18n
41
- The count and the two switch buttons come from the `dataView` namespace (`count` with `{count}`,
42
- `list`, `grid`, `empty`).
54
+ The count, the two switch buttons and the density group come from the `dataView` namespace
55
+ (`count` with `{count}`, `list`, `grid`, `columns`, `empty`).
43
56
 
44
57
  ## Tokens
45
- The grid gap `--kpt-space-4`, the active switch `--kpt-color-primary`.
58
+ The grid gap `--kpt-space-3`, the active switch `--kpt-color-primary`.
46
59
 
47
60
  ## Accessibility
48
61
  Both layout buttons carry labels from the dictionary; an empty list renders a message instead of
@@ -1,9 +1,17 @@
1
1
  import { type ComponentPropsWithRef, type ReactNode } from 'react';
2
2
  import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
3
+ /** Szerokość okna. `md` to wartość domyślna i zarazem jedyna, jaką okno miało wcześniej. */
4
+ export type KptDialogSize = 'sm' | 'md' | 'lg';
3
5
  export interface KptDialogProps extends Omit<ComponentPropsWithRef<'dialog'>, 'open' | 'onClose'>, KptI18nOverrides {
4
6
  open: boolean;
5
7
  onOpenChange: (open: boolean) => void;
6
8
  header?: string;
9
+ /**
10
+ * Szerokość okna: `sm` 24rem, `md` 32rem (domyślna), `lg` 48rem — zawsze przycięta do szerokości
11
+ * okna przeglądarki. `lg` jest dla treści, której nie da się sensownie zwęzić: kodu, tabeli,
12
+ * porównania dwóch kolumn.
13
+ */
14
+ size?: KptDialogSize;
7
15
  /** Pozwala zamknąć klawiszem Esc i przyciskiem ×. */
8
16
  dismissible?: boolean;
9
17
  children?: ReactNode;
@@ -21,7 +29,7 @@ export interface KptDialogProps extends Omit<ComponentPropsWithRef<'dialog'>, 'o
21
29
  * </KptDialog.Footer>
22
30
  * </KptDialog>
23
31
  */
24
- export declare function KptDialog({ open, onOpenChange, header, dismissible, locale, dictionary, className, children, ref, ...rest }: Readonly<KptDialogProps>): import("react").JSX.Element;
32
+ export declare function KptDialog({ open, onOpenChange, header, size, dismissible, locale, dictionary, className, children, ref, ...rest }: Readonly<KptDialogProps>): import("react").JSX.Element;
25
33
  export declare namespace KptDialog {
26
34
  var Footer: typeof KptDialogFooter;
27
35
  }
@@ -18,7 +18,7 @@ import { KptIcon } from "../icon/icon.js";
18
18
  * </KptDialog.Footer>
19
19
  * </KptDialog>
20
20
  */
21
- export function KptDialog({ open, onOpenChange, header = '', dismissible = true, locale, dictionary, className, children, ref, ...rest }) {
21
+ export function KptDialog({ open, onOpenChange, header = '', size = 'md', dismissible = true, locale, dictionary, className, children, ref, ...rest }) {
22
22
  const { t } = useKptMessages({ locale, dictionary });
23
23
  const dialogRef = useRef(null);
24
24
  // Element trafia do kontekstu, więc musi wywołać render — sam `ref` by nie wystarczył.
@@ -46,7 +46,7 @@ export function KptDialog({ open, onOpenChange, header = '', dismissible = true,
46
46
  }
47
47
  onOpenChange(false);
48
48
  };
49
- return (_jsx(KptOverlayContainerContext.Provider, { value: open ? dialogEl : null, children: _jsxs("dialog", { ref: composeRefs(dialogRef, setDialogEl, ref), className: cn('kpt-dialog', className), onClose: () => onOpenChange(false), onCancel: onCancel, ...rest, children: [header ? (_jsxs("div", { className: "kpt-dialog__header", children: [_jsx("h2", { className: "kpt-dialog__title", children: header }), dismissible ? (_jsx("button", { className: "kpt-dialog__close", type: "button", onClick: () => onOpenChange(false), "aria-label": t('common.close'), children: _jsx(KptIcon, { name: "x" }) })) : null] })) : null, _jsx("div", { className: "kpt-dialog__body", children: body }), footers] }) }));
49
+ return (_jsx(KptOverlayContainerContext.Provider, { value: open ? dialogEl : null, children: _jsxs("dialog", { ref: composeRefs(dialogRef, setDialogEl, ref), className: cn('kpt-dialog', className), "data-size": size, onClose: () => onOpenChange(false), onCancel: onCancel, ...rest, children: [header ? (_jsxs("div", { className: "kpt-dialog__header", children: [_jsx("h2", { className: "kpt-dialog__title", children: header }), dismissible ? (_jsx("button", { className: "kpt-dialog__close", type: "button", onClick: () => onOpenChange(false), "aria-label": t('common.close'), children: _jsx(KptIcon, { name: "x" }) })) : null] })) : null, _jsx("div", { className: "kpt-dialog__body", children: body }), footers] }) }));
50
50
  }
51
51
  /**
52
52
  * Stopka okna. Nosi atrybut `kptdialogfooter`, w który celuje wspólny SCSS (nazwy atrybutów
@@ -0,0 +1 @@
1
+ export declare function isDevBuild(): boolean;
@@ -0,0 +1,3 @@
1
+ export function isDevBuild() {
2
+ return typeof process !== 'undefined' && process?.env?.['NODE_ENV'] !== 'production';
3
+ }
@@ -21,6 +21,11 @@ export interface KptOverlayProps {
21
21
  * zasłoniłby to pole i zabrałby mu każde kliknięcie.
22
22
  */
23
23
  withBackdrop?: boolean;
24
+ /**
25
+ * Otwieraj nad wyzwalaczem, dopóki jest tam miejsce (odpowiednik `placement="top"` w porcie
26
+ * Angulara, gdzie kolejnością pozycji steruje CDK). Bez tego panel wychodzi spod wyzwalacza.
27
+ */
28
+ preferAbove?: boolean;
24
29
  children: ReactNode;
25
30
  }
26
- export declare function KptOverlay({ open, anchor, onClose, matchAnchorWidth, offset, align, withBackdrop, children, }: Readonly<KptOverlayProps>): import("react").ReactPortal | null;
31
+ export declare function KptOverlay({ open, anchor, onClose, matchAnchorWidth, offset, align, withBackdrop, preferAbove, children, }: Readonly<KptOverlayProps>): import("react").ReactPortal | null;
@@ -4,7 +4,7 @@ import { createPortal } from 'react-dom';
4
4
  import { useKptOverlayContainer } from "./overlay-container.js";
5
5
  /** Ta sama warstwa co `--kpt-z-overlay` w tokenach — panel ma być nad treścią aplikacji. */
6
6
  const Z_INDEX = 'var(--kpt-z-overlay, 1100)';
7
- export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, offset = 4, align = 'start', withBackdrop = true, children, }) {
7
+ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, offset = 4, align = 'start', withBackdrop = true, preferAbove = false, children, }) {
8
8
  const container = useKptOverlayContainer();
9
9
  const panelRef = useRef(null);
10
10
  const [position, setPosition] = useState(null);
@@ -17,13 +17,15 @@ export function KptOverlay({ open, anchor, onClose, matchAnchorWidth = false, of
17
17
  const below = window.innerHeight - rect.bottom;
18
18
  // Odbicie w górę tylko wtedy, gdy pod spodem naprawdę brakuje miejsca, a nad wyzwalaczem
19
19
  // jest go więcej — inaczej panel skakałby przy każdym przewinięciu o kilka pikseli.
20
- const flip = panelHeight > 0 && below < panelHeight + offset && rect.top > below;
20
+ // Przy `preferAbove` jest odwrotnie: panel stoi nad wyzwalaczem, dopóki się tam mieści.
21
+ const fitsAbove = panelHeight === 0 || rect.top > panelHeight + offset;
22
+ const flip = preferAbove ? fitsAbove : panelHeight > 0 && below < panelHeight + offset && rect.top > below;
21
23
  setPosition({
22
24
  top: flip ? rect.top - panelHeight - offset : rect.bottom + offset,
23
25
  left: align === 'end' ? rect.right - panelWidth : rect.left,
24
26
  ...(matchAnchorWidth ? { width: rect.width } : {}),
25
27
  });
26
- }, [anchor, matchAnchorWidth, offset, align]);
28
+ }, [anchor, matchAnchorWidth, offset, align, preferAbove]);
27
29
  useLayoutEffect(() => {
28
30
  if (!open) {
29
31
  setPosition(null);
@@ -0,0 +1,60 @@
1
+ # KptMention / KptMentions (@konce-pt/react)
2
+
3
+ Mentions in text: `@someone` as an element you can hover to see a peek card with the rest of the
4
+ connections. `KptMention` is a single mention; `KptMentions` turns a whole paragraph into text plus
5
+ mentions.
6
+ Import: `import { KptMention, KptMentions } from '@konce-pt/react';`
7
+
8
+ ## DOM
9
+ <span class="kpt-mentions-host">
10
+ <span class="kpt-mentions__text">A question for </span>
11
+ <span class="kpt-peek-host kpt-mention-host">
12
+ <button class="kpt-mention" data-kind="person">@Anna Kowalska</button>
13
+ </span>
14
+ <span class="kpt-mentions__text"> about the estimate.</span>
15
+ </span>
16
+
17
+ ## KptMention — props
18
+ - `item`: `KptMentionItem` — the whole entry at once; the single props below win over it
19
+ - `id`, `label`, `kind`: string — `kind` lands in `data-kind`, so it can be styled per type
20
+ - `prefix`: string (default '@'), `href`: string | null — with `href` the mention is a link
21
+ - `placement`, `openDelay` — passed to `KptPeek`
22
+ - `disabled`: boolean — no card; the mention stays a plain highlighted word
23
+ - `children`: ReactNode — the card
24
+
25
+ ## KptMentions — props
26
+ - `text`: string — the content with `@id` or `@[Name with spaces](id)`
27
+ - `items`: `readonly KptMentionItem[]` — entries the ids resolve against
28
+ - `prefix`, `placement` — passed to every mention
29
+ - `renderCard`: `(item, id, label) => ReactNode` — the card; without it mentions are plain words
30
+
31
+ ## Example
32
+ <KptMentions
33
+ text={note}
34
+ items={people}
35
+ renderCard={(item, id, label) => <KptCard>{item?.data?.role ?? label}</KptCard>}
36
+ />
37
+
38
+ ## The text stays text
39
+ `KptMentions` does not render HTML: the paragraph goes in as a plain string, `parseMentionText()`
40
+ from `@konce-pt/mention` splits it into segments and the mention is an element the library builds
41
+ itself. An application does not have to push user-written content through a sanitizer to get
42
+ mentions out of it.
43
+
44
+ An id that is not on the list still renders — the label falls back to the id, because a note has to
45
+ stay readable after someone leaves the team. Without `renderCard` the mention is a highlighted
46
+ word, not a button: there is nothing to open, so it does not pretend otherwise.
47
+
48
+ ## Mentions in the editor
49
+ `KptRichText` takes `mentions`, `mentionLimit` and `onMention`: typing `@` opens the suggestion
50
+ list, arrows and Enter (or Tab) insert the mention as
51
+ `<span class="kpt-mention" data-mention="id" contenteditable="false">`. The id survives saving, and
52
+ `contenteditable="false"` keeps the mention in one piece.
53
+
54
+ ## Tokens
55
+ The mention is underlined with a **dotted** line: `--kpt-color-primary-border` at rest, darkening
56
+ to `--kpt-color-primary` on hover and while the card is open. Dotted, not solid — a solid underline
57
+ would read as a link, and a mention usually leads nowhere, it opens a card. Text
58
+ `--kpt-color-primary`; a mention without a card `--kpt-color-text` + `--kpt-font-weight-medium` and
59
+ no line at all, since there is nothing to promise. Focus ring `--kpt-color-focus-ring`. The card
60
+ takes its own tokens from `KptPeek`.
@@ -0,0 +1,38 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
2
+ import type { KptMentionItem } from '@konce-pt/mention';
3
+ import { type KptPeekPlacement } from '../peek/peek.tsx';
4
+ export interface KptMentionProps extends Omit<ComponentPropsWithRef<'span'>, 'id' | 'prefix' | 'children'> {
5
+ /** Cała pozycja naraz. Pojedyncze propsy poniżej mają nad nią priorytet. */
6
+ item?: KptMentionItem | null;
7
+ /** Identyfikator zapisany w treści — nie zmienia się przy zmianie nazwy. */
8
+ id?: string;
9
+ /** Nazwa do pokazania; bez niej bierze się ją z `item`, a w ostateczności z `id`. */
10
+ label?: string;
11
+ /** Rodzaj (osoba, zadanie, dokument) — ląduje w `data-kind`, więc da się go ostylować. */
12
+ kind?: string;
13
+ /** Znak przed nazwą. Pusty łańcuch zostawia samą nazwę. */
14
+ prefix?: string;
15
+ /** Adres, pod który prowadzi klik. Bez niego wzmianka jest przyciskiem otwierającym kartę. */
16
+ href?: string | null;
17
+ placement?: KptPeekPlacement;
18
+ openDelay?: number;
19
+ /** Wyłączona wzmianka nie otwiera karty — zostaje samym napisem. */
20
+ disabled?: boolean;
21
+ /** Treść karty. Bez niej wzmianka też zostaje napisem: nie ma czego pokazać. */
22
+ children?: ReactNode;
23
+ }
24
+ /**
25
+ * Wzmianka w tekście — `@ktoś` albo `@coś` jako element, na który da się najechać i zobaczyć
26
+ * kartę podglądu z resztą powiązań. Treść karty daje aplikacja przez `children`: biblioteka nie
27
+ * wie, czym jest wzmiankowana rzecz, a osoba, zadanie i dokument wyglądają inaczej.
28
+ *
29
+ * Wyzwalacz jest `<button>`, a nie `<span>`: karta otwiera się też z klawiatury i dotyku
30
+ * (przypięcie), a to wymaga elementu, na który da się wejść Tabem. Z `href` staje się linkiem,
31
+ * bo wtedy klik prowadzi gdzieś naprawdę.
32
+ *
33
+ * @example
34
+ * <KptMention id="anna.k" label="Anna Kowalska">
35
+ * <KptCard>Profil, projekty, kontakt…</KptCard>
36
+ * </KptMention>
37
+ */
38
+ export declare function KptMention({ item, id, label, kind, prefix, href, placement, openDelay, disabled, children, className, ...rest }: Readonly<KptMentionProps>): import("react").JSX.Element;
@@ -0,0 +1,29 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cn } from "../internal/cn.js";
3
+ import { KptPeek } from "../peek/peek.js";
4
+ /**
5
+ * Wzmianka w tekście — `@ktoś` albo `@coś` jako element, na który da się najechać i zobaczyć
6
+ * kartę podglądu z resztą powiązań. Treść karty daje aplikacja przez `children`: biblioteka nie
7
+ * wie, czym jest wzmiankowana rzecz, a osoba, zadanie i dokument wyglądają inaczej.
8
+ *
9
+ * Wyzwalacz jest `<button>`, a nie `<span>`: karta otwiera się też z klawiatury i dotyku
10
+ * (przypięcie), a to wymaga elementu, na który da się wejść Tabem. Z `href` staje się linkiem,
11
+ * bo wtedy klik prowadzi gdzieś naprawdę.
12
+ *
13
+ * @example
14
+ * <KptMention id="anna.k" label="Anna Kowalska">
15
+ * <KptCard>Profil, projekty, kontakt…</KptCard>
16
+ * </KptMention>
17
+ */
18
+ export function KptMention({ item = null, id = '', label = '', kind = '', prefix = '@', href = null, placement = 'bottom', openDelay = 300, disabled = false, children, className, ...rest }) {
19
+ const display = prefix + (label || item?.label || id || item?.id || '');
20
+ const resolvedKind = kind || item?.kind || undefined;
21
+ const plain = disabled || !children;
22
+ if (plain) {
23
+ // Bez karty wzmianka nie udaje kontrolki: zostaje wyróżnionym napisem, którego nie ma
24
+ // po co dotykać Tabem.
25
+ return (_jsx("span", { className: cn('kpt-mention-host', className), ...rest, children: _jsx("span", { className: "kpt-mention", "data-plain": "", "data-kind": resolvedKind, children: display }) }));
26
+ }
27
+ const trigger = href ? (_jsx("a", { className: "kpt-mention", href: href, "data-kind": resolvedKind, children: display })) : (_jsx("button", { type: "button", className: "kpt-mention", "data-kind": resolvedKind, children: display }));
28
+ return (_jsx(KptPeek, { className: cn('kpt-mention-host', className), trigger: trigger, placement: placement, openDelay: openDelay, label: display, ...rest, children: children }));
29
+ }
@@ -0,0 +1,31 @@
1
+ import type { ComponentPropsWithRef, ReactNode } from 'react';
2
+ import { type KptMentionItem } from '@konce-pt/mention';
3
+ import type { KptPeekPlacement } from '../peek/peek.tsx';
4
+ export interface KptMentionsProps<T = unknown> extends Omit<ComponentPropsWithRef<'span'>, 'children' | 'prefix'> {
5
+ /** Treść z wzmiankami: `@id` albo `@[Nazwa ze spacją](id)`. */
6
+ text?: string;
7
+ /** Pozycje, po których rozwiązują się identyfikatory. Nieznane `id` zostaje etykietą. */
8
+ items?: readonly KptMentionItem<T>[];
9
+ /** Znak przed nazwą we wzmiance. */
10
+ prefix?: string;
11
+ placement?: KptPeekPlacement;
12
+ /** Karta wzmianki. Bez niej wzmianki są samym napisem, bo nie ma czego pokazać. */
13
+ renderCard?: (item: KptMentionItem<T> | null, id: string, label: string) => ReactNode;
14
+ }
15
+ /**
16
+ * Akapit ze wzmiankami — tekst wchodzi jako zwykły napis, a `@wzmianki` wychodzą z niego jako
17
+ * elementy z kartą podglądu. Rozbiciem zajmuje się `parseMentionText()` z `@konce-pt/mention`
18
+ * (czysty TS z testami), więc oba porty czytają tę samą treść tak samo.
19
+ *
20
+ * Wzmianek nie renderujemy z HTML-a: treść zostaje tekstem, a wzmianka jest elementem, który
21
+ * biblioteka sama zbudowała. Aplikacja nie musi więc przepuszczać przez sanitizer czegoś,
22
+ * co i tak pochodzi od jej użytkowników.
23
+ *
24
+ * @example
25
+ * <KptMentions
26
+ * text={note}
27
+ * items={people}
28
+ * renderCard={(item, id, label) => <KptCard>{item?.data?.role ?? label}</KptCard>}
29
+ * />
30
+ */
31
+ export declare function KptMentions<T = unknown>({ text, items, prefix, placement, renderCard, className, ...rest }: Readonly<KptMentionsProps<T>>): import("react").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { parseMentionText } from '@konce-pt/mention';
3
+ import { cn } from "../internal/cn.js";
4
+ import { KptMention } from "./mention.js";
5
+ /**
6
+ * Akapit ze wzmiankami — tekst wchodzi jako zwykły napis, a `@wzmianki` wychodzą z niego jako
7
+ * elementy z kartą podglądu. Rozbiciem zajmuje się `parseMentionText()` z `@konce-pt/mention`
8
+ * (czysty TS z testami), więc oba porty czytają tę samą treść tak samo.
9
+ *
10
+ * Wzmianek nie renderujemy z HTML-a: treść zostaje tekstem, a wzmianka jest elementem, który
11
+ * biblioteka sama zbudowała. Aplikacja nie musi więc przepuszczać przez sanitizer czegoś,
12
+ * co i tak pochodzi od jej użytkowników.
13
+ *
14
+ * @example
15
+ * <KptMentions
16
+ * text={note}
17
+ * items={people}
18
+ * renderCard={(item, id, label) => <KptCard>{item?.data?.role ?? label}</KptCard>}
19
+ * />
20
+ */
21
+ export function KptMentions({ text = '', items = [], prefix = '@', placement = 'bottom', renderCard, className, ...rest }) {
22
+ const segments = parseMentionText(text, items);
23
+ return (_jsx("span", { className: cn('kpt-mentions-host', className), ...rest, children: segments.map((segment, index) => segment.kind === 'text' ? (_jsx("span", { className: "kpt-mentions__text", children: segment.text }, index)) : (_jsx(KptMention, { id: segment.id, label: segment.label, kind: segment.item?.kind ?? '', prefix: prefix, placement: placement, children: renderCard?.(segment.item, segment.id, segment.label) }, index))) }));
24
+ }
@@ -1,6 +1,7 @@
1
1
  # KptOrderList (@konce-pt/react)
2
2
 
3
- A list with manual reordering. Click selects an item, the buttons move it up and down.
3
+ A list with manual reordering. Click selects an item, the buttons move it up and down, and
4
+ `dragdrop` lets you drag it into place.
4
5
  Import: `import { KptOrderList } from '@konce-pt/react';`
5
6
 
6
7
  ## DOM
@@ -19,23 +20,33 @@ Import: `import { KptOrderList } from '@konce-pt/react';`
19
20
  ## Props
20
21
  - `items` / `defaultItems` / `onItemsChange` — the list; the callback receives the new order
21
22
  - `header`: string
23
+ - `dragdrop` — `false` by default; enables dragging (opt-in, nothing changes without it)
22
24
  - `renderItem(item, index)` — required; the equivalent of `<ng-template let-item>`
23
25
  - `className`, `ref` and every other `<div>` prop go to the host
24
26
 
25
27
  ## The selection follows the item
26
28
  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.
29
+ entry — with the selection pinned to a position, the second press would move its neighbour. A drop
30
+ does the same.
31
+
32
+ ## Where a dragged item lands
33
+ Dropping onto a row puts the dragged item at that row's position and everything else shifts, while
34
+ the buttons keep swapping with the neighbour. Dropping on the empty part of the list appends at the
35
+ end. While a drag is running the row under the cursor carries a `--dragover` modifier and the
36
+ dragged one `is-dragging`.
28
37
 
29
38
  ## Examples
30
- <KptOrderList items={tasks} onItemsChange={setTasks} header="Order" renderItem={(item) => item} />
39
+ <KptOrderList items={tasks} onItemsChange={setTasks} header="Order" dragdrop renderItem={(item) => item} />
31
40
  <KptOrderList defaultItems={steps} renderItem={(step) => step.name} />
32
41
 
33
42
  ## i18n
34
- The buttons use `orderList.up` and `orderList.down`.
43
+ The buttons use `orderList.up` and `orderList.down`. Dragging carries no visible label, so it adds
44
+ no dictionary keys.
35
45
 
36
46
  ## Tokens
37
47
  The selection `--kpt-color-primary`, the buttons `--kpt-color-surface-raised`.
38
48
 
39
49
  ## Accessibility
40
50
  Both buttons are labelled from the dictionary and go disabled while nothing is selected, so the
41
- control never looks broken.
51
+ control never looks broken. Native HTML5 drag and drop has no keyboard equivalent, so they stay the
52
+ full keyboard path — `dragdrop` never replaces them.
@@ -5,14 +5,16 @@ export interface KptOrderListProps<T> extends Omit<ComponentPropsWithRef<'div'>,
5
5
  defaultItems?: T[];
6
6
  onItemsChange?: (items: T[]) => void;
7
7
  header?: string;
8
+ /** Włącza przestawianie pozycji metodą przeciągnij-i-upuść. */
9
+ dragdrop?: boolean;
8
10
  /** Szablon elementu — odpowiednik `<ng-template let-item>` z Angulara. */
9
11
  renderItem: (item: T, index: number) => ReactNode;
10
12
  }
11
13
  /**
12
14
  * OrderList — lista z ręcznym porządkowaniem. Klik zaznacza element, przyciski przesuwają go
13
- * w górę i w dół.
15
+ * w górę i w dół. Z `dragdrop` pozycje przestawia się także przeciąganiem.
14
16
  *
15
17
  * @example
16
- * <KptOrderList items={tasks} onItemsChange={setTasks} header="Kolejność" renderItem={(t) => t.name} />
18
+ * <KptOrderList items={tasks} onItemsChange={setTasks} header="Kolejność" dragdrop renderItem={(t) => t.name} />
17
19
  */
18
- export declare function KptOrderList<T>({ items, defaultItems, onItemsChange, header, renderItem, locale, dictionary, className, ...rest }: Readonly<KptOrderListProps<T>>): import("react").JSX.Element;
20
+ export declare function KptOrderList<T>({ items, defaultItems, onItemsChange, header, dragdrop, renderItem, locale, dictionary, className, ...rest }: Readonly<KptOrderListProps<T>>): import("react").JSX.Element;