@rackbops/ui-react 0.2.42 → 0.2.44
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/dist/Tabs.js +3 -3
- package/dist/Tabstrip.d.ts +1 -1
- package/dist/Tabstrip.js +14 -2
- package/dist/feedback.d.ts +4 -0
- package/dist/feedback.js +1 -1
- package/dist/form.js +2 -7
- package/package.json +7 -4
package/dist/Tabs.js
CHANGED
|
@@ -47,10 +47,10 @@ export const Tabs = forwardRef(function Tabs({ items, defaultId, activeId: activ
|
|
|
47
47
|
const selected = t.id === activeId;
|
|
48
48
|
return (_jsx("button", { ref: (el) => {
|
|
49
49
|
tabRefs.current[idx] = el;
|
|
50
|
-
}, type: "button", role: "tab", id: `${base}-tab-${
|
|
51
|
-
}) }), items.map((t) => {
|
|
50
|
+
}, type: "button", role: "tab", id: `${base}-tab-${idx}`, "aria-selected": selected, "aria-controls": `${base}-panel-${idx}`, tabIndex: selected ? 0 : -1, className: cx("rb-tab", selected && "rb-tab--active"), onClick: () => select(t.id), onKeyDown: onKeyDown, children: t.label }, t.id));
|
|
51
|
+
}) }), items.map((t, idx) => {
|
|
52
52
|
const selected = t.id === activeId;
|
|
53
|
-
return (_jsx("div", { className: "rb-tabpanel", role: "tabpanel", id: `${base}-panel-${
|
|
53
|
+
return (_jsx("div", { className: "rb-tabpanel", role: "tabpanel", id: `${base}-panel-${idx}`, "aria-labelledby": `${base}-tab-${idx}`, hidden: !selected, tabIndex: 0, children: t.content }, t.id));
|
|
54
54
|
})] }));
|
|
55
55
|
});
|
|
56
56
|
Tabs.displayName = "Tabs";
|
package/dist/Tabstrip.d.ts
CHANGED
package/dist/Tabstrip.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useRef } from "react";
|
|
2
3
|
import { cx } from "./cx.js";
|
|
3
4
|
/**
|
|
4
5
|
* A controlled tab strip on the `rb-tabstrip` contract -- the design system's existing
|
|
@@ -18,8 +19,15 @@ import { cx } from "./cx.js";
|
|
|
18
19
|
* relationship that does not exist would mislead a screen-reader user.
|
|
19
20
|
*/
|
|
20
21
|
export function Tabstrip({ tabs, selected, onSelect, label }) {
|
|
22
|
+
const tabRefs = useRef([]);
|
|
21
23
|
function onKeyDown(event) {
|
|
22
|
-
|
|
24
|
+
// Index from the tab that received the key when there is one: a controlled parent that
|
|
25
|
+
// commits `selected` late (a router transition, a debounce) would otherwise leave `selected`
|
|
26
|
+
// stale between presses, and focus (which has already moved) and the next "from" index
|
|
27
|
+
// would disagree. Fall back to `selected` when the event came from the strip itself.
|
|
28
|
+
const focused = event.target.closest?.('[role="tab"]');
|
|
29
|
+
const focusedIndex = focused ? tabRefs.current.indexOf(focused) : -1;
|
|
30
|
+
const index = focusedIndex !== -1 ? focusedIndex : tabs.findIndex((t) => t.id === selected);
|
|
23
31
|
if (index === -1) {
|
|
24
32
|
return;
|
|
25
33
|
}
|
|
@@ -44,6 +52,8 @@ export function Tabstrip({ tabs, selected, onSelect, label }) {
|
|
|
44
52
|
if (target) {
|
|
45
53
|
event.preventDefault();
|
|
46
54
|
onSelect(target.id);
|
|
55
|
+
// Roving tabindex: focus follows the selection, so Enter/Space acts on the new tab.
|
|
56
|
+
tabRefs.current[next]?.focus();
|
|
47
57
|
}
|
|
48
58
|
}
|
|
49
59
|
// When `selected` matches no tab (a caller mid-reload passing a stale id), every tab would
|
|
@@ -54,7 +64,9 @@ export function Tabstrip({ tabs, selected, onSelect, label }) {
|
|
|
54
64
|
return (_jsx("div", { role: "tablist", "aria-label": label, className: "rb-tabstrip", onKeyDown: onKeyDown, children: tabs.map((tab, index) => {
|
|
55
65
|
const isSelected = tab.id === selected;
|
|
56
66
|
const isTabStop = hasSelected ? isSelected : index === 0;
|
|
57
|
-
return (_jsxs("button", {
|
|
67
|
+
return (_jsxs("button", { ref: (el) => {
|
|
68
|
+
tabRefs.current[index] = el;
|
|
69
|
+
}, type: "button", role: "tab", "aria-selected": isSelected,
|
|
58
70
|
// Roving tabIndex: exactly one tab is reachable by Tab, so the whole strip is one
|
|
59
71
|
// stop and the arrow keys above do the moving within it.
|
|
60
72
|
tabIndex: isTabStop ? 0 : -1, className: cx("rb-tabstrip__tab", isSelected && "rb-tabstrip__tab--active"), onClick: () => onSelect(tab.id), children: [tab.label, tab.badge !== undefined && _jsx("span", { className: "rb-tabstrip__badge", children: tab.badge })] }, tab.id));
|
package/dist/feedback.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { type HTMLAttributes, type ProgressHTMLAttributes, type ReactNode, type RefAttributes } from "react";
|
|
2
|
+
/** A forwardRef DOM wrapper that adds a base rb-* class and any fixed static attributes. */
|
|
3
|
+
export declare function styled<E extends HTMLElement, P extends {
|
|
4
|
+
className?: string;
|
|
5
|
+
}>(tag: string, cls: string, attrs?: Record<string, unknown>): import("react").ForwardRefExoticComponent<import("react").PropsWithoutRef<P> & RefAttributes<E>>;
|
|
2
6
|
export type SemanticVariant = "info" | "success" | "warning" | "danger";
|
|
3
7
|
export interface BadgeProps extends HTMLAttributes<HTMLSpanElement>, RefAttributes<HTMLSpanElement> {
|
|
4
8
|
variant?: SemanticVariant;
|
package/dist/feedback.js
CHANGED
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { createElement, forwardRef, } from "react";
|
|
3
3
|
import { cx } from "./cx.js";
|
|
4
4
|
/** A forwardRef DOM wrapper that adds a base rb-* class and any fixed static attributes. */
|
|
5
|
-
function styled(tag, cls, attrs = {}) {
|
|
5
|
+
export function styled(tag, cls, attrs = {}) {
|
|
6
6
|
return forwardRef(function Styled({ className, ...rest }, ref) {
|
|
7
7
|
return createElement(tag, { ref, ...attrs, className: cx(cls, className), ...rest });
|
|
8
8
|
});
|
package/dist/form.js
CHANGED
|
@@ -1,12 +1,7 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { forwardRef, } from "react";
|
|
3
3
|
import { cx } from "./cx.js";
|
|
4
|
-
|
|
5
|
-
function styled(tag, cls) {
|
|
6
|
-
return forwardRef(function Styled({ className, ...rest }, ref) {
|
|
7
|
-
return createElement(tag, { ref, className: cx(cls, className), ...rest });
|
|
8
|
-
});
|
|
9
|
-
}
|
|
4
|
+
import { styled } from "./feedback.js";
|
|
10
5
|
export const Input = styled("input", "rb-input");
|
|
11
6
|
Input.displayName = "Input";
|
|
12
7
|
export const Textarea = styled("textarea", "rb-textarea");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rackbops/ui-react",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.44",
|
|
4
4
|
"description": "React components styled by @rackbops/styles rackbops themes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"access": "public"
|
|
13
13
|
},
|
|
14
14
|
"type": "module",
|
|
15
|
+
"sideEffects": false,
|
|
15
16
|
"files": [
|
|
16
17
|
"dist",
|
|
17
18
|
"LICENSE",
|
|
@@ -26,17 +27,19 @@
|
|
|
26
27
|
}
|
|
27
28
|
},
|
|
28
29
|
"peerDependencies": {
|
|
30
|
+
"@rackbops/styles": "^0.2.44",
|
|
29
31
|
"react": ">=18"
|
|
30
32
|
},
|
|
31
33
|
"devDependencies": {
|
|
34
|
+
"@rackbops/styles": "^0.2.44",
|
|
32
35
|
"@types/jsdom": "^30.0.0",
|
|
33
|
-
"@types/node": "^26.
|
|
36
|
+
"@types/node": "^26.6.3",
|
|
34
37
|
"@types/react": "^19.0.0",
|
|
35
38
|
"@types/react-dom": "^19.0.0",
|
|
36
|
-
"jsdom": "^30.
|
|
39
|
+
"jsdom": "^30.1.1",
|
|
37
40
|
"react": "^19.0.0",
|
|
38
41
|
"react-dom": "^19.0.0",
|
|
39
|
-
"tsx": "^4.
|
|
42
|
+
"tsx": "^4.23.15",
|
|
40
43
|
"typescript": "^7.0.0"
|
|
41
44
|
},
|
|
42
45
|
"scripts": {
|