@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.
- package/README.md +4 -4
- package/dist/backdrop/backdrop.d.ts +79 -0
- package/dist/backdrop/backdrop.js +195 -0
- package/dist/backdrop/llms.txt +132 -0
- package/dist/button/button.d.ts +23 -7
- package/dist/button/button.js +33 -9
- package/dist/button/llms.txt +48 -12
- package/dist/button-group/button-group.d.ts +7 -1
- package/dist/button-group/button-group.js +9 -4
- package/dist/button-group/llms.txt +30 -5
- package/dist/chat/chat.d.ts +53 -0
- package/dist/chat/chat.js +160 -0
- package/dist/chat/llms.txt +78 -0
- package/dist/chat-composer/chat-composer.d.ts +41 -0
- package/dist/chat-composer/chat-composer.js +81 -0
- package/dist/chat-composer/llms.txt +56 -0
- package/dist/chat-dock/chat-dock.d.ts +40 -0
- package/dist/chat-dock/chat-dock.js +67 -0
- package/dist/chat-dock/llms.txt +71 -0
- package/dist/chat-entry/public-api.d.ts +12 -0
- package/dist/chat-entry/public-api.js +10 -0
- package/dist/chat-message/chat-message.d.ts +53 -0
- package/dist/chat-message/chat-message.js +112 -0
- package/dist/chat-message/llms.txt +73 -0
- package/dist/chat-typing/chat-typing.d.ts +23 -0
- package/dist/chat-typing/chat-typing.js +30 -0
- package/dist/chat-typing/llms.txt +41 -0
- package/dist/chip/chip.d.ts +10 -1
- package/dist/chip/chip.js +3 -2
- package/dist/chip/llms.txt +9 -0
- package/dist/data-view/data-view.d.ts +15 -3
- package/dist/data-view/data-view.js +22 -5
- package/dist/data-view/llms.txt +20 -7
- package/dist/dialog/dialog.d.ts +9 -1
- package/dist/dialog/dialog.js +2 -2
- package/dist/internal/dev.d.ts +1 -0
- package/dist/internal/dev.js +3 -0
- package/dist/internal/overlay.d.ts +6 -1
- package/dist/internal/overlay.js +5 -3
- package/dist/mention/llms.txt +60 -0
- package/dist/mention/mention.d.ts +38 -0
- package/dist/mention/mention.js +29 -0
- package/dist/mention/mentions.d.ts +31 -0
- package/dist/mention/mentions.js +24 -0
- package/dist/order-list/llms.txt +16 -5
- package/dist/order-list/order-list.d.ts +5 -3
- package/dist/order-list/order-list.js +69 -4
- package/dist/peek/llms.txt +42 -0
- package/dist/peek/peek.d.ts +35 -0
- package/dist/peek/peek.js +127 -0
- package/dist/pick-list/llms.txt +19 -5
- package/dist/pick-list/pick-list.d.ts +7 -2
- package/dist/pick-list/pick-list.js +123 -17
- package/dist/progress/llms.txt +70 -22
- package/dist/progress/progress.d.ts +34 -7
- package/dist/progress/progress.js +46 -9
- package/dist/public-api.d.ts +15 -3
- package/dist/public-api.js +6 -0
- package/dist/rich-text/llms.txt +10 -0
- package/dist/rich-text/rich-text.d.ts +11 -1
- package/dist/rich-text/rich-text.js +157 -5
- package/dist/rich-text/sanitize.js +10 -1
- package/dist/roadmap/roadmap.js +1 -3
- package/dist/shared/types.d.ts +2 -0
- 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.
|
package/dist/chip/chip.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/chip/llms.txt
CHANGED
|
@@ -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}
|
|
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}
|
|
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
|
-
|
|
23
|
-
const
|
|
24
|
-
|
|
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
|
}
|
package/dist/data-view/llms.txt
CHANGED
|
@@ -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
|
|
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`,
|
|
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}
|
|
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
|
|
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-
|
|
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
|
package/dist/dialog/dialog.d.ts
CHANGED
|
@@ -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
|
}
|
package/dist/dialog/dialog.js
CHANGED
|
@@ -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;
|
|
@@ -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;
|
package/dist/internal/overlay.js
CHANGED
|
@@ -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
|
-
|
|
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
|
+
}
|
package/dist/order-list/llms.txt
CHANGED
|
@@ -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;
|