@konce-pt/react 0.8.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/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/accordion/accordion.d.ts +45 -0
- package/dist/accordion/accordion.js +69 -0
- package/dist/alert/alert.d.ts +25 -0
- package/dist/alert/alert.js +31 -0
- package/dist/app-shell/app-shell.d.ts +94 -0
- package/dist/app-shell/app-shell.js +105 -0
- package/dist/auth/auth-types.d.ts +44 -0
- package/dist/auth/auth-types.js +2 -0
- package/dist/auth/auth.d.ts +76 -0
- package/dist/auth/auth.js +184 -0
- package/dist/autocomplete/autocomplete.d.ts +18 -0
- package/dist/autocomplete/autocomplete.js +72 -0
- package/dist/avatar/avatar.d.ts +33 -0
- package/dist/avatar/avatar.js +30 -0
- package/dist/avatar-group/avatar-group.d.ts +21 -0
- package/dist/avatar-group/avatar-group.js +15 -0
- package/dist/badge/badge.d.ts +25 -0
- package/dist/badge/badge.js +14 -0
- package/dist/bottom-sheet/bottom-sheet.d.ts +21 -0
- package/dist/bottom-sheet/bottom-sheet.js +22 -0
- package/dist/breadcrumb/breadcrumb.d.ts +19 -0
- package/dist/breadcrumb/breadcrumb.js +20 -0
- package/dist/button/button.d.ts +27 -0
- package/dist/button/button.js +49 -0
- package/dist/button-group/button-group.d.ts +25 -0
- package/dist/button-group/button-group.js +30 -0
- package/dist/card/card.d.ts +66 -0
- package/dist/card/card.js +96 -0
- package/dist/carousel/carousel.d.ts +20 -0
- package/dist/carousel/carousel.js +24 -0
- package/dist/charts/chart-legend.d.ts +23 -0
- package/dist/charts/chart-legend.js +9 -0
- package/dist/charts/chart-tooltip.d.ts +21 -0
- package/dist/charts/chart-tooltip.js +13 -0
- package/dist/charts/chart.d.ts +18 -0
- package/dist/charts/chart.js +231 -0
- package/dist/charts-entry/public-api.d.ts +4 -0
- package/dist/charts-entry/public-api.js +7 -0
- package/dist/checkbox/checkbox.d.ts +33 -0
- package/dist/checkbox/checkbox.js +29 -0
- package/dist/chip/chip.d.ts +22 -0
- package/dist/chip/chip.js +16 -0
- package/dist/chips-input/chips-input.d.ts +25 -0
- package/dist/chips-input/chips-input.js +54 -0
- package/dist/clock/clock.d.ts +17 -0
- package/dist/clock/clock.js +57 -0
- package/dist/color-picker/color-picker.d.ts +23 -0
- package/dist/color-picker/color-picker.js +28 -0
- package/dist/confirm/confirm-container.d.ts +13 -0
- package/dist/confirm/confirm-container.js +26 -0
- package/dist/confirm/confirm-store.d.ts +29 -0
- package/dist/confirm/confirm-store.js +52 -0
- package/dist/context-menu/context-menu.d.ts +21 -0
- package/dist/context-menu/context-menu.js +36 -0
- package/dist/data-table/data-table-types.d.ts +67 -0
- package/dist/data-table/data-table-types.js +1 -0
- package/dist/data-table/data-table.d.ts +62 -0
- package/dist/data-table/data-table.js +453 -0
- package/dist/data-table/export-csv.d.ts +7 -0
- package/dist/data-table/export-csv.js +19 -0
- package/dist/data-view/data-view.d.ts +21 -0
- package/dist/data-view/data-view.js +25 -0
- package/dist/date-range/date-range.d.ts +30 -0
- package/dist/date-range/date-range.js +155 -0
- package/dist/datepicker/datepicker.d.ts +39 -0
- package/dist/datepicker/datepicker.js +202 -0
- package/dist/dialog/dialog.d.ts +35 -0
- package/dist/dialog/dialog.js +59 -0
- package/dist/divider/divider.d.ts +16 -0
- package/dist/divider/divider.js +13 -0
- package/dist/drawer/drawer.d.ts +25 -0
- package/dist/drawer/drawer.js +25 -0
- package/dist/empty/empty.d.ts +18 -0
- package/dist/empty/empty.js +14 -0
- package/dist/fab/fab.d.ts +22 -0
- package/dist/fab/fab.js +17 -0
- package/dist/fieldset/fieldset.d.ts +22 -0
- package/dist/fieldset/fieldset.js +24 -0
- package/dist/file-upload/file-upload.d.ts +22 -0
- package/dist/file-upload/file-upload.js +50 -0
- package/dist/form-field/form-field-context.d.ts +23 -0
- package/dist/form-field/form-field-context.js +17 -0
- package/dist/form-field/form-field.d.ts +39 -0
- package/dist/form-field/form-field.js +41 -0
- package/dist/galleria/galleria.d.ts +22 -0
- package/dist/galleria/galleria.js +21 -0
- package/dist/grid/col.d.ts +39 -0
- package/dist/grid/col.js +32 -0
- package/dist/grid/flex.d.ts +45 -0
- package/dist/grid/flex.js +35 -0
- package/dist/grid/grid.d.ts +47 -0
- package/dist/grid/grid.js +38 -0
- package/dist/grid/layout.d.ts +18 -0
- package/dist/grid/layout.js +32 -0
- package/dist/grid-entry/public-api.d.ts +6 -0
- package/dist/grid-entry/public-api.js +8 -0
- package/dist/i18n/i18n-context.d.ts +45 -0
- package/dist/i18n/i18n-context.js +65 -0
- package/dist/icon/icon-registry.d.ts +16 -0
- package/dist/icon/icon-registry.js +43 -0
- package/dist/icon/icon.d.ts +17 -0
- package/dist/icon/icon.js +23 -0
- package/dist/icon-button/icon-button.d.ts +23 -0
- package/dist/icon-button/icon-button.js +14 -0
- package/dist/icons-entry/public-api.d.ts +12 -0
- package/dist/icons-entry/public-api.js +20 -0
- package/dist/image/image.d.ts +17 -0
- package/dist/image/image.js +16 -0
- package/dist/input/input.d.ts +41 -0
- package/dist/input/input.js +36 -0
- package/dist/input-mask/input-mask.d.ts +19 -0
- package/dist/input-mask/input-mask.js +65 -0
- package/dist/input-number/input-number.d.ts +28 -0
- package/dist/input-number/input-number.js +52 -0
- package/dist/input-otp/input-otp.d.ts +21 -0
- package/dist/input-otp/input-otp.js +59 -0
- package/dist/internal/cn.d.ts +9 -0
- package/dist/internal/cn.js +19 -0
- package/dist/internal/compose-refs.d.ts +6 -0
- package/dist/internal/compose-refs.js +16 -0
- package/dist/internal/overlay-container.d.ts +3 -0
- package/dist/internal/overlay-container.js +19 -0
- package/dist/internal/overlay.d.ts +26 -0
- package/dist/internal/overlay.js +64 -0
- package/dist/internal/slot.d.ts +23 -0
- package/dist/internal/slot.js +49 -0
- package/dist/internal/types.d.ts +25 -0
- package/dist/internal/types.js +1 -0
- package/dist/internal/use-breakpoint.d.ts +18 -0
- package/dist/internal/use-breakpoint.js +52 -0
- package/dist/internal/use-controllable-state.d.ts +11 -0
- package/dist/internal/use-controllable-state.js +18 -0
- package/dist/internal/use-id.d.ts +9 -0
- package/dist/internal/use-id.js +13 -0
- package/dist/knob/knob.d.ts +27 -0
- package/dist/knob/knob.js +86 -0
- package/dist/listbox/listbox.d.ts +28 -0
- package/dist/listbox/listbox.js +43 -0
- package/dist/map/map-create-dialog.d.ts +21 -0
- package/dist/map/map-create-dialog.js +196 -0
- package/dist/map/map-hours-field.d.ts +22 -0
- package/dist/map/map-hours-field.js +90 -0
- package/dist/map/map-image-field.d.ts +24 -0
- package/dist/map/map-image-field.js +61 -0
- package/dist/map/map-legend.d.ts +29 -0
- package/dist/map/map-legend.js +41 -0
- package/dist/map/map-poi-card.d.ts +42 -0
- package/dist/map/map-poi-card.js +152 -0
- package/dist/map/map-search.d.ts +37 -0
- package/dist/map/map-search.js +201 -0
- package/dist/map/map.d.ts +113 -0
- package/dist/map/map.js +425 -0
- package/dist/map/ports.d.ts +76 -0
- package/dist/map/ports.js +174 -0
- package/dist/map-entry/public-api.d.ts +20 -0
- package/dist/map-entry/public-api.js +19 -0
- package/dist/megamenu/megamenu.d.ts +17 -0
- package/dist/megamenu/megamenu.js +28 -0
- package/dist/menu/menu-item.d.ts +33 -0
- package/dist/menu/menu-item.js +1 -0
- package/dist/menu/menu-rows.d.ts +9 -0
- package/dist/menu/menu-rows.js +15 -0
- package/dist/menu/menu.d.ts +22 -0
- package/dist/menu/menu.js +31 -0
- package/dist/menubar/menubar.d.ts +16 -0
- package/dist/menubar/menubar.js +39 -0
- package/dist/meter-group/meter-group.d.ts +20 -0
- package/dist/meter-group/meter-group.js +24 -0
- package/dist/order-list/order-list.d.ts +18 -0
- package/dist/order-list/order-list.js +37 -0
- package/dist/paginator/paginator.d.ts +29 -0
- package/dist/paginator/paginator.js +45 -0
- package/dist/panel/panel.d.ts +31 -0
- package/dist/panel/panel.js +36 -0
- package/dist/password/password.d.ts +28 -0
- package/dist/password/password.js +37 -0
- package/dist/pick-list/pick-list.d.ts +28 -0
- package/dist/pick-list/pick-list.js +65 -0
- package/dist/popover/popover.d.ts +23 -0
- package/dist/popover/popover.js +27 -0
- package/dist/progress/progress.d.ts +19 -0
- package/dist/progress/progress.js +21 -0
- package/dist/public-api.d.ts +181 -0
- package/dist/public-api.js +105 -0
- package/dist/radio-group/radio-group.d.ts +24 -0
- package/dist/radio-group/radio-group.js +23 -0
- package/dist/rating/rating.d.ts +22 -0
- package/dist/rating/rating.js +30 -0
- package/dist/rich-text/lists.d.ts +17 -0
- package/dist/rich-text/lists.js +144 -0
- package/dist/rich-text/rich-text.d.ts +28 -0
- package/dist/rich-text/rich-text.js +654 -0
- package/dist/rich-text/sanitize.d.ts +10 -0
- package/dist/rich-text/sanitize.js +85 -0
- package/dist/rich-text/tables.d.ts +44 -0
- package/dist/rich-text/tables.js +268 -0
- package/dist/roadmap/roadmap.d.ts +37 -0
- package/dist/roadmap/roadmap.js +271 -0
- package/dist/roadmap-entry/public-api.d.ts +4 -0
- package/dist/roadmap-entry/public-api.js +7 -0
- package/dist/scroll-top/scroll-top.d.ts +16 -0
- package/dist/scroll-top/scroll-top.js +38 -0
- package/dist/select/select.d.ts +37 -0
- package/dist/select/select.js +117 -0
- package/dist/shared/types.d.ts +8 -0
- package/dist/shared/types.js +1 -0
- package/dist/sidenav/sidenav.d.ts +26 -0
- package/dist/sidenav/sidenav.js +41 -0
- package/dist/skeleton/skeleton.d.ts +20 -0
- package/dist/skeleton/skeleton.js +15 -0
- package/dist/slider/slider.d.ts +28 -0
- package/dist/slider/slider.js +30 -0
- package/dist/speed-dial/speed-dial.d.ts +20 -0
- package/dist/speed-dial/speed-dial.js +23 -0
- package/dist/spinner/spinner.d.ts +15 -0
- package/dist/spinner/spinner.js +14 -0
- package/dist/split-button/split-button.d.ts +28 -0
- package/dist/split-button/split-button.js +34 -0
- package/dist/splitter/splitter.d.ts +39 -0
- package/dist/splitter/splitter.js +80 -0
- package/dist/stepper/stepper.d.ts +51 -0
- package/dist/stepper/stepper.js +71 -0
- package/dist/switch/switch.d.ts +39 -0
- package/dist/switch/switch.js +30 -0
- package/dist/switch-group/switch-group.d.ts +29 -0
- package/dist/switch-group/switch-group.js +47 -0
- package/dist/tabs/tabs.d.ts +38 -0
- package/dist/tabs/tabs.js +74 -0
- package/dist/textarea/textarea.d.ts +28 -0
- package/dist/textarea/textarea.js +44 -0
- package/dist/timeline/timeline.d.ts +19 -0
- package/dist/timeline/timeline.js +12 -0
- package/dist/toast/toast-container.d.ts +12 -0
- package/dist/toast/toast-container.js +23 -0
- package/dist/toast/toast-store.d.ts +26 -0
- package/dist/toast/toast-store.js +51 -0
- package/dist/toolbar/toolbar.d.ts +29 -0
- package/dist/toolbar/toolbar.js +24 -0
- package/dist/tooltip/tooltip.d.ts +26 -0
- package/dist/tooltip/tooltip.js +113 -0
- package/dist/tree/tree.d.ts +31 -0
- package/dist/tree/tree.js +62 -0
- package/package.json +91 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { cn } from "../internal/cn.js";
|
|
4
|
+
/**
|
|
5
|
+
* Pole wyboru (checkbox). Cały układ niesie `<label>`, więc kliknięcie w etykietę przełącza pole
|
|
6
|
+
* bez `htmlFor` — natywny `<input>` w środku odpowiada za semantykę i klawiaturę.
|
|
7
|
+
*
|
|
8
|
+
* Działa kontrolowane (`checked` + `onCheckedChange`) i niekontrolowane (`defaultChecked`).
|
|
9
|
+
*
|
|
10
|
+
* `className` trafia na blok `.kpt-checkbox`, a pozostałe propsy (`name`, `value`, `ref`,
|
|
11
|
+
* handlery) na natywny `<input>` — tam, gdzie oczekuje ich formularz.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* <KptCheckbox name="terms" label="Akceptuję regulamin" />
|
|
15
|
+
* <KptCheckbox checked={on} onCheckedChange={setOn} />
|
|
16
|
+
*/
|
|
17
|
+
export function KptCheckbox({ label = '', required = false, invalid = false, touched, onCheckedChange, onTouch, hostProps, className, disabled = false, onChange, onBlur, children, 'aria-invalid': ariaInvalid, ...rest }) {
|
|
18
|
+
const { className: hostClassName, ...hostRest } = hostProps ?? {};
|
|
19
|
+
const showInvalid = invalid && (touched ?? true);
|
|
20
|
+
const handleChange = useCallback((event) => {
|
|
21
|
+
onChange?.(event);
|
|
22
|
+
onCheckedChange?.(event.target.checked);
|
|
23
|
+
}, [onChange, onCheckedChange]);
|
|
24
|
+
const handleBlur = useCallback((event) => {
|
|
25
|
+
onBlur?.(event);
|
|
26
|
+
onTouch?.();
|
|
27
|
+
}, [onBlur, onTouch]);
|
|
28
|
+
return (_jsx("span", { className: cn('kpt-checkbox-host', hostClassName), ...hostRest, children: _jsxs("label", { className: cn('kpt-checkbox', disabled && 'kpt-checkbox--disabled', className), children: [_jsx("input", { type: "checkbox", className: "kpt-checkbox__input", disabled: disabled, "aria-required": required || undefined, "aria-invalid": ariaInvalid ?? (showInvalid || undefined), onChange: handleChange, onBlur: handleBlur, ...rest }), _jsx("span", { className: "kpt-checkbox__box", "aria-hidden": "true", children: _jsx("svg", { viewBox: "0 0 16 16", className: "kpt-checkbox__check", children: _jsx("path", { d: "M13 4.5 6.5 11 3 7.5" }) }) }), label ? _jsx("span", { className: "kpt-checkbox__label", children: label }) : null, children] }) }));
|
|
29
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
2
|
+
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
3
|
+
import type { KptHostProps } from '../internal/types.ts';
|
|
4
|
+
export type KptChipVariant = 'neutral' | 'primary' | 'success' | 'danger' | 'warning' | 'info';
|
|
5
|
+
export interface KptChipProps extends ComponentPropsWithRef<'span'>, KptI18nOverrides {
|
|
6
|
+
variant?: KptChipVariant;
|
|
7
|
+
/** Dokłada przycisk usuwania. */
|
|
8
|
+
removable?: boolean;
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
/** Wywoływane po kliknięciu przycisku usuwania. */
|
|
11
|
+
onRemove?: () => void;
|
|
12
|
+
/** Propsy wrappera hosta (`.kpt-chip-host`). `className` i `ref` idą na `.kpt-chip`. */
|
|
13
|
+
hostProps?: KptHostProps<'span'>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Chip / tag — etykieta, opcjonalnie usuwalna.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* <KptChip>Angular</KptChip>
|
|
20
|
+
* <KptChip variant="success" removable onRemove={remove}>UI</KptChip>
|
|
21
|
+
*/
|
|
22
|
+
export declare function KptChip({ variant, removable, disabled, onRemove, locale, dictionary, hostProps, className, children, ...rest }: Readonly<KptChipProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../internal/cn.js";
|
|
3
|
+
import { KptIcon } from "../icon/icon.js";
|
|
4
|
+
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
5
|
+
/**
|
|
6
|
+
* Chip / tag — etykieta, opcjonalnie usuwalna.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* <KptChip>Angular</KptChip>
|
|
10
|
+
* <KptChip variant="success" removable onRemove={remove}>UI</KptChip>
|
|
11
|
+
*/
|
|
12
|
+
export function KptChip({ variant = 'neutral', removable = false, disabled = false, onRemove, locale, dictionary, hostProps, className, children, ...rest }) {
|
|
13
|
+
const { t } = useKptMessages({ locale, dictionary });
|
|
14
|
+
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
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef } from 'react';
|
|
2
|
+
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
3
|
+
export interface KptChipsInputProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'defaultValue'>, KptI18nOverrides {
|
|
4
|
+
value?: string[];
|
|
5
|
+
defaultValue?: string[];
|
|
6
|
+
onValueChange?: (value: string[]) => void;
|
|
7
|
+
/** Placeholder; pominięty = `chipsInput.placeholder` ze słownika. */
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
allowDuplicates?: boolean;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
invalid?: boolean;
|
|
12
|
+
touched?: boolean;
|
|
13
|
+
onTouch?: () => void;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Pole tagów — dodawanie Enterem albo przecinkiem, usuwanie Backspace lub ×.
|
|
17
|
+
*
|
|
18
|
+
* Tekst w trakcie pisania żyje w DOM, nie w stanie Reacta: wartością komponentu jest lista
|
|
19
|
+
* zatwierdzonych tagów, a bufor wpisywania to prywatna sprawa pola. Dzięki temu każde naciśnięcie
|
|
20
|
+
* klawisza nie przerysowuje listy chipów.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* <KptChipsInput value={tags} onValueChange={setTags} placeholder="Dodaj tag…" />
|
|
24
|
+
*/
|
|
25
|
+
export declare function KptChipsInput({ value, defaultValue, onValueChange, placeholder, allowDuplicates, disabled, invalid, touched, onTouch, locale, dictionary, className, ...rest }: Readonly<KptChipsInputProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from 'react';
|
|
3
|
+
import { cn } from "../internal/cn.js";
|
|
4
|
+
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
5
|
+
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
6
|
+
import { KptChip } from "../chip/chip.js";
|
|
7
|
+
/**
|
|
8
|
+
* Pole tagów — dodawanie Enterem albo przecinkiem, usuwanie Backspace lub ×.
|
|
9
|
+
*
|
|
10
|
+
* Tekst w trakcie pisania żyje w DOM, nie w stanie Reacta: wartością komponentu jest lista
|
|
11
|
+
* zatwierdzonych tagów, a bufor wpisywania to prywatna sprawa pola. Dzięki temu każde naciśnięcie
|
|
12
|
+
* klawisza nie przerysowuje listy chipów.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <KptChipsInput value={tags} onValueChange={setTags} placeholder="Dodaj tag…" />
|
|
16
|
+
*/
|
|
17
|
+
export function KptChipsInput({ value, defaultValue = [], onValueChange, placeholder, allowDuplicates = false, disabled = false, invalid = false, touched, onTouch, locale, dictionary, className, ...rest }) {
|
|
18
|
+
const { t } = useKptMessages({ locale, dictionary });
|
|
19
|
+
const inputRef = useRef(null);
|
|
20
|
+
const [chips, setChips] = useControllableState({
|
|
21
|
+
value,
|
|
22
|
+
defaultValue,
|
|
23
|
+
onChange: onValueChange,
|
|
24
|
+
});
|
|
25
|
+
const showInvalid = invalid && (touched ?? true);
|
|
26
|
+
const commit = (el) => {
|
|
27
|
+
const text = el.value.trim();
|
|
28
|
+
if (!text)
|
|
29
|
+
return;
|
|
30
|
+
if (allowDuplicates || !chips.includes(text))
|
|
31
|
+
setChips([...chips, text]);
|
|
32
|
+
el.value = '';
|
|
33
|
+
};
|
|
34
|
+
const removeAt = (index) => {
|
|
35
|
+
setChips(chips.filter((_, i) => i !== index));
|
|
36
|
+
onTouch?.();
|
|
37
|
+
};
|
|
38
|
+
const onKeyDown = (event) => {
|
|
39
|
+
const el = event.currentTarget;
|
|
40
|
+
if (event.key === 'Enter' || event.key === ',') {
|
|
41
|
+
event.preventDefault();
|
|
42
|
+
commit(el);
|
|
43
|
+
}
|
|
44
|
+
else if (event.key === 'Backspace' && el.value === '' && chips.length) {
|
|
45
|
+
// Backspace w pustym polu zjada ostatni chip — to samo, czego uczy każdy klient poczty.
|
|
46
|
+
removeAt(chips.length - 1);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const onBlur = (event) => {
|
|
50
|
+
commit(event.currentTarget);
|
|
51
|
+
onTouch?.();
|
|
52
|
+
};
|
|
53
|
+
return (_jsx("div", { className: cn('kpt-chips-input-host', className), ...rest, children: _jsxs("div", { className: cn('kpt-chips-input', disabled && 'kpt-chips-input--disabled', showInvalid && 'kpt-chips-input--invalid'), children: [chips.map((chip, index) => (_jsx(KptChip, { variant: "primary", removable: !disabled, onRemove: () => removeAt(index), children: chip }, index))), _jsx("input", { ref: inputRef, className: "kpt-chips-input__field", type: "text", placeholder: chips.length ? '' : (placeholder ?? t('chipsInput.placeholder')), disabled: disabled, onKeyDown: onKeyDown, onBlur: onBlur })] }) }));
|
|
54
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef } from 'react';
|
|
2
|
+
export interface KptClockProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange'> {
|
|
3
|
+
/** Godzina jako 'HH:mm' — zawsze 24h, niezależnie od `hourFormat`. */
|
|
4
|
+
value?: string;
|
|
5
|
+
onValueChange?: (value: string) => void;
|
|
6
|
+
hourFormat?: 12 | 24;
|
|
7
|
+
minuteStep?: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Tarcza zegara — dwa etapy: godziny → minuty, klikiem albo przeciąganiem. W trybie 24h dochodzi
|
|
11
|
+
* wewnętrzny pierścień 13–00; w 12h przełącznik AM/PM. Używana przez `KptDatepicker`
|
|
12
|
+
* i `KptDateRange`.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* <KptClock value={time} onValueChange={setTime} hourFormat={12} minuteStep={5} />
|
|
16
|
+
*/
|
|
17
|
+
export declare function KptClock({ value, onValueChange, hourFormat, minuteStep, className, ...rest }: Readonly<KptClockProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef, useState } from 'react';
|
|
3
|
+
import { from12h, handAngle, handIsInner, hourFromAngle, hourMarks, minuteFromAngle, minuteMarks, pad, parseTime, } from '@konce-pt/datetime';
|
|
4
|
+
import { cn } from "../internal/cn.js";
|
|
5
|
+
/**
|
|
6
|
+
* Tarcza zegara — dwa etapy: godziny → minuty, klikiem albo przeciąganiem. W trybie 24h dochodzi
|
|
7
|
+
* wewnętrzny pierścień 13–00; w 12h przełącznik AM/PM. Używana przez `KptDatepicker`
|
|
8
|
+
* i `KptDateRange`.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* <KptClock value={time} onValueChange={setTime} hourFormat={12} minuteStep={5} />
|
|
12
|
+
*/
|
|
13
|
+
export function KptClock({ value = '', onValueChange, hourFormat = 24, minuteStep = 1, className, ...rest }) {
|
|
14
|
+
const faceRef = useRef(null);
|
|
15
|
+
const [phase, setPhase] = useState('hours');
|
|
16
|
+
// Wartość jest jedynym źródłem prawdy — stan tarczy wyliczamy z niej przy każdym renderze,
|
|
17
|
+
// więc podmiana `value` z zewnątrz nie wymaga synchronizacji.
|
|
18
|
+
const parsed = parseTime(value);
|
|
19
|
+
const hour = parsed?.h ?? 0;
|
|
20
|
+
const minute = parsed?.m ?? 0;
|
|
21
|
+
const ampm = hour < 12 ? 'AM' : 'PM';
|
|
22
|
+
const hour12 = hour % 12 === 0 ? 12 : hour % 12;
|
|
23
|
+
const emit = (h, m) => onValueChange?.(`${pad(h)}:${pad(m)}`);
|
|
24
|
+
const onDialPointer = (event) => {
|
|
25
|
+
const face = faceRef.current;
|
|
26
|
+
if (!face)
|
|
27
|
+
return;
|
|
28
|
+
if (event.type === 'pointerdown')
|
|
29
|
+
face.setPointerCapture(event.pointerId);
|
|
30
|
+
// Przy ruchu bez wciśniętego przycisku tarcza ma tylko śledzić kursor wzrokiem, nie zmieniać
|
|
31
|
+
// wartości — inaczej samo przesunięcie myszy nad zegarem przestawiałoby godzinę.
|
|
32
|
+
else if (!(event.buttons & 1))
|
|
33
|
+
return;
|
|
34
|
+
const rect = face.getBoundingClientRect();
|
|
35
|
+
const dx = event.clientX - (rect.left + rect.width / 2);
|
|
36
|
+
const dy = event.clientY - (rect.top + rect.height / 2);
|
|
37
|
+
let deg = (Math.atan2(dx, -dy) * 180) / Math.PI;
|
|
38
|
+
if (deg < 0)
|
|
39
|
+
deg += 360;
|
|
40
|
+
if (phase === 'hours') {
|
|
41
|
+
emit(hourFromAngle(deg, Math.hypot(dx, dy) / (rect.width / 2), hourFormat, hour), minute);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
emit(hour, minuteFromAngle(deg, minuteStep));
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const marks = phase === 'hours' ? hourMarks(hour, hourFormat) : minuteMarks(minute);
|
|
48
|
+
return (_jsx("div", { className: cn('kpt-clock-host', className), ...rest, children: _jsxs("div", { className: "kpt-clock", children: [_jsxs("div", { className: "kpt-clock__time", children: [_jsx("button", { type: "button", className: cn('kpt-clock__seg', phase === 'hours' && 'is-active'), onClick: () => setPhase('hours'), children: hourFormat === 12 ? String(hour12) : pad(hour) }), _jsx("span", { className: "kpt-clock__colon", children: ":" }), _jsx("button", { type: "button", className: cn('kpt-clock__seg', phase === 'minutes' && 'is-active'), onClick: () => setPhase('minutes'), children: pad(minute) }), hourFormat === 12 ? (_jsxs("div", { className: "kpt-clock__ampm", children: [_jsx("button", { type: "button", className: cn(ampm === 'AM' && 'is-active'), onClick: () => emit(from12h(hour12, 'AM'), minute), children: "AM" }), _jsx("button", { type: "button", className: cn(ampm === 'PM' && 'is-active'), onClick: () => emit(from12h(hour12, 'PM'), minute), children: "PM" })] })) : null] }), _jsxs("div", { ref: faceRef, className: "kpt-clock__face", onPointerDown: onDialPointer, onPointerMove: onDialPointer, onPointerUp: () => phase === 'hours' && setPhase('minutes'), children: [_jsx("span", { className: "kpt-clock__center" }), _jsx("span", { className: cn('kpt-clock__hand', handIsInner(hour, hourFormat, phase) && 'kpt-clock__hand--inner'), style: { transform: `rotate(${handAngle(hour, minute, phase)}deg)` } }), marks.map((mark) => (_jsx("button", { type: "button", className: cn('kpt-clock__num', mark.inner && 'kpt-clock__num--inner', mark.selected && 'kpt-clock__num--selected'), style: { left: `${mark.x}%`, top: `${mark.y}%` }, onClick: () => {
|
|
49
|
+
if (phase === 'hours') {
|
|
50
|
+
emit(mark.value, minute);
|
|
51
|
+
setPhase('minutes');
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
emit(hour, mark.value);
|
|
55
|
+
}
|
|
56
|
+
}, children: mark.label }, `${phase}-${mark.value}`)))] })] }) }));
|
|
57
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
2
|
+
export interface KptColorPickerProps extends Omit<ComponentPropsWithRef<'div'>, 'onChange' | 'defaultValue'> {
|
|
3
|
+
/** Kolor jako hex, np. '#3b82f6'. */
|
|
4
|
+
value?: string;
|
|
5
|
+
defaultValue?: string;
|
|
6
|
+
onValueChange?: (value: string) => void;
|
|
7
|
+
/** Paleta szybkiego wyboru. */
|
|
8
|
+
presets?: string[];
|
|
9
|
+
disabled?: boolean;
|
|
10
|
+
invalid?: boolean;
|
|
11
|
+
touched?: boolean;
|
|
12
|
+
onTouch?: () => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Wybór koloru: próbka, pole hex i presety. Wartością jest hex.
|
|
16
|
+
*
|
|
17
|
+
* Próbka to natywny `<input type="color">` schowany pod kolorowym kwadratem — paletę systemową
|
|
18
|
+
* otwiera przeglądarka, więc działa też na telefonie i nie duplikujemy jej własnym kodem.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* <KptColorPicker value={color} onValueChange={setColor} />
|
|
22
|
+
*/
|
|
23
|
+
export declare function KptColorPicker({ value, defaultValue, onValueChange, presets, disabled, invalid, touched, onTouch, className, ...rest }: Readonly<KptColorPickerProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from "../internal/cn.js";
|
|
3
|
+
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
4
|
+
import { useKptFormFieldContext } from "../form-field/form-field-context.js";
|
|
5
|
+
const DEFAULT_PRESETS = [
|
|
6
|
+
'#ef4444',
|
|
7
|
+
'#f59e0b',
|
|
8
|
+
'#10b981',
|
|
9
|
+
'#3b82f6',
|
|
10
|
+
'#8b5cf6',
|
|
11
|
+
'#ec4899',
|
|
12
|
+
'#111827',
|
|
13
|
+
'#ffffff',
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Wybór koloru: próbka, pole hex i presety. Wartością jest hex.
|
|
17
|
+
*
|
|
18
|
+
* Próbka to natywny `<input type="color">` schowany pod kolorowym kwadratem — paletę systemową
|
|
19
|
+
* otwiera przeglądarka, więc działa też na telefonie i nie duplikujemy jej własnym kodem.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* <KptColorPicker value={color} onValueChange={setColor} />
|
|
23
|
+
*/
|
|
24
|
+
export function KptColorPicker({ value, defaultValue = '#3b82f6', onValueChange, presets = DEFAULT_PRESETS, disabled = false, invalid = false, touched, onTouch, className, ...rest }) {
|
|
25
|
+
const field = useKptFormFieldContext();
|
|
26
|
+
const [current, setCurrent] = useControllableState({ value, defaultValue, onChange: onValueChange });
|
|
27
|
+
return (_jsx("div", { className: cn('kpt-color-picker-host', className), ...rest, children: _jsxs("div", { className: "kpt-color-picker", children: [_jsx("label", { className: "kpt-color-picker__swatch", style: { backgroundColor: current }, children: _jsx("input", { type: "color", value: current, disabled: disabled, onChange: (event) => setCurrent(event.target.value), onBlur: () => onTouch?.() }) }), _jsx("input", { type: "text", className: "kpt-color-picker__hex", id: field?.controlId, value: current, disabled: disabled, maxLength: 7, "aria-invalid": (invalid && (touched ?? true)) || undefined, onChange: (event) => setCurrent(event.target.value), onBlur: () => onTouch?.() }), _jsx("div", { className: "kpt-color-picker__presets", children: presets.map((color) => (_jsx("button", { type: "button", className: cn('kpt-color-picker__preset', color === current && 'is-active'), style: { backgroundColor: color }, disabled: disabled, onClick: () => setCurrent(color), "aria-label": color }, color))) })] }) }));
|
|
28
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ComponentPropsWithRef } from 'react';
|
|
2
|
+
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
3
|
+
export interface KptConfirmContainerProps extends ComponentPropsWithRef<'div'>, KptI18nOverrides {
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Kontener potwierdzeń — renderuje żądanie z `kptConfirm()` na `KptDialog`. Umieść raz
|
|
7
|
+
* w aplikacji, obok `<KptToastContainer />`.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* <KptConfirmContainer />
|
|
11
|
+
* // gdziekolwiek: if (await kptConfirm({ message: 'Usunąć?' })) { … }
|
|
12
|
+
*/
|
|
13
|
+
export declare function KptConfirmContainer({ locale, dictionary, className, ...rest }: Readonly<KptConfirmContainerProps>): import("react").JSX.Element;
|
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
import { KptButton } from "../button/button.js";
|
|
5
|
+
import { KptDialog } from "../dialog/dialog.js";
|
|
6
|
+
import { KptIcon } from "../icon/icon.js";
|
|
7
|
+
import { acceptKptConfirm, rejectKptConfirm, useKptConfirmRequest } from "./confirm-store.js";
|
|
8
|
+
/**
|
|
9
|
+
* Kontener potwierdzeń — renderuje żądanie z `kptConfirm()` na `KptDialog`. Umieść raz
|
|
10
|
+
* w aplikacji, obok `<KptToastContainer />`.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <KptConfirmContainer />
|
|
14
|
+
* // gdziekolwiek: if (await kptConfirm({ message: 'Usunąć?' })) { … }
|
|
15
|
+
*/
|
|
16
|
+
export function KptConfirmContainer({ locale, dictionary, className, ...rest }) {
|
|
17
|
+
const { t } = useKptMessages({ locale, dictionary });
|
|
18
|
+
const request = useKptConfirmRequest();
|
|
19
|
+
return (_jsx("div", { className: cn('kpt-confirm-container-host', className), ...rest, children: _jsxs(KptDialog, { open: request !== null,
|
|
20
|
+
// Escape i × zamykają okno bez odpowiedzi — traktujemy to jak odmowę, żeby czekający
|
|
21
|
+
// `await` zawsze coś dostał.
|
|
22
|
+
onOpenChange: (open) => {
|
|
23
|
+
if (!open)
|
|
24
|
+
rejectKptConfirm();
|
|
25
|
+
}, header: request?.header ?? t('confirm.header'), locale: locale, dictionary: dictionary, children: [_jsxs("div", { className: "kpt-confirm__body", children: [request?.icon ? (_jsx(KptIcon, { className: "kpt-confirm__icon", name: request.icon, "data-variant": request.variant ?? 'filled' })) : null, _jsx("p", { className: "kpt-confirm__message", children: request?.message })] }), _jsxs(KptDialog.Footer, { children: [_jsx(KptButton, { variant: "text", onClick: rejectKptConfirm, children: request?.rejectLabel ?? t('confirm.reject') }), _jsx(KptButton, { variant: request?.variant ?? 'filled', onClick: acceptKptConfirm, children: request?.acceptLabel ?? t('confirm.accept') })] })] }) }));
|
|
26
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface KptConfirmOptions {
|
|
2
|
+
message: string;
|
|
3
|
+
header?: string;
|
|
4
|
+
acceptLabel?: string;
|
|
5
|
+
rejectLabel?: string;
|
|
6
|
+
/** Wariant przycisku akceptacji. */
|
|
7
|
+
variant?: 'filled' | 'danger';
|
|
8
|
+
icon?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface KptConfirmRequest extends KptConfirmOptions {
|
|
11
|
+
id: number;
|
|
12
|
+
resolve: (accepted: boolean) => void;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Pyta użytkownika o potwierdzenie. Wymaga `<KptConfirmContainer />` w aplikacji.
|
|
16
|
+
*
|
|
17
|
+
* Jedno żądanie naraz: kolejne wywołanie przy otwartym oknie odrzuca poprzednie, żeby jego
|
|
18
|
+
* Promise nigdy nie został nierozstrzygnięty — czekający `await` zostałby inaczej na zawsze.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* if (await kptConfirm({ message: 'Usunąć rekord?', variant: 'danger' })) { … }
|
|
22
|
+
*/
|
|
23
|
+
export declare function kptConfirm(options: KptConfirmOptions): Promise<boolean>;
|
|
24
|
+
/** Zamyka bieżące potwierdzenie odpowiedzią „tak". Używane przez kontener. */
|
|
25
|
+
export declare function acceptKptConfirm(): void;
|
|
26
|
+
/** Zamyka bieżące potwierdzenie odpowiedzią „nie" — także przy Escape i kliknięciu w tło. */
|
|
27
|
+
export declare function rejectKptConfirm(): void;
|
|
28
|
+
/** Bieżące żądanie potwierdzenia albo `null`. */
|
|
29
|
+
export declare function useKptConfirmRequest(): KptConfirmRequest | null;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useSyncExternalStore } from 'react';
|
|
2
|
+
/*
|
|
3
|
+
* Magazyn potwierdzeń jako moduł-singleton — odpowiednik serwisu `providedIn: 'root'` z Angulara,
|
|
4
|
+
* ten sam wzorzec co `kptToast`. Dzięki temu `await kptConfirm(...)` woła się także spoza drzewa
|
|
5
|
+
* Reacta (warstwa danych, guard nawigacji), bez owijania aplikacji providerem.
|
|
6
|
+
*/
|
|
7
|
+
let current = null;
|
|
8
|
+
let seq = 0;
|
|
9
|
+
const listeners = new Set();
|
|
10
|
+
function emit() {
|
|
11
|
+
for (const listener of listeners)
|
|
12
|
+
listener();
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Pyta użytkownika o potwierdzenie. Wymaga `<KptConfirmContainer />` w aplikacji.
|
|
16
|
+
*
|
|
17
|
+
* Jedno żądanie naraz: kolejne wywołanie przy otwartym oknie odrzuca poprzednie, żeby jego
|
|
18
|
+
* Promise nigdy nie został nierozstrzygnięty — czekający `await` zostałby inaczej na zawsze.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* if (await kptConfirm({ message: 'Usunąć rekord?', variant: 'danger' })) { … }
|
|
22
|
+
*/
|
|
23
|
+
export function kptConfirm(options) {
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
current?.resolve(false);
|
|
26
|
+
current = { id: ++seq, ...options, resolve };
|
|
27
|
+
emit();
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function settle(accepted) {
|
|
31
|
+
current?.resolve(accepted);
|
|
32
|
+
current = null;
|
|
33
|
+
emit();
|
|
34
|
+
}
|
|
35
|
+
/** Zamyka bieżące potwierdzenie odpowiedzią „tak". Używane przez kontener. */
|
|
36
|
+
export function acceptKptConfirm() {
|
|
37
|
+
settle(true);
|
|
38
|
+
}
|
|
39
|
+
/** Zamyka bieżące potwierdzenie odpowiedzią „nie" — także przy Escape i kliknięciu w tło. */
|
|
40
|
+
export function rejectKptConfirm() {
|
|
41
|
+
settle(false);
|
|
42
|
+
}
|
|
43
|
+
function subscribe(listener) {
|
|
44
|
+
listeners.add(listener);
|
|
45
|
+
return () => {
|
|
46
|
+
listeners.delete(listener);
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Bieżące żądanie potwierdzenia albo `null`. */
|
|
50
|
+
export function useKptConfirmRequest() {
|
|
51
|
+
return useSyncExternalStore(subscribe, () => current, () => null);
|
|
52
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
|
+
import type { KptMenuItem } from '../menu/menu-item.ts';
|
|
3
|
+
export interface KptContextMenuProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onSelect'> {
|
|
4
|
+
items?: KptMenuItem<T>[];
|
|
5
|
+
/** Obszar reagujący na prawy przycisk myszy. */
|
|
6
|
+
children?: ReactNode;
|
|
7
|
+
onSelect?: (item: KptMenuItem<T>) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Menu kontekstowe (PPM) na obszarze dzieci. Panel pozycjonowany do kursora.
|
|
11
|
+
*
|
|
12
|
+
* W odróżnieniu od `KptMenu` panel nie idzie przez `KptOverlay` — nie ma tu wyzwalacza,
|
|
13
|
+
* względem którego dałoby się go przypiąć; pozycję wyznaczają współrzędne kliknięcia,
|
|
14
|
+
* a wygląd i warstwę niesie wspólny SCSS (`.kpt-context-menu__panel`).
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <KptContextMenu items={items} onSelect={onSelect}>
|
|
18
|
+
* <div className="obszar">Kliknij prawym przyciskiem</div>
|
|
19
|
+
* </KptContextMenu>
|
|
20
|
+
*/
|
|
21
|
+
export declare function KptContextMenu<T>({ items, children, onSelect, className, ...rest }: Readonly<KptContextMenuProps<T>>): import("react").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { cn } from "../internal/cn.js";
|
|
4
|
+
import { MenuRows } from "../menu/menu-rows.js";
|
|
5
|
+
/**
|
|
6
|
+
* Menu kontekstowe (PPM) na obszarze dzieci. Panel pozycjonowany do kursora.
|
|
7
|
+
*
|
|
8
|
+
* W odróżnieniu od `KptMenu` panel nie idzie przez `KptOverlay` — nie ma tu wyzwalacza,
|
|
9
|
+
* względem którego dałoby się go przypiąć; pozycję wyznaczają współrzędne kliknięcia,
|
|
10
|
+
* a wygląd i warstwę niesie wspólny SCSS (`.kpt-context-menu__panel`).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <KptContextMenu items={items} onSelect={onSelect}>
|
|
14
|
+
* <div className="obszar">Kliknij prawym przyciskiem</div>
|
|
15
|
+
* </KptContextMenu>
|
|
16
|
+
*/
|
|
17
|
+
export function KptContextMenu({ items = [], children, onSelect, className, ...rest }) {
|
|
18
|
+
const [open, setOpen] = useState(false);
|
|
19
|
+
const [point, setPoint] = useState({ x: 0, y: 0 });
|
|
20
|
+
const onContextMenu = (event) => {
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
setPoint({ x: event.clientX, y: event.clientY });
|
|
23
|
+
setOpen(true);
|
|
24
|
+
};
|
|
25
|
+
const close = () => setOpen(false);
|
|
26
|
+
const pick = (item) => {
|
|
27
|
+
if (item.disabled)
|
|
28
|
+
return;
|
|
29
|
+
onSelect?.(item);
|
|
30
|
+
close();
|
|
31
|
+
};
|
|
32
|
+
return (_jsxs("div", { className: cn('kpt-context-menu-host', className), ...rest, children: [_jsx("div", { className: "kpt-context-menu__area", onContextMenu: onContextMenu, children: children }), open ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "kpt-context-menu__backdrop", onClick: close, onContextMenu: (event) => {
|
|
33
|
+
event.preventDefault();
|
|
34
|
+
close();
|
|
35
|
+
} }), _jsx("div", { className: "kpt-context-menu__panel", role: "menu", style: { left: point.x, top: point.y }, children: _jsx(MenuRows, { items: items, block: "kpt-context-menu", onPick: pick }) })] })) : null] }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { KptColumnFilter, KptColumnSummary } from '@konce-pt/table';
|
|
2
|
+
import type { ReactNode } from 'react';
|
|
3
|
+
import type { KptOption } from '../shared/types.ts';
|
|
4
|
+
/** Rodzaj kontrolki edycji inline komórki. */
|
|
5
|
+
export type KptColumnEditType = 'text' | 'number' | 'date' | 'select' | 'multiselect';
|
|
6
|
+
export interface KptColumnEdit {
|
|
7
|
+
type: KptColumnEditType;
|
|
8
|
+
/** Opcje dla `type: 'select'` / `'multiselect'`. */
|
|
9
|
+
options?: KptOption<unknown>[];
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
/** Dla `type: 'number'`. */
|
|
12
|
+
min?: number;
|
|
13
|
+
max?: number;
|
|
14
|
+
step?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface KptColumn {
|
|
17
|
+
/** Nazwa pola w wierszu. */
|
|
18
|
+
field: string;
|
|
19
|
+
/** Nagłówek kolumny. */
|
|
20
|
+
header: string;
|
|
21
|
+
sortable?: boolean;
|
|
22
|
+
align?: 'start' | 'center' | 'end';
|
|
23
|
+
/** Szerokość kolumny (np. '10rem', '20%'). Wymagana dla kolumn zamrożonych. */
|
|
24
|
+
width?: string;
|
|
25
|
+
/** Zamrożenie (sticky) — obsługiwane dla wiodących, sąsiadujących kolumn. */
|
|
26
|
+
frozen?: boolean;
|
|
27
|
+
/** Filtr kolumny w wierszu nagłówka. */
|
|
28
|
+
filter?: KptColumnFilter;
|
|
29
|
+
/** Włącza edycję inline (klik w komórkę zamienia wartość na kontrolkę tego typu). */
|
|
30
|
+
edit?: KptColumnEdit;
|
|
31
|
+
/** Włącza agregację tej kolumny w wierszu podsumowania (`<tfoot>`). */
|
|
32
|
+
summary?: KptColumnSummary;
|
|
33
|
+
}
|
|
34
|
+
/** Zdarzenie po zatwierdzeniu edycji komórki. */
|
|
35
|
+
export interface KptCellEditEvent<T> {
|
|
36
|
+
/** Wiersz sprzed zmiany. */
|
|
37
|
+
row: T;
|
|
38
|
+
field: string;
|
|
39
|
+
/** Nowa wartość. */
|
|
40
|
+
value: unknown;
|
|
41
|
+
/** Wiersz po scaleniu ze zmienioną wartością — gotowe body PUT/PATCH. */
|
|
42
|
+
updatedRow: T;
|
|
43
|
+
}
|
|
44
|
+
export type KptSortDir = 'asc' | 'desc' | null;
|
|
45
|
+
/** Stan przekazywany w trybie lazy przy każdej zmianie sortowania, filtra albo strony. */
|
|
46
|
+
export interface KptTableLazyState {
|
|
47
|
+
pageIndex: number;
|
|
48
|
+
pageSize: number;
|
|
49
|
+
sortField: string | null;
|
|
50
|
+
sortDir: KptSortDir;
|
|
51
|
+
filter: string;
|
|
52
|
+
/** Wartości filtrów per kolumna (pole → wartość kontrolki). */
|
|
53
|
+
columnFilters: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
/** Kontekst własnego edytora komórki (odpowiednik `kptCellEdit` z Angulara). */
|
|
56
|
+
export interface KptCellEditContext<T> {
|
|
57
|
+
value: unknown;
|
|
58
|
+
row: T;
|
|
59
|
+
/** Zatwierdza wartość i zamyka edytor. */
|
|
60
|
+
commit: (value: unknown) => void;
|
|
61
|
+
/** Porzuca zmianę. */
|
|
62
|
+
cancel: () => void;
|
|
63
|
+
}
|
|
64
|
+
/** Szablony komórek: pole → funkcja renderująca (odpowiednik `kptCell`). */
|
|
65
|
+
export type KptCellRenderers<T> = Record<string, (row: T, value: unknown) => ReactNode>;
|
|
66
|
+
/** Własne edytory komórek: pole → funkcja renderująca (odpowiednik `kptCellEdit`). */
|
|
67
|
+
export type KptCellEditRenderers<T> = Record<string, (context: KptCellEditContext<T>) => ReactNode>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type ComponentPropsWithRef, type ReactNode } from 'react';
|
|
2
|
+
import { type KptI18nOverrides } from '../i18n/i18n-context.tsx';
|
|
3
|
+
import type { KptCellEditEvent, KptCellEditRenderers, KptCellRenderers, KptColumn, KptTableLazyState } from './data-table-types.ts';
|
|
4
|
+
export interface KptDataTableProps<T> extends Omit<ComponentPropsWithRef<'div'>, 'onSelect' | 'children'>, KptI18nOverrides {
|
|
5
|
+
columns: readonly KptColumn[];
|
|
6
|
+
data?: readonly T[];
|
|
7
|
+
/** Pole filtra globalnego w pasku narzędzi. */
|
|
8
|
+
filterable?: boolean;
|
|
9
|
+
filterRowPosition?: 'top' | 'bottom';
|
|
10
|
+
/** Rozmiar strony; 0 wyłącza paginację. */
|
|
11
|
+
pageSize?: number;
|
|
12
|
+
pageSizeOptions?: number[];
|
|
13
|
+
selectable?: 'none' | 'single' | 'multiple';
|
|
14
|
+
loading?: boolean;
|
|
15
|
+
emptyMessage?: string;
|
|
16
|
+
/** Pole identyfikujące wiersz; bez niego wiersze porównujemy po referencji. */
|
|
17
|
+
rowKey?: string | null;
|
|
18
|
+
scrollHeight?: string | null;
|
|
19
|
+
/** Wirtualizacja wierszy; wymaga `scrollHeight`. */
|
|
20
|
+
virtualScroll?: boolean;
|
|
21
|
+
rowHeight?: number;
|
|
22
|
+
reorderable?: boolean;
|
|
23
|
+
exportable?: boolean;
|
|
24
|
+
exportFilename?: string;
|
|
25
|
+
/** Tryb serwerowy: bez filtrowania, sortowania i paginacji po stronie klienta. */
|
|
26
|
+
lazy?: boolean;
|
|
27
|
+
totalRecords?: number | null;
|
|
28
|
+
expandable?: boolean;
|
|
29
|
+
multiExpand?: boolean;
|
|
30
|
+
summaryLabel?: string;
|
|
31
|
+
/** Gotowe wartości podsumowania (pole → wartość); nadpisują wyliczenia, w `lazy` są jedynym źródłem. */
|
|
32
|
+
summaryValues?: Record<string, unknown> | null;
|
|
33
|
+
selection?: T[];
|
|
34
|
+
defaultSelection?: T[];
|
|
35
|
+
onSelectionChange?: (rows: T[]) => void;
|
|
36
|
+
expandedRows?: T[];
|
|
37
|
+
defaultExpandedRows?: T[];
|
|
38
|
+
onExpandedRowsChange?: (rows: T[]) => void;
|
|
39
|
+
hiddenFields?: readonly string[];
|
|
40
|
+
defaultHiddenFields?: readonly string[];
|
|
41
|
+
onHiddenFieldsChange?: (fields: readonly string[]) => void;
|
|
42
|
+
onRowClick?: (row: T) => void;
|
|
43
|
+
onLazyLoad?: (state: KptTableLazyState) => void;
|
|
44
|
+
onCellEdit?: (event: KptCellEditEvent<T>) => void;
|
|
45
|
+
/** Szablony komórek: pole → funkcja renderująca. */
|
|
46
|
+
cells?: KptCellRenderers<T>;
|
|
47
|
+
/** Własne edytory komórek: pole → funkcja renderująca. */
|
|
48
|
+
cellEditors?: KptCellEditRenderers<T>;
|
|
49
|
+
/** Treść rozwiniętego wiersza (wymaga `expandable`). */
|
|
50
|
+
renderRowDetail?: (row: T) => ReactNode;
|
|
51
|
+
/** Treść po lewej stronie paginatora (odpowiednik slotu `[kptPaginatorActions]`). */
|
|
52
|
+
paginatorActions?: ReactNode;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Flagowa tabela danych: kolumny konfiguracją, sortowanie, filtr globalny i filtry kolumn,
|
|
56
|
+
* paginacja, zaznaczanie, kolumny zamrożone i przestawiane, edycja inline, wiersz podsumowania,
|
|
57
|
+
* rozwijane wiersze, wirtualizacja i eksport CSV.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* <KptDataTable columns={cols} data={rows} filterable pageSize={10} selectable="multiple" rowKey="id" />
|
|
61
|
+
*/
|
|
62
|
+
export declare function KptDataTable<T extends Record<string, unknown>>({ columns, data, filterable, filterRowPosition, pageSize, pageSizeOptions, selectable, loading, emptyMessage, rowKey, scrollHeight, virtualScroll, rowHeight, reorderable, exportable, exportFilename, lazy, totalRecords, expandable, multiExpand, summaryLabel, summaryValues, selection, defaultSelection, onSelectionChange, expandedRows, defaultExpandedRows, onExpandedRowsChange, hiddenFields, defaultHiddenFields, onHiddenFieldsChange, onRowClick, onLazyLoad, onCellEdit, cells, cellEditors, renderRowDetail, paginatorActions, locale, dictionary, className, style, ...rest }: Readonly<KptDataTableProps<T>>): import("react").JSX.Element;
|