@konce-pt/react 0.11.0 → 0.11.2
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.
|
@@ -10,7 +10,7 @@ export interface KptButtonGroupProps<T> extends Omit<ComponentPropsWithRef<'div'
|
|
|
10
10
|
disabled?: boolean;
|
|
11
11
|
/** Wywoływane po wyborze — moment, w którym kontrolka staje się dotknięta. */
|
|
12
12
|
onTouch?: () => void;
|
|
13
|
-
/** Chowa etykiety — zostaje sama ikona, a `label` zasila `aria-label` i `
|
|
13
|
+
/** Chowa etykiety — zostaje sama ikona, a `label` zasila `aria-label` i dymek `KptTooltip`. */
|
|
14
14
|
iconOnly?: boolean;
|
|
15
15
|
/** Propsy wrappera hosta (`.kpt-button-group-host`). */
|
|
16
16
|
hostProps?: KptHostProps<'span'>;
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from "../internal/cn.js";
|
|
3
3
|
import { useControllableState } from "../internal/use-controllable-state.js";
|
|
4
4
|
import { KptIcon } from "../icon/icon.js";
|
|
5
|
+
import { KptTooltip } from "../tooltip/tooltip.js";
|
|
5
6
|
/**
|
|
6
7
|
* Segmentowana grupa przycisków (toggle) — pojedynczy wybór z opcji.
|
|
7
8
|
*
|
|
@@ -30,6 +31,6 @@ export function KptButtonGroup({ options = [], value, defaultValue, onValueChang
|
|
|
30
31
|
};
|
|
31
32
|
return (_jsx("span", { className: cn('kpt-button-group-host', hostClassName), ...hostRest, children: _jsx("div", { className: cn('kpt-button-group', className), role: "group", "data-size": size, "data-icon-only": iconOnly ? '' : undefined, ...rest, children: options.map((option) => {
|
|
32
33
|
const active = option.value === current;
|
|
33
|
-
return (_jsxs("button", { type: "button", className: cn('kpt-button-group__item', active && 'is-active'), disabled: disabled || option.disabled, "aria-pressed": active, "aria-label": iconOnly ? option.label : undefined,
|
|
34
|
+
return (_jsx(KptTooltip, { text: iconOnly ? option.label : '', children: _jsxs("button", { type: "button", className: cn('kpt-button-group__item', active && 'is-active'), disabled: disabled || option.disabled, "aria-pressed": active, "aria-label": iconOnly ? option.label : undefined, onClick: () => select(option), children: [option.icon ? _jsx(KptIcon, { className: "kpt-button-group__icon", name: option.icon }) : null, iconOnly ? null : _jsx("span", { className: "kpt-button-group__label", children: option.label })] }) }, String(option.value)));
|
|
34
35
|
}) }) }));
|
|
35
36
|
}
|
package/dist/tooltip/tooltip.js
CHANGED
|
@@ -5,6 +5,63 @@ import { composeRefs } from "../internal/compose-refs.js";
|
|
|
5
5
|
const FOCUSABLE = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])';
|
|
6
6
|
/** Ile czasu ma wskaźnik na przejście z elementu na dymek, zanim ten zniknie (WCAG 1.4.13). */
|
|
7
7
|
const HIDE_DELAY_MS = 120;
|
|
8
|
+
/** Strona przeciwna i dwie boczne — kolejność prób, gdy zadana strona się nie nadaje. */
|
|
9
|
+
const FALLBACKS = {
|
|
10
|
+
top: ['top', 'bottom', 'right', 'left'],
|
|
11
|
+
bottom: ['bottom', 'top', 'right', 'left'],
|
|
12
|
+
left: ['left', 'right', 'top', 'bottom'],
|
|
13
|
+
right: ['right', 'left', 'top', 'bottom'],
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Ustawia dymek przy hoście, na pierwszej stronie z `FALLBACKS`, która się nadaje: dymek mieści się
|
|
17
|
+
* w oknie, a krawędź hosta od tej strony nie jest niczym przykryta (przyklejony nagłówek, menu, panel
|
|
18
|
+
* — sprawdzane `elementFromPoint` tuż przy krawędzi). Bez tego dymek przycisku wsuniętego pod
|
|
19
|
+
* nagłówek wyskakiwał nad nagłówkiem, odcięty od tego, co opisuje. Gdy żadna strona się nie nadaje,
|
|
20
|
+
* zostaje zadana. Na koniec dymek jest dociśnięty do okna z marginesem 4 px.
|
|
21
|
+
* Bliźniak tej funkcji żyje w drugim porcie — zmiany w obu naraz.
|
|
22
|
+
*/
|
|
23
|
+
function placeTooltip(host, tip, preferred) {
|
|
24
|
+
const r = host.getBoundingClientRect();
|
|
25
|
+
const t = tip.getBoundingClientRect();
|
|
26
|
+
const gap = 8;
|
|
27
|
+
const margin = 4;
|
|
28
|
+
const vw = document.documentElement.clientWidth;
|
|
29
|
+
const vh = document.documentElement.clientHeight;
|
|
30
|
+
const at = (side) => {
|
|
31
|
+
switch (side) {
|
|
32
|
+
case 'bottom':
|
|
33
|
+
return { top: r.bottom + gap, left: r.left + r.width / 2 - t.width / 2 };
|
|
34
|
+
case 'left':
|
|
35
|
+
return { top: r.top + r.height / 2 - t.height / 2, left: r.left - t.width - gap };
|
|
36
|
+
case 'right':
|
|
37
|
+
return { top: r.top + r.height / 2 - t.height / 2, left: r.right + gap };
|
|
38
|
+
default:
|
|
39
|
+
return { top: r.top - t.height - gap, left: r.left + r.width / 2 - t.width / 2 };
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
const fits = (side) => {
|
|
43
|
+
const { top, left } = at(side);
|
|
44
|
+
// Po osi poprzecznej dymek i tak zostanie dociśnięty do okna — liczy się tylko oś strony.
|
|
45
|
+
return side === 'top' || side === 'bottom'
|
|
46
|
+
? top >= margin && top + t.height <= vh - margin
|
|
47
|
+
: left >= margin && left + t.width <= vw - margin;
|
|
48
|
+
};
|
|
49
|
+
// Punkt 2 px w głąb hosta przy krawędzi danej strony; widoczny, gdy na wierzchu jest host, jego
|
|
50
|
+
// potomek albo sam dymek (stoi jeszcze w poprzednim miejscu).
|
|
51
|
+
const exposed = (side) => {
|
|
52
|
+
const x = side === 'left' ? r.left + 2 : side === 'right' ? r.right - 2 : r.left + r.width / 2;
|
|
53
|
+
const y = side === 'top' ? r.top + 2 : side === 'bottom' ? r.bottom - 2 : r.top + r.height / 2;
|
|
54
|
+
if (x < 0 || y < 0 || x >= vw || y >= vh)
|
|
55
|
+
return false;
|
|
56
|
+
const hit = document.elementFromPoint(x, y);
|
|
57
|
+
return !hit || host.contains(hit) || tip.contains(hit);
|
|
58
|
+
};
|
|
59
|
+
const side = FALLBACKS[preferred].find((s) => fits(s) && exposed(s)) ?? preferred;
|
|
60
|
+
const { top, left } = at(side);
|
|
61
|
+
tip.dataset['side'] = side;
|
|
62
|
+
tip.style.top = `${Math.min(Math.max(margin, top), Math.max(margin, vh - t.height - margin))}px`;
|
|
63
|
+
tip.style.left = `${Math.min(Math.max(margin, left), Math.max(margin, vw - t.width - margin))}px`;
|
|
64
|
+
}
|
|
8
65
|
/**
|
|
9
66
|
* Dymek podpowiedzi pokazywany na hover i focus. Lekki — element dodawany do `body`
|
|
10
67
|
* i pozycjonowany względem dziecka.
|
|
@@ -60,30 +117,7 @@ export function KptTooltip({ text, position = 'top', onlyWhenTruncated = false,
|
|
|
60
117
|
const host = hostRef.current;
|
|
61
118
|
if (!tip || !host)
|
|
62
119
|
return;
|
|
63
|
-
|
|
64
|
-
const t = tip.getBoundingClientRect();
|
|
65
|
-
const gap = 8;
|
|
66
|
-
let top;
|
|
67
|
-
let left;
|
|
68
|
-
switch (position) {
|
|
69
|
-
case 'bottom':
|
|
70
|
-
top = r.bottom + gap;
|
|
71
|
-
left = r.left + r.width / 2 - t.width / 2;
|
|
72
|
-
break;
|
|
73
|
-
case 'left':
|
|
74
|
-
top = r.top + r.height / 2 - t.height / 2;
|
|
75
|
-
left = r.left - t.width - gap;
|
|
76
|
-
break;
|
|
77
|
-
case 'right':
|
|
78
|
-
top = r.top + r.height / 2 - t.height / 2;
|
|
79
|
-
left = r.right + gap;
|
|
80
|
-
break;
|
|
81
|
-
default:
|
|
82
|
-
top = r.top - t.height - gap;
|
|
83
|
-
left = r.left + r.width / 2 - t.width / 2;
|
|
84
|
-
}
|
|
85
|
-
tip.style.top = `${Math.max(4, top)}px`;
|
|
86
|
-
tip.style.left = `${Math.max(4, left)}px`;
|
|
120
|
+
placeTooltip(host, tip, position);
|
|
87
121
|
}, [position]);
|
|
88
122
|
const onKeyDown = useCallback((event) => {
|
|
89
123
|
if (event.key === 'Escape')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konce-pt/react",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "Open-source React 19 component library on the Koncept UI design system — the same kpt-* CSS layer and --kpt-* tokens as the Angular port. Zero runtime dependencies.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "konce.pt",
|
|
@@ -65,17 +65,17 @@
|
|
|
65
65
|
"leaflet": "^1.9.0"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@konce-pt/
|
|
69
|
-
"@konce-pt/
|
|
70
|
-
"@konce-pt/
|
|
71
|
-
"@konce-pt/
|
|
72
|
-
"@konce-pt/
|
|
73
|
-
"@konce-pt/
|
|
74
|
-
"@konce-pt/roadmap": "0.11.
|
|
75
|
-
"@konce-pt/tokens": "0.11.
|
|
76
|
-
"@konce-pt/
|
|
77
|
-
"@konce-pt/
|
|
78
|
-
"@konce-pt/
|
|
68
|
+
"@konce-pt/chat": "0.11.2",
|
|
69
|
+
"@konce-pt/backdrop": "0.11.2",
|
|
70
|
+
"@konce-pt/chart": "0.11.2",
|
|
71
|
+
"@konce-pt/i18n": "0.11.2",
|
|
72
|
+
"@konce-pt/mention": "0.11.2",
|
|
73
|
+
"@konce-pt/table": "0.11.2",
|
|
74
|
+
"@konce-pt/roadmap": "0.11.2",
|
|
75
|
+
"@konce-pt/tokens": "0.11.2",
|
|
76
|
+
"@konce-pt/map": "0.11.2",
|
|
77
|
+
"@konce-pt/datetime": "0.11.2",
|
|
78
|
+
"@konce-pt/icons": "0.11.2"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@types/react": "^19.2.0",
|