@konce-pt/react 0.11.1 → 0.12.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 +8 -2
- package/dist/accordion/accordion.js +11 -10
- package/dist/alert/alert.js +1 -0
- package/dist/alert/llms.txt +1 -0
- package/dist/app-shell/app-shell.js +12 -5
- package/dist/app-shell/llms.txt +5 -4
- package/dist/auth/auth.js +17 -8
- package/dist/auth/llms.txt +3 -2
- package/dist/autocomplete/autocomplete.d.ts +1 -1
- package/dist/autocomplete/autocomplete.js +12 -4
- package/dist/autocomplete/llms.txt +3 -0
- package/dist/avatar/avatar.js +1 -0
- package/dist/avatar-group/avatar-group.js +1 -0
- package/dist/backdrop/backdrop.d.ts +0 -19
- package/dist/backdrop/backdrop.js +18 -13
- package/dist/bottom-sheet/bottom-sheet.d.ts +6 -1
- package/dist/bottom-sheet/bottom-sheet.js +3 -2
- package/dist/bottom-sheet/llms.txt +3 -0
- package/dist/breadcrumb/breadcrumb.d.ts +7 -1
- package/dist/breadcrumb/breadcrumb.js +10 -2
- package/dist/breadcrumb/llms.txt +8 -0
- package/dist/button/button.js +2 -1
- package/dist/button-group/button-group.d.ts +15 -2
- package/dist/button-group/button-group.js +31 -4
- package/dist/button-group/llms.txt +9 -6
- package/dist/card/card.js +4 -3
- package/dist/carousel/carousel.js +4 -1
- package/dist/charts/chart-legend.js +1 -0
- package/dist/charts/chart.d.ts +3 -2
- package/dist/charts/chart.js +12 -4
- package/dist/charts/llms.txt +6 -3
- package/dist/chat/chat.js +39 -9
- package/dist/chat/llms.txt +9 -0
- package/dist/chat-composer/chat-composer.d.ts +5 -2
- package/dist/chat-composer/chat-composer.js +10 -1
- package/dist/chat-dock/chat-dock.js +1 -0
- package/dist/chat-message/chat-message.js +2 -1
- package/dist/chat-typing/chat-typing.js +1 -0
- package/dist/checkbox/checkbox.d.ts +1 -1
- package/dist/checkbox/checkbox.js +9 -2
- package/dist/checkbox/llms.txt +3 -0
- package/dist/chip/chip.js +1 -0
- package/dist/chips-input/chips-input.d.ts +3 -1
- package/dist/chips-input/chips-input.js +14 -5
- package/dist/chips-input/llms.txt +3 -0
- package/dist/clock/clock.d.ts +9 -4
- package/dist/clock/clock.js +35 -5
- package/dist/clock/llms.txt +6 -2
- package/dist/color-picker/color-picker.d.ts +5 -1
- package/dist/color-picker/color-picker.js +36 -17
- package/dist/color-picker/llms.txt +3 -0
- package/dist/confirm/confirm-container.js +1 -0
- package/dist/confirm/confirm-store.js +6 -0
- package/dist/confirm/llms.txt +2 -1
- package/dist/context-menu/context-menu.js +35 -12
- package/dist/context-menu/llms.txt +3 -0
- package/dist/data-table/data-table.d.ts +12 -1
- package/dist/data-table/data-table.js +113 -51
- package/dist/data-table/export-csv.d.ts +2 -2
- package/dist/data-table/export-csv.js +7 -9
- package/dist/data-table/llms.txt +19 -4
- package/dist/data-view/data-view.js +1 -0
- package/dist/date-range/date-range.d.ts +16 -4
- package/dist/date-range/date-range.js +69 -46
- package/dist/date-range/llms.txt +17 -3
- package/dist/datepicker/datepicker.d.ts +17 -3
- package/dist/datepicker/datepicker.js +86 -54
- package/dist/datepicker/llms.txt +17 -3
- package/dist/dialog/dialog.js +29 -8
- package/dist/dialog/llms.txt +3 -0
- package/dist/divider/divider.d.ts +7 -1
- package/dist/divider/divider.js +3 -2
- package/dist/divider/llms.txt +1 -0
- package/dist/drawer/drawer.d.ts +6 -1
- package/dist/drawer/drawer.js +3 -2
- package/dist/drawer/llms.txt +3 -0
- package/dist/fieldset/fieldset.js +4 -1
- package/dist/file-upload/file-upload.d.ts +7 -1
- package/dist/file-upload/file-upload.js +18 -7
- package/dist/file-upload/llms.txt +6 -3
- package/dist/form-field/form-field.js +1 -0
- package/dist/galleria/galleria.js +4 -1
- package/dist/i18n/i18n-context.d.ts +3 -3
- package/dist/i18n/i18n-context.js +25 -3
- package/dist/icon/icon.js +4 -1
- package/dist/image/image.js +4 -4
- package/dist/input/input.js +1 -0
- package/dist/input-mask/input-mask.d.ts +7 -2
- package/dist/input-mask/input-mask.js +15 -41
- package/dist/input-mask/llms.txt +3 -0
- package/dist/input-number/input-number.d.ts +3 -1
- package/dist/input-number/input-number.js +15 -11
- package/dist/input-number/llms.txt +5 -2
- package/dist/input-otp/input-otp.d.ts +16 -3
- package/dist/input-otp/input-otp.js +43 -19
- package/dist/input-otp/llms.txt +11 -0
- package/dist/internal/mask.d.ts +14 -0
- package/dist/internal/mask.js +62 -0
- package/dist/internal/number-group.d.ts +22 -0
- package/dist/internal/number-group.js +53 -0
- package/dist/internal/option-key.d.ts +6 -0
- package/dist/internal/option-key.js +8 -0
- package/dist/internal/overlay.js +37 -7
- package/dist/internal/password-strength.d.ts +6 -0
- package/dist/internal/password-strength.js +74 -0
- package/dist/internal/scroll-lock.d.ts +6 -0
- package/dist/internal/scroll-lock.js +35 -0
- package/dist/internal/slot-children.d.ts +13 -0
- package/dist/internal/slot-children.js +31 -0
- package/dist/internal/step.d.ts +12 -0
- package/dist/internal/step.js +31 -0
- package/dist/internal/tween.js +2 -3
- package/dist/internal/use-controllable-state.d.ts +5 -0
- package/dist/internal/use-controllable-state.js +25 -4
- package/dist/internal/use-modal-focus.d.ts +1 -0
- package/dist/internal/use-modal-focus.js +12 -1
- package/dist/knob/knob.d.ts +5 -2
- package/dist/knob/knob.js +15 -14
- package/dist/knob/llms.txt +4 -2
- package/dist/listbox/listbox.d.ts +3 -1
- package/dist/listbox/listbox.js +30 -10
- package/dist/listbox/llms.txt +3 -0
- package/dist/map/llms.txt +5 -1
- package/dist/map/map-create-dialog.js +30 -22
- package/dist/map/map-hours-field.js +1 -0
- package/dist/map/map-image-field.js +2 -1
- package/dist/map/map-legend.js +1 -0
- package/dist/map/map-poi-card.js +2 -1
- package/dist/map/map-search.js +54 -30
- package/dist/map/map.d.ts +6 -1
- package/dist/map/map.js +62 -34
- package/dist/megamenu/llms.txt +11 -0
- package/dist/megamenu/megamenu.d.ts +7 -1
- package/dist/megamenu/megamenu.js +15 -6
- package/dist/menu/menu-rows.js +1 -0
- package/dist/menu/menu.js +10 -3
- package/dist/menubar/llms.txt +11 -0
- package/dist/menubar/menubar.d.ts +7 -1
- package/dist/menubar/menubar.js +15 -3
- package/dist/meter-group/meter-group.js +1 -0
- package/dist/order-list/llms.txt +3 -0
- package/dist/order-list/order-list.js +21 -6
- package/dist/paginator/paginator.js +7 -4
- package/dist/panel/panel.js +5 -3
- package/dist/password/llms.txt +6 -2
- package/dist/password/password.js +4 -14
- package/dist/peek/llms.txt +1 -1
- package/dist/peek/peek.js +37 -15
- package/dist/pick-list/llms.txt +3 -0
- package/dist/pick-list/pick-list.js +19 -3
- package/dist/popover/llms.txt +3 -0
- package/dist/popover/popover.d.ts +3 -1
- package/dist/popover/popover.js +10 -3
- package/dist/progress/progress.js +1 -0
- package/dist/public-api.d.ts +1 -1
- package/dist/radio-group/llms.txt +3 -0
- package/dist/radio-group/radio-group.d.ts +3 -1
- package/dist/radio-group/radio-group.js +13 -2
- package/dist/rating/rating.js +1 -0
- package/dist/rich-text/llms.txt +14 -0
- package/dist/rich-text/rich-text.d.ts +3 -9
- package/dist/rich-text/rich-text.js +241 -96
- package/dist/rich-text/sanitize.d.ts +9 -0
- package/dist/rich-text/sanitize.js +77 -29
- package/dist/roadmap/llms.txt +9 -3
- package/dist/roadmap/roadmap.js +88 -11
- package/dist/scroll-top/scroll-top.js +1 -0
- package/dist/select/llms.txt +3 -0
- package/dist/select/select.d.ts +3 -1
- package/dist/select/select.js +46 -32
- package/dist/shared/types.d.ts +21 -0
- package/dist/shared/types.js +9 -1
- package/dist/sidenav/sidenav.d.ts +1 -2
- package/dist/sidenav/sidenav.js +4 -3
- package/dist/slider/llms.txt +3 -0
- package/dist/slider/slider.d.ts +3 -1
- package/dist/slider/slider.js +15 -4
- package/dist/speed-dial/speed-dial.js +2 -1
- package/dist/spinner/spinner.js +1 -0
- package/dist/split-button/split-button.js +10 -3
- package/dist/splitter/splitter.js +23 -8
- package/dist/stepper/llms.txt +3 -0
- package/dist/stepper/stepper.js +9 -5
- package/dist/switch/llms.txt +3 -0
- package/dist/switch/switch.d.ts +1 -1
- package/dist/switch/switch.js +9 -2
- package/dist/switch-group/llms.txt +3 -0
- package/dist/switch-group/switch-group.d.ts +3 -1
- package/dist/switch-group/switch-group.js +5 -3
- package/dist/tabs/llms.txt +3 -0
- package/dist/tabs/tabs.js +30 -14
- package/dist/textarea/textarea.js +1 -0
- package/dist/toast/llms.txt +3 -0
- package/dist/toast/toast-container.js +1 -0
- package/dist/toast/toast-store.d.ts +5 -1
- package/dist/toast/toast-store.js +1 -1
- package/dist/tooltip/llms.txt +5 -3
- package/dist/tooltip/tooltip.d.ts +3 -2
- package/dist/tooltip/tooltip.js +148 -55
- package/dist/tree/llms.txt +1 -0
- package/dist/tree/tree.d.ts +6 -1
- package/dist/tree/tree.js +14 -7
- package/package.json +15 -14
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client';
|
|
1
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
3
|
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
3
4
|
import { createPortal } from 'react-dom';
|
|
@@ -8,11 +9,12 @@ import { useKptOverlayContainer } from "../internal/overlay-container.js";
|
|
|
8
9
|
import { KptOverlay } from "../internal/overlay.js";
|
|
9
10
|
import { useKptMessages } from "../i18n/i18n-context.js";
|
|
10
11
|
import { KptIcon } from "../icon/icon.js";
|
|
11
|
-
import { sanitizeHtml, sanitizeUrl } from "./sanitize.js";
|
|
12
|
+
import { sanitizeHtml, sanitizeHtmlReport, sanitizeUrl } from "./sanitize.js";
|
|
12
13
|
import { canIndentItem, canOutdentItem, selectedItems, shiftItems } from "./lists.js";
|
|
13
14
|
import { CELL_SELECTED, deleteColumn, deleteRow, insertColumn, insertRow, mergeCells, regionBetween, splitCell, tableHtml, toggleHeaderColumn, toggleHeaderRow, } from "./tables.js";
|
|
14
15
|
import { useKptFieldA11y } from "../form-field/form-field-context.js";
|
|
15
16
|
import { nextRovingIndex } from "../internal/roving.js";
|
|
17
|
+
import { trapTab } from "../internal/calendar-focus.js";
|
|
16
18
|
import { focusMenuEdge, handleMenuKeydown } from "../menu/menu-keys.js";
|
|
17
19
|
const ICON = {
|
|
18
20
|
copy: 'copy',
|
|
@@ -84,25 +86,21 @@ const GRID_COLS = Array.from({ length: 8 }, (_, i) => i + 1);
|
|
|
84
86
|
* (Ctrl+Z). Własne komendy wymagałyby własnej historii, czyli przepisania edytora.
|
|
85
87
|
*/
|
|
86
88
|
function legacyExec(cmd, value) {
|
|
89
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- brak zamiennika, patrz JSDoc
|
|
87
90
|
return document.execCommand(cmd, false, value); // NOSONAR: brak zamiennika, patrz JSDoc
|
|
88
91
|
}
|
|
89
92
|
function legacyState(cmd) {
|
|
90
93
|
try {
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-deprecated -- brak zamiennika, patrz `legacyExec`
|
|
91
95
|
return document.queryCommandState(cmd); // NOSONAR: brak zamiennika
|
|
92
96
|
}
|
|
93
97
|
catch {
|
|
94
98
|
return false;
|
|
95
99
|
}
|
|
96
100
|
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* <KptRichText value={html} onValueChange={setHtml} />
|
|
103
|
-
* <KptRichText value={html} onValueChange={setHtml} toolbar={[['bold', 'italic'], ['link']]} />
|
|
104
|
-
*/
|
|
105
|
-
export function KptRichText({ value, defaultValue = '', onValueChange, toolbar = DEFAULT_TOOLBAR, placeholder = '', maxListLevel = 6, id, ariaLabel = null, required = false, disabled = false, invalid = false, touched, onTouch, mentions = [], mentionLimit = KPT_MENTION_LIMIT, onMention, locale, dictionary, className, ...rest }) {
|
|
101
|
+
export function KptRichText({ value, defaultValue = '', onValueChange, toolbar = DEFAULT_TOOLBAR, placeholder = '', maxListLevel = 6, id, ariaLabel = null, required = false, disabled: disabledProp = false, readOnly = false, invalid = false, touched, onTouch, mentions = [], mentionLimit = KPT_MENTION_LIMIT, onMention, locale, dictionary, className, ...rest }) {
|
|
102
|
+
/** Edycja zablokowana: wyłączone pole albo tylko do odczytu — narzędzia i skróty nie działają. */
|
|
103
|
+
const disabled = disabledProp || readOnly;
|
|
106
104
|
/** `contenteditable` nie dostaje nazwy z `label[for]` — stąd `aria-labelledby` na etykietę wrappera. */
|
|
107
105
|
const field = useKptFieldA11y(id, 'kpt-rich-text');
|
|
108
106
|
const { t } = useKptMessages({ locale, dictionary });
|
|
@@ -128,6 +126,8 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
128
126
|
const [colorOpen, setColorOpen] = useState(false);
|
|
129
127
|
const [colorKind, setColorKind] = useState('foreColor');
|
|
130
128
|
const [tableOpen, setTableOpen] = useState(false);
|
|
129
|
+
/** Aktywna opcja listy stylów (aria-activedescendant). */
|
|
130
|
+
const [styleActive, setStyleActive] = useState(0);
|
|
131
131
|
const [grid, setGrid] = useState({ r: 0, c: 0 });
|
|
132
132
|
const [sourceView, setSourceView] = useState(false);
|
|
133
133
|
const [menuOpen, setMenuOpen] = useState(false);
|
|
@@ -148,7 +148,7 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
148
148
|
const [currentBlock, setCurrentBlock] = useState('p');
|
|
149
149
|
const [selCount, setSelCount] = useState(0);
|
|
150
150
|
const ctxCell = useRef(null);
|
|
151
|
-
const canSplitCtx =
|
|
151
|
+
const [canSplitCtx, setCanSplitCtx] = useState(false);
|
|
152
152
|
const selCells = useRef(new Set());
|
|
153
153
|
const selAnchor = useRef(null);
|
|
154
154
|
const selecting = useRef(false);
|
|
@@ -167,13 +167,19 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
167
167
|
* Zapis z zewnątrz wstawiamy ręcznie, bo `contenteditable` nie może być renderowany przez
|
|
168
168
|
* Reacta — przerysowanie kasowałoby zaznaczenie i pozycję kursora przy każdym znaku.
|
|
169
169
|
* Porównanie z surowym `innerHTML` sprawia, że pisanie w edytorze nie wchodzi w tę gałąź,
|
|
170
|
-
* więc sanityzacja włącza się wyłącznie przy zapisie z aplikacji albo z trybu HTML.
|
|
170
|
+
* więc sanityzacja włącza się wyłącznie przy zapisie z aplikacji albo z trybu HTML. Gdy
|
|
171
|
+
* sanityzator coś usunął, oczyszczona treść wraca też do wartości — inaczej aplikacja dostawałaby
|
|
172
|
+
* z powrotem niebezpieczny HTML. Sama różnica zapisu (cudzysłowy) wartości nie rusza.
|
|
171
173
|
*/
|
|
172
174
|
useEffect(() => {
|
|
173
175
|
const el = editorRef.current;
|
|
174
|
-
if (el
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
if (!el || el.innerHTML === current)
|
|
177
|
+
return;
|
|
178
|
+
const clean = sanitizeHtmlReport(current);
|
|
179
|
+
el.innerHTML = clean.html;
|
|
180
|
+
if (clean.changed)
|
|
181
|
+
setCurrent(clean.html);
|
|
182
|
+
}, [current, setCurrent, sourceView]);
|
|
177
183
|
const inEditor = useCallback(() => {
|
|
178
184
|
const el = editorRef.current;
|
|
179
185
|
const selection = window.getSelection();
|
|
@@ -325,7 +331,7 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
325
331
|
if (!(target instanceof Element))
|
|
326
332
|
return;
|
|
327
333
|
const focus = target.closest('td, th');
|
|
328
|
-
if (
|
|
334
|
+
if (focus?.closest('table') !== selAnchor.current.closest('table'))
|
|
329
335
|
return;
|
|
330
336
|
if (focus === selAnchor.current && !selecting.current)
|
|
331
337
|
return;
|
|
@@ -571,6 +577,39 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
571
577
|
pushValue();
|
|
572
578
|
};
|
|
573
579
|
// ── Tabele ──
|
|
580
|
+
const pickStyle = (tag) => {
|
|
581
|
+
setStyleOpen(false);
|
|
582
|
+
focusEditor();
|
|
583
|
+
restoreSelection();
|
|
584
|
+
legacyExec('formatBlock', `<${tag}>`);
|
|
585
|
+
pushValue();
|
|
586
|
+
refreshState();
|
|
587
|
+
};
|
|
588
|
+
/** Siatka tabeli z klawiatury: strzałki zmieniają rozmiar (1–8), Enter wstawia, Escape wraca. */
|
|
589
|
+
const onGridKeyDown = (event) => {
|
|
590
|
+
const clamp = (n) => Math.min(GRID_ROWS.length, Math.max(1, n));
|
|
591
|
+
const r = grid.r || 1;
|
|
592
|
+
const c = grid.c || 1;
|
|
593
|
+
if (event.key === 'ArrowDown')
|
|
594
|
+
setGrid({ r: clamp(r + 1), c });
|
|
595
|
+
else if (event.key === 'ArrowUp')
|
|
596
|
+
setGrid({ r: clamp(r - 1), c });
|
|
597
|
+
else if (event.key === 'ArrowRight')
|
|
598
|
+
setGrid({ r, c: clamp(c + 1) });
|
|
599
|
+
else if (event.key === 'ArrowLeft')
|
|
600
|
+
setGrid({ r, c: clamp(c - 1) });
|
|
601
|
+
else if (event.key === 'Enter' || event.key === ' ')
|
|
602
|
+
insertTableAt(r, c);
|
|
603
|
+
else if (event.key === 'Escape') {
|
|
604
|
+
setTableOpen(false);
|
|
605
|
+
setGrid({ r: 0, c: 0 });
|
|
606
|
+
tableAnchor?.focus();
|
|
607
|
+
}
|
|
608
|
+
else
|
|
609
|
+
return;
|
|
610
|
+
event.preventDefault();
|
|
611
|
+
event.stopPropagation();
|
|
612
|
+
};
|
|
574
613
|
const insertTableAt = (rows, cols) => {
|
|
575
614
|
setTableOpen(false);
|
|
576
615
|
setGrid({ r: 0, c: 0 });
|
|
@@ -608,7 +647,7 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
608
647
|
const rect = cell.getBoundingClientRect();
|
|
609
648
|
saveSelection();
|
|
610
649
|
ctxCell.current = cell;
|
|
611
|
-
|
|
650
|
+
setCanSplitCtx((cell.colSpan || 1) > 1 || (cell.rowSpan || 1) > 1);
|
|
612
651
|
setMenuPoint({ x: rect.left, y: rect.bottom });
|
|
613
652
|
menuFromKeyboard.current = true;
|
|
614
653
|
setMenuOpen(true);
|
|
@@ -650,7 +689,7 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
650
689
|
event.preventDefault();
|
|
651
690
|
saveSelection();
|
|
652
691
|
ctxCell.current = cell;
|
|
653
|
-
|
|
692
|
+
setCanSplitCtx((cell.colSpan || 1) > 1 || (cell.rowSpan || 1) > 1);
|
|
654
693
|
setMenuPoint({ x: event.clientX, y: event.clientY });
|
|
655
694
|
setMenuOpen(true);
|
|
656
695
|
};
|
|
@@ -738,7 +777,54 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
738
777
|
return canOutdent;
|
|
739
778
|
return true;
|
|
740
779
|
};
|
|
741
|
-
|
|
780
|
+
/**
|
|
781
|
+
* Panele narzędzi żyją w nakładce na końcu `<body>` — po zamontowaniu fokus wchodzi do środka,
|
|
782
|
+
* inaczej Tab musiałby przejść przez całą stronę, żeby do nich dojść (WCAG 2.1.1).
|
|
783
|
+
*/
|
|
784
|
+
// Refy stabilne (`useCallback`): nowa funkcja przy każdym renderze byłaby wołana od nowa
|
|
785
|
+
// i przy każdej zmianie stanu edytora zabierałaby fokus z powrotem na początek panelu.
|
|
786
|
+
const focusPanelOnMount = useCallback((el) => {
|
|
787
|
+
if (el)
|
|
788
|
+
requestAnimationFrame(() => el.focus());
|
|
789
|
+
}, []);
|
|
790
|
+
const focusSwatchOnMount = useCallback((el) => {
|
|
791
|
+
if (el)
|
|
792
|
+
requestAnimationFrame(() => el.querySelector('.kpt-rich-text__swatch')?.focus());
|
|
793
|
+
}, []);
|
|
794
|
+
const focusGridOnMount = useCallback((el) => {
|
|
795
|
+
if (!el)
|
|
796
|
+
return;
|
|
797
|
+
setGrid((g) => (g.r === 0 ? { r: 1, c: 1 } : g));
|
|
798
|
+
requestAnimationFrame(() => el.focus());
|
|
799
|
+
}, []);
|
|
800
|
+
/** Paleta: strzałki po próbkach, Tab krąży w panelu, Escape zamyka i oddaje fokus narzędziu. */
|
|
801
|
+
const onPaletteKeyDown = (event) => {
|
|
802
|
+
const panel = event.currentTarget;
|
|
803
|
+
if (event.key === 'Escape') {
|
|
804
|
+
event.preventDefault();
|
|
805
|
+
event.stopPropagation();
|
|
806
|
+
setColorOpen(false);
|
|
807
|
+
if (colorKind === 'cellBg')
|
|
808
|
+
focusEditor();
|
|
809
|
+
else
|
|
810
|
+
(colorKind === 'foreColor' ? foreAnchor : backAnchor)?.focus();
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
if (event.key === 'Tab') {
|
|
814
|
+
trapTab(panel, event.nativeEvent);
|
|
815
|
+
return;
|
|
816
|
+
}
|
|
817
|
+
const swatches = [...panel.querySelectorAll('.kpt-rich-text__swatch')];
|
|
818
|
+
const at = swatches.indexOf(document.activeElement);
|
|
819
|
+
if (at === -1)
|
|
820
|
+
return;
|
|
821
|
+
const next = nextRovingIndex(swatches.map(() => false), at, event.key);
|
|
822
|
+
if (next === null || next === at)
|
|
823
|
+
return;
|
|
824
|
+
event.preventDefault();
|
|
825
|
+
swatches[next].focus();
|
|
826
|
+
};
|
|
827
|
+
const paletteContent = (_jsxs("div", { ref: focusSwatchOnMount, className: "kpt-rich-text__palette", role: "group", "aria-label": t(colorKind === 'backColor' ? 'richText.backColor' : 'richText.foreColor'), onMouseDown: (event) => event.preventDefault(), onKeyDown: onPaletteKeyDown, children: [_jsx("div", { className: "kpt-rich-text__swatches", children: SWATCHES.map((swatch) => (_jsx("button", { type: "button", className: "kpt-rich-text__swatch", style: { background: swatch.color }, "aria-label": t(`richText.swatches.${swatch.name}`), onClick: () => applyColor(swatch.color) }, swatch.color))) }), _jsxs("label", { className: "kpt-rich-text__picker", children: [_jsx("span", { children: t('richText.paletteCustom') }), _jsx("input", { type: "color", onInput: (event) => applyColor(event.target.value) })] })] }));
|
|
742
828
|
/**
|
|
743
829
|
* Panel otwarty przy dolnej albo prawej krawędzi okna wychodziłby poza ekran — CDK robił to
|
|
744
830
|
* w Angularze sam, tutaj przesuwamy go po zamontowaniu, gdy już znać jego rozmiar.
|
|
@@ -791,13 +877,118 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
791
877
|
buttons[next].focus();
|
|
792
878
|
};
|
|
793
879
|
const toolButton = (item) => (_jsx("button", { ...rovingProps(item), ref: item === 'link' ? setLinkAnchor : undefined, "aria-haspopup": item === 'link' ? 'dialog' : undefined, "aria-expanded": item === 'link' ? linkOpen : undefined, type: "button", className: cn('kpt-rich-text__tool', isActive(item) && 'is-active'), "aria-label": t(`richText.${item}`), "aria-pressed": pressed(item), title: t(`richText.${item}`), disabled: disabled || !enabled(item), onMouseDown: (event) => event.preventDefault(), onClick: () => exec(item), children: _jsx(KptIcon, { name: ICON[item] }) }, item));
|
|
794
|
-
|
|
795
|
-
|
|
880
|
+
/**
|
|
881
|
+
* Akcje menu tabeli po identyfikatorze. Handlery żyją tutaj, a nie jako domknięcia przekazywane
|
|
882
|
+
* do `menuItem()` — funkcja wołana w renderze nie dostaje wtedy niczego, co czyta refy.
|
|
883
|
+
*/
|
|
884
|
+
const runTableAction = (action) => {
|
|
885
|
+
switch (action) {
|
|
886
|
+
case 'insertLeft': {
|
|
887
|
+
if (ctxCell.current)
|
|
888
|
+
insertColumn(ctxCell.current, 'left');
|
|
889
|
+
afterTableOp();
|
|
890
|
+
break;
|
|
891
|
+
}
|
|
892
|
+
case 'insertRight': {
|
|
893
|
+
if (ctxCell.current)
|
|
894
|
+
insertColumn(ctxCell.current, 'right');
|
|
895
|
+
afterTableOp();
|
|
896
|
+
break;
|
|
897
|
+
}
|
|
898
|
+
case 'headerColumn': {
|
|
899
|
+
if (ctxCell.current)
|
|
900
|
+
toggleHeaderColumn(ctxCell.current);
|
|
901
|
+
ctxCell.current = null; // komórki zostały podmienione
|
|
902
|
+
afterTableOp();
|
|
903
|
+
break;
|
|
904
|
+
}
|
|
905
|
+
case 'deleteColumn': {
|
|
906
|
+
if (ctxCell.current)
|
|
907
|
+
deleteColumn(ctxCell.current);
|
|
908
|
+
afterTableOp();
|
|
909
|
+
break;
|
|
910
|
+
}
|
|
911
|
+
case 'insertAbove': {
|
|
912
|
+
if (ctxCell.current)
|
|
913
|
+
insertRow(ctxCell.current, 'above');
|
|
914
|
+
afterTableOp();
|
|
915
|
+
break;
|
|
916
|
+
}
|
|
917
|
+
case 'insertBelow': {
|
|
918
|
+
if (ctxCell.current)
|
|
919
|
+
insertRow(ctxCell.current, 'below');
|
|
920
|
+
afterTableOp();
|
|
921
|
+
break;
|
|
922
|
+
}
|
|
923
|
+
case 'headerRow': {
|
|
924
|
+
if (ctxCell.current)
|
|
925
|
+
toggleHeaderRow(ctxCell.current);
|
|
926
|
+
ctxCell.current = null;
|
|
927
|
+
afterTableOp();
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
case 'deleteRow': {
|
|
931
|
+
if (ctxCell.current)
|
|
932
|
+
deleteRow(ctxCell.current);
|
|
933
|
+
afterTableOp();
|
|
934
|
+
break;
|
|
935
|
+
}
|
|
936
|
+
case 'cellBackground': {
|
|
937
|
+
setMenuOpen(false);
|
|
938
|
+
setColorKind('cellBg');
|
|
939
|
+
setColorOpen(true);
|
|
940
|
+
break;
|
|
941
|
+
}
|
|
942
|
+
case 'alignLeft': {
|
|
943
|
+
for (const cell of activeCells())
|
|
944
|
+
cell.style.textAlign = 'left';
|
|
945
|
+
afterTableOp();
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
948
|
+
case 'alignCenter': {
|
|
949
|
+
for (const cell of activeCells())
|
|
950
|
+
cell.style.textAlign = 'center';
|
|
951
|
+
afterTableOp();
|
|
952
|
+
break;
|
|
953
|
+
}
|
|
954
|
+
case 'alignRight': {
|
|
955
|
+
for (const cell of activeCells())
|
|
956
|
+
cell.style.textAlign = 'right';
|
|
957
|
+
afterTableOp();
|
|
958
|
+
break;
|
|
959
|
+
}
|
|
960
|
+
case 'mergeCells': {
|
|
961
|
+
mergeCells([...selCells.current]);
|
|
962
|
+
clearCellSelection();
|
|
963
|
+
afterTableOp();
|
|
964
|
+
break;
|
|
965
|
+
}
|
|
966
|
+
case 'splitCell': {
|
|
967
|
+
if (ctxCell.current)
|
|
968
|
+
splitCell(ctxCell.current);
|
|
969
|
+
afterTableOp();
|
|
970
|
+
break;
|
|
971
|
+
}
|
|
972
|
+
case 'border': {
|
|
973
|
+
setMenuOpen(false);
|
|
974
|
+
setBorderOpen(true);
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
977
|
+
case 'deleteTable': {
|
|
978
|
+
ctxCell.current?.closest('table')?.remove();
|
|
979
|
+
afterTableOp();
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
const menuItem = (icon, label, action, extra) => (_jsxs("button", { type: "button", role: "menuitem", tabIndex: -1, className: cn('kpt-rt-menu__item', extra), "aria-disabled": extra === 'is-disabled' || undefined, onClick: () => runTableAction(action), children: [_jsx(KptIcon, { name: icon }), " ", label] }));
|
|
985
|
+
return (_jsxs("div", { className: cn('kpt-rich-text-host', className), ...rest, children: [_jsxs("div", { className: cn('kpt-rich-text', showInvalid && 'kpt-rich-text--invalid', disabledProp && 'kpt-rich-text--disabled'), children: [_jsx("div", { className: "kpt-rich-text__toolbar", role: "toolbar", "aria-label": t('richText.toolbar'), "aria-controls": field.id, onKeyDown: onToolbarKeyDown, children: sections.map((section, index) => (_jsxs("span", { style: { display: 'contents' }, children: [index > 0 ? _jsx("span", { className: "kpt-rich-text__divider", "aria-hidden": "true" }) : null, section.map((item) => {
|
|
796
986
|
if (item === 'heading') {
|
|
797
987
|
return (_jsxs("button", { ref: setStyleAnchor, ...rovingProps(item), type: "button", className: cn('kpt-rich-text__style', styleOpen && 'is-open'), disabled: disabled, "aria-label": t('richText.heading'), "aria-expanded": styleOpen, title: t('richText.heading'), onMouseDown: (event) => event.preventDefault(), onClick: () => {
|
|
798
988
|
if (disabled)
|
|
799
989
|
return;
|
|
800
990
|
saveSelection();
|
|
991
|
+
setStyleActive(Math.max(0, styleOptions.findIndex((o) => o.tag === currentBlock)));
|
|
801
992
|
setStyleOpen(true);
|
|
802
993
|
}, children: [_jsx("span", { children: styleLabel }), _jsx(KptIcon, { name: "chevron-down", className: "kpt-rich-text__style-caret" })] }, item));
|
|
803
994
|
}
|
|
@@ -814,7 +1005,9 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
814
1005
|
return (_jsx("button", { ref: setTableAnchor, ...rovingProps(item), type: "button", className: cn('kpt-rich-text__tool', tableOpen && 'is-active'), "aria-label": t('richText.table'), title: t('richText.table'), disabled: disabled, onMouseDown: (event) => event.preventDefault(), onClick: () => exec(item), children: _jsx(KptIcon, { name: ICON[item] }) }, item));
|
|
815
1006
|
}
|
|
816
1007
|
return toolButton(item);
|
|
817
|
-
})] }, index))) }), sourceView ? (_jsx("textarea", { className: "kpt-rich-text__source", value: current, disabled: disabled, spellCheck: false, "aria-label": t('richText.htmlSource'), onChange: (event) => setCurrent(event.target.value), onBlur: () => onTouch?.() })) : (_jsx("div", { ref: editorRef, className: "kpt-rich-text__editor", contentEditable: !disabled,
|
|
1008
|
+
})] }, index))) }), sourceView ? (_jsx("textarea", { className: "kpt-rich-text__source", value: current, disabled: disabled, spellCheck: false, "aria-label": t('richText.htmlSource'), onChange: (event) => setCurrent(event.target.value), onBlur: () => onTouch?.() })) : (_jsx("div", { ref: editorRef, className: "kpt-rich-text__editor", contentEditable: !disabled,
|
|
1009
|
+
// Wyłączony edytor (contentEditable=false) wypada z kolejności Tab jak wyłączone pole.
|
|
1010
|
+
tabIndex: disabled ? -1 : 0, "aria-readonly": readOnly || undefined, suppressContentEditableWarning: true, "data-placeholder": placeholder, "aria-invalid": showInvalid || undefined, role: "textbox", "aria-multiline": "true", id: field.id, "aria-required": required || undefined, "aria-label": ariaLabel ?? undefined, "aria-labelledby": ariaLabel ? undefined : field.labelledBy, "aria-describedby": field.describedBy, onInput: () => {
|
|
818
1011
|
pushValue();
|
|
819
1012
|
syncMention();
|
|
820
1013
|
}, onKeyDown: onKeyDown, onPaste: onPaste, onContextMenu: onContextMenu, onMouseDown: onEditorMouseDown, onMouseMove: onEditorMouseMove, onBlur: () => onTouch?.() }))] }), mentionOpen && container
|
|
@@ -844,90 +1037,42 @@ export function KptRichText({ value, defaultValue = '', onValueChange, toolbar =
|
|
|
844
1037
|
// Panel jest niewidoczny do pierwszego pomiaru — fokus po klatce.
|
|
845
1038
|
if (el)
|
|
846
1039
|
requestAnimationFrame(() => el.focus());
|
|
847
|
-
}, className: "kpt-rt-link__input", id: `${field.id}-link`, type: "url", inputMode: "url", placeholder: "https://", value: linkDraft, onChange: (event) => setLinkDraft(event.target.value) }), _jsx("button", { type: "submit", className: "kpt-rt-link__apply", children: t('richText.linkApply') })] }) }), _jsx(KptOverlay, { open: styleOpen, anchor: styleAnchor, onClose: () => setStyleOpen(false), offset: 4, children: _jsx("ul", { className: "kpt-rich-text__style-panel", role: "listbox",
|
|
1040
|
+
}, className: "kpt-rt-link__input", id: `${field.id}-link`, type: "url", inputMode: "url", placeholder: "https://", value: linkDraft, onChange: (event) => setLinkDraft(event.target.value) }), _jsx("button", { type: "submit", className: "kpt-rt-link__apply", children: t('richText.linkApply') })] }) }), _jsx(KptOverlay, { open: styleOpen, anchor: styleAnchor, onClose: () => setStyleOpen(false), offset: 4, children: _jsx("ul", { ref: focusPanelOnMount, className: "kpt-rich-text__style-panel", role: "listbox", tabIndex: -1, "aria-label": t('richText.heading'), "aria-activedescendant": `${field.id}-style-${styleActive}`, onKeyDown: (event) => {
|
|
1041
|
+
const count = styleOptions.length;
|
|
1042
|
+
if (event.key === 'ArrowDown')
|
|
1043
|
+
setStyleActive((i) => (i + 1) % count);
|
|
1044
|
+
else if (event.key === 'ArrowUp')
|
|
1045
|
+
setStyleActive((i) => (i - 1 + count) % count);
|
|
1046
|
+
else if (event.key === 'Home')
|
|
1047
|
+
setStyleActive(0);
|
|
1048
|
+
else if (event.key === 'End')
|
|
1049
|
+
setStyleActive(count - 1);
|
|
1050
|
+
else if (event.key === 'Enter' || event.key === ' ')
|
|
1051
|
+
pickStyle(styleOptions[styleActive].tag);
|
|
1052
|
+
else if (event.key === 'Escape' || event.key === 'Tab') {
|
|
848
1053
|
setStyleOpen(false);
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
1054
|
+
styleAnchor?.focus();
|
|
1055
|
+
}
|
|
1056
|
+
else
|
|
1057
|
+
return;
|
|
1058
|
+
event.preventDefault();
|
|
1059
|
+
event.stopPropagation();
|
|
1060
|
+
}, children: styleOptions.map((option, index) => (_jsx("li", { id: `${field.id}-style-${index}`, className: cn(`kpt-rich-text__style-opt kpt-rich-text__style-opt--${option.tag}`, currentBlock === option.tag && 'is-selected', styleActive === index && 'is-active'), role: "option", "aria-selected": currentBlock === option.tag, onClick: () => pickStyle(option.tag), children: option.label }, option.tag))) }) }), _jsx(KptOverlay, { open: colorOpen && colorKind === 'foreColor', anchor: foreAnchor, onClose: () => setColorOpen(false), offset: 4, children: paletteContent }), _jsx(KptOverlay, { open: colorOpen && colorKind === 'backColor', anchor: backAnchor, onClose: () => setColorOpen(false), offset: 4, children: paletteContent }), _jsx(KptOverlay, { open: tableOpen, anchor: tableAnchor, onClose: () => {
|
|
855
1061
|
setTableOpen(false);
|
|
856
1062
|
setGrid({ r: 0, c: 0 });
|
|
857
|
-
}, offset: 4, children: _jsxs("div", { className: "kpt-rt-grid-pop", onMouseDown: (event) => event.preventDefault(), children: [_jsx("div", {
|
|
1063
|
+
}, offset: 4, children: _jsxs("div", { className: "kpt-rt-grid-pop", onMouseDown: (event) => event.preventDefault(), children: [_jsx("div", { ref: focusGridOnMount, className: "kpt-rt-grid", role: "group",
|
|
1064
|
+
// Jeden przystanek ze strzałkami (rozmiar tabeli) — grupa z własną obsługą klawiatury.
|
|
1065
|
+
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex -- patrz wyżej
|
|
1066
|
+
tabIndex: 0, "aria-label": t('richText.table'), "aria-describedby": `${field.id}-grid-size`, "aria-keyshortcuts": "ArrowUp ArrowDown ArrowLeft ArrowRight Enter Escape", onKeyDown: onGridKeyDown, onMouseLeave: () => setGrid({ r: 0, c: 0 }), children: GRID_ROWS.map((r) => (_jsx("div", { className: "kpt-rt-grid__row", children: GRID_COLS.map((c) => (_jsx("span", { className: cn('kpt-rt-grid__cell', r <= grid.r && c <= grid.c && 'is-on'), onMouseEnter: () => setGrid({ r, c }), onClick: () => insertTableAt(r, c) }, c))) }, r))) }), _jsxs("div", { className: "kpt-rt-grid__label", id: `${field.id}-grid-size`, "aria-live": "polite", children: [grid.r, " \u00D7 ", grid.c] })] }) }), menuOpen
|
|
858
1067
|
? pointPanel(_jsxs("div", { ref: (el) => {
|
|
859
1068
|
if (el && menuFromKeyboard.current) {
|
|
860
1069
|
menuFromKeyboard.current = false;
|
|
861
1070
|
requestAnimationFrame(() => focusMenuEdge(el, 'first'));
|
|
862
1071
|
}
|
|
863
|
-
}, className: "kpt-rt-menu", role: "menu", "aria-label": t('richText.table'), onContextMenu: (event) => event.preventDefault(), onKeyDown: onMenuKeyDown, children: [_jsx("div", { className: "kpt-rt-menu__group", "aria-hidden": "true", children: t('richText.menu.column') }), menuItem('plus', t('richText.menu.insertLeft'), () =>
|
|
864
|
-
if (ctxCell.current)
|
|
865
|
-
insertColumn(ctxCell.current, 'left');
|
|
866
|
-
afterTableOp();
|
|
867
|
-
}), menuItem('plus', t('richText.menu.insertRight'), () => {
|
|
868
|
-
if (ctxCell.current)
|
|
869
|
-
insertColumn(ctxCell.current, 'right');
|
|
870
|
-
afterTableOp();
|
|
871
|
-
}), menuItem('table', t('richText.menu.headerColumn'), () => {
|
|
872
|
-
if (ctxCell.current)
|
|
873
|
-
toggleHeaderColumn(ctxCell.current);
|
|
874
|
-
ctxCell.current = null; // komórki zostały podmienione
|
|
875
|
-
afterTableOp();
|
|
876
|
-
}), menuItem('trash', t('richText.menu.deleteColumn'), () => {
|
|
877
|
-
if (ctxCell.current)
|
|
878
|
-
deleteColumn(ctxCell.current);
|
|
879
|
-
afterTableOp();
|
|
880
|
-
}), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), _jsx("div", { className: "kpt-rt-menu__group", "aria-hidden": "true", children: t('richText.menu.row') }), menuItem('plus', t('richText.menu.insertAbove'), () => {
|
|
881
|
-
if (ctxCell.current)
|
|
882
|
-
insertRow(ctxCell.current, 'above');
|
|
883
|
-
afterTableOp();
|
|
884
|
-
}), menuItem('plus', t('richText.menu.insertBelow'), () => {
|
|
885
|
-
if (ctxCell.current)
|
|
886
|
-
insertRow(ctxCell.current, 'below');
|
|
887
|
-
afterTableOp();
|
|
888
|
-
}), menuItem('table', t('richText.menu.headerRow'), () => {
|
|
889
|
-
if (ctxCell.current)
|
|
890
|
-
toggleHeaderRow(ctxCell.current);
|
|
891
|
-
ctxCell.current = null;
|
|
892
|
-
afterTableOp();
|
|
893
|
-
}), menuItem('trash', t('richText.menu.deleteRow'), () => {
|
|
894
|
-
if (ctxCell.current)
|
|
895
|
-
deleteRow(ctxCell.current);
|
|
896
|
-
afterTableOp();
|
|
897
|
-
}), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), _jsx("div", { className: "kpt-rt-menu__group", "aria-hidden": "true", children: t('richText.menu.cell') }), menuItem('palette', t('richText.menu.cellBackground'), () => {
|
|
898
|
-
setMenuOpen(false);
|
|
899
|
-
setColorKind('cellBg');
|
|
900
|
-
setColorOpen(true);
|
|
901
|
-
}), menuItem('align-left', t('richText.menu.alignLeft'), () => {
|
|
902
|
-
for (const cell of activeCells())
|
|
903
|
-
cell.style.textAlign = 'left';
|
|
904
|
-
afterTableOp();
|
|
905
|
-
}), menuItem('align-center', t('richText.menu.alignCenter'), () => {
|
|
906
|
-
for (const cell of activeCells())
|
|
907
|
-
cell.style.textAlign = 'center';
|
|
908
|
-
afterTableOp();
|
|
909
|
-
}), menuItem('align-right', t('richText.menu.alignRight'), () => {
|
|
910
|
-
for (const cell of activeCells())
|
|
911
|
-
cell.style.textAlign = 'right';
|
|
912
|
-
afterTableOp();
|
|
913
|
-
}), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), menuItem('table', t('richText.menu.mergeCells'), () => {
|
|
914
|
-
mergeCells([...selCells.current]);
|
|
915
|
-
clearCellSelection();
|
|
916
|
-
afterTableOp();
|
|
917
|
-
}, selCount < 2 ? 'is-disabled' : undefined), menuItem('grip-vertical', t('richText.menu.splitCell'), () => {
|
|
918
|
-
if (ctxCell.current)
|
|
919
|
-
splitCell(ctxCell.current);
|
|
920
|
-
afterTableOp();
|
|
921
|
-
}, canSplitCtx.current ? undefined : 'is-disabled'), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), menuItem('table', t('richText.menu.border'), () => {
|
|
922
|
-
setMenuOpen(false);
|
|
923
|
-
setBorderOpen(true);
|
|
924
|
-
}), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), menuItem('trash', t('richText.menu.deleteTable'), () => {
|
|
925
|
-
ctxCell.current?.closest('table')?.remove();
|
|
926
|
-
afterTableOp();
|
|
927
|
-
}, 'kpt-rt-menu__item--danger')] }), () => setMenuOpen(false))
|
|
1072
|
+
}, className: "kpt-rt-menu", role: "menu", tabIndex: -1, "aria-label": t('richText.table'), onContextMenu: (event) => event.preventDefault(), onKeyDown: onMenuKeyDown, children: [_jsx("div", { className: "kpt-rt-menu__group", "aria-hidden": "true", children: t('richText.menu.column') }), menuItem('plus', t('richText.menu.insertLeft'), 'insertLeft'), menuItem('plus', t('richText.menu.insertRight'), 'insertRight'), menuItem('table', t('richText.menu.headerColumn'), 'headerColumn'), menuItem('trash', t('richText.menu.deleteColumn'), 'deleteColumn'), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), _jsx("div", { className: "kpt-rt-menu__group", "aria-hidden": "true", children: t('richText.menu.row') }), menuItem('plus', t('richText.menu.insertAbove'), 'insertAbove'), menuItem('plus', t('richText.menu.insertBelow'), 'insertBelow'), menuItem('table', t('richText.menu.headerRow'), 'headerRow'), menuItem('trash', t('richText.menu.deleteRow'), 'deleteRow'), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), _jsx("div", { className: "kpt-rt-menu__group", "aria-hidden": "true", children: t('richText.menu.cell') }), menuItem('palette', t('richText.menu.cellBackground'), 'cellBackground'), menuItem('align-left', t('richText.menu.alignLeft'), 'alignLeft'), menuItem('align-center', t('richText.menu.alignCenter'), 'alignCenter'), menuItem('align-right', t('richText.menu.alignRight'), 'alignRight'), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), menuItem('table', t('richText.menu.mergeCells'), 'mergeCells', selCount < 2 ? 'is-disabled' : undefined), menuItem('grip-vertical', t('richText.menu.splitCell'), 'splitCell', canSplitCtx ? undefined : 'is-disabled'), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), menuItem('table', t('richText.menu.border'), 'border'), _jsx("div", { className: "kpt-rt-menu__sep", role: "separator" }), menuItem('trash', t('richText.menu.deleteTable'), 'deleteTable', 'kpt-rt-menu__item--danger')] }), () => setMenuOpen(false))
|
|
928
1073
|
: null, borderOpen
|
|
929
1074
|
? pointPanel(_jsxs("div", { className: "kpt-rt-border", onMouseDown: (event) => event.preventDefault(), children: [_jsxs("div", { className: "kpt-rt-border__seg", children: [_jsx("button", { type: "button", className: cn(borderTarget === 'table' && 'is-active'), onClick: () => setBorderTarget('table'), children: t('richText.border.table') }), _jsx("button", { type: "button", className: cn(borderTarget === 'cell' && 'is-active'), onClick: () => setBorderTarget('cell'), children: t('richText.border.cell') })] }), _jsxs("div", { className: "kpt-rt-border__widths", children: [_jsx("button", { type: "button", onClick: () => setBorderWidth('none'), children: t('richText.border.none') }), _jsx("button", { type: "button", onClick: () => setBorderWidth('thin'), children: t('richText.border.thin') }), _jsx("button", { type: "button", onClick: () => setBorderWidth('medium'), children: t('richText.border.medium') }), _jsx("button", { type: "button", onClick: () => setBorderWidth('thick'), children: t('richText.border.thick') })] }), _jsx("div", { className: "kpt-rich-text__swatches", children: SWATCHES.map((swatch) => (_jsx("button", { type: "button", className: "kpt-rich-text__swatch", style: { background: swatch.color }, "aria-label": t(`richText.swatches.${swatch.name}`), onClick: () => setBorderColor(swatch.color) }, swatch.color))) }), _jsxs("label", { className: "kpt-rich-text__picker", children: [_jsx("span", { children: t('richText.border.customColor') }), _jsx("input", { type: "color", onInput: (event) => setBorderColor(event.target.value) })] })] }), () => setBorderOpen(false))
|
|
930
1075
|
: null, colorOpen && colorKind === 'cellBg'
|
|
931
|
-
? pointPanel(
|
|
1076
|
+
? pointPanel(paletteContent, () => setColorOpen(false))
|
|
932
1077
|
: null] }));
|
|
933
1078
|
}
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Czyści HTML i mówi, czy coś usunął. `changed: false` znaczy, że treść była czysta — wtedy
|
|
3
|
+
* wołający nie musi nadpisywać wartości modelu (serializacja DOM potrafi zmienić zapis, np.
|
|
4
|
+
* cudzysłowy, bez zmiany treści, a taka różnica nie może brudzić formularza).
|
|
5
|
+
*/
|
|
6
|
+
export declare function sanitizeHtmlReport(html: string): {
|
|
7
|
+
html: string;
|
|
8
|
+
changed: boolean;
|
|
9
|
+
};
|
|
1
10
|
/**
|
|
2
11
|
* Czyści HTML wchodzący do edytora. Dotyczy **każdego** zapisu do DOM edytora, nie tylko
|
|
3
12
|
* wklejania: `value` z aplikacji też bywa niezaufane (baza, CMS, inny użytkownik).
|