@diwauhris/ui 1.0.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 +75 -0
- package/lib/assets/ui.css +154 -0
- package/lib/index.cjs +183 -0
- package/lib/index.mjs +65 -0
- package/lib/index10.cjs +33 -0
- package/lib/index10.cjs.map +1 -0
- package/lib/index10.mjs +33 -0
- package/lib/index10.mjs.map +1 -0
- package/lib/index11.cjs +16 -0
- package/lib/index11.cjs.map +1 -0
- package/lib/index11.mjs +16 -0
- package/lib/index11.mjs.map +1 -0
- package/lib/index12.cjs +16 -0
- package/lib/index12.cjs.map +1 -0
- package/lib/index12.mjs +15 -0
- package/lib/index12.mjs.map +1 -0
- package/lib/index13.cjs +57 -0
- package/lib/index13.cjs.map +1 -0
- package/lib/index13.mjs +57 -0
- package/lib/index13.mjs.map +1 -0
- package/lib/index14.cjs +10 -0
- package/lib/index14.cjs.map +1 -0
- package/lib/index14.mjs +10 -0
- package/lib/index14.mjs.map +1 -0
- package/lib/index15.cjs +30 -0
- package/lib/index15.cjs.map +1 -0
- package/lib/index15.mjs +30 -0
- package/lib/index15.mjs.map +1 -0
- package/lib/index16.cjs +28 -0
- package/lib/index16.cjs.map +1 -0
- package/lib/index16.mjs +26 -0
- package/lib/index16.mjs.map +1 -0
- package/lib/index17.cjs +43 -0
- package/lib/index17.cjs.map +1 -0
- package/lib/index17.mjs +43 -0
- package/lib/index17.mjs.map +1 -0
- package/lib/index18.cjs +59 -0
- package/lib/index18.cjs.map +1 -0
- package/lib/index18.mjs +59 -0
- package/lib/index18.mjs.map +1 -0
- package/lib/index19.cjs +67 -0
- package/lib/index19.cjs.map +1 -0
- package/lib/index19.mjs +67 -0
- package/lib/index19.mjs.map +1 -0
- package/lib/index2.cjs +33 -0
- package/lib/index2.mjs +13 -0
- package/lib/index20.cjs +79 -0
- package/lib/index20.cjs.map +1 -0
- package/lib/index20.mjs +79 -0
- package/lib/index20.mjs.map +1 -0
- package/lib/index21.cjs +105 -0
- package/lib/index21.cjs.map +1 -0
- package/lib/index21.mjs +104 -0
- package/lib/index21.mjs.map +1 -0
- package/lib/index22.cjs +50 -0
- package/lib/index22.cjs.map +1 -0
- package/lib/index22.mjs +50 -0
- package/lib/index22.mjs.map +1 -0
- package/lib/index23.cjs +143 -0
- package/lib/index23.cjs.map +1 -0
- package/lib/index23.mjs +143 -0
- package/lib/index23.mjs.map +1 -0
- package/lib/index25.cjs +177 -0
- package/lib/index25.cjs.map +1 -0
- package/lib/index25.mjs +175 -0
- package/lib/index25.mjs.map +1 -0
- package/lib/index26.cjs +108 -0
- package/lib/index26.cjs.map +1 -0
- package/lib/index26.mjs +108 -0
- package/lib/index26.mjs.map +1 -0
- package/lib/index27.cjs +120 -0
- package/lib/index27.cjs.map +1 -0
- package/lib/index27.mjs +120 -0
- package/lib/index27.mjs.map +1 -0
- package/lib/index28.cjs +54 -0
- package/lib/index28.cjs.map +1 -0
- package/lib/index28.mjs +54 -0
- package/lib/index28.mjs.map +1 -0
- package/lib/index29.cjs +100 -0
- package/lib/index29.cjs.map +1 -0
- package/lib/index29.mjs +100 -0
- package/lib/index29.mjs.map +1 -0
- package/lib/index3.cjs +38 -0
- package/lib/index3.cjs.map +1 -0
- package/lib/index3.mjs +38 -0
- package/lib/index3.mjs.map +1 -0
- package/lib/index30.cjs +27 -0
- package/lib/index30.cjs.map +1 -0
- package/lib/index30.mjs +27 -0
- package/lib/index30.mjs.map +1 -0
- package/lib/index31.cjs +72 -0
- package/lib/index31.cjs.map +1 -0
- package/lib/index31.mjs +72 -0
- package/lib/index31.mjs.map +1 -0
- package/lib/index32.cjs +19 -0
- package/lib/index32.cjs.map +1 -0
- package/lib/index32.mjs +19 -0
- package/lib/index32.mjs.map +1 -0
- package/lib/index33.cjs +25 -0
- package/lib/index33.cjs.map +1 -0
- package/lib/index33.mjs +25 -0
- package/lib/index33.mjs.map +1 -0
- package/lib/index34.cjs +55 -0
- package/lib/index34.cjs.map +1 -0
- package/lib/index34.mjs +51 -0
- package/lib/index34.mjs.map +1 -0
- package/lib/index35.cjs +25 -0
- package/lib/index35.cjs.map +1 -0
- package/lib/index35.mjs +25 -0
- package/lib/index35.mjs.map +1 -0
- package/lib/index36.cjs +54 -0
- package/lib/index36.cjs.map +1 -0
- package/lib/index36.mjs +49 -0
- package/lib/index36.mjs.map +1 -0
- package/lib/index37.cjs +130 -0
- package/lib/index37.cjs.map +1 -0
- package/lib/index37.mjs +128 -0
- package/lib/index37.mjs.map +1 -0
- package/lib/index38.cjs +106 -0
- package/lib/index38.cjs.map +1 -0
- package/lib/index38.mjs +102 -0
- package/lib/index38.mjs.map +1 -0
- package/lib/index39.cjs +137 -0
- package/lib/index39.cjs.map +1 -0
- package/lib/index39.mjs +137 -0
- package/lib/index39.mjs.map +1 -0
- package/lib/index4.cjs +24 -0
- package/lib/index4.cjs.map +1 -0
- package/lib/index4.mjs +24 -0
- package/lib/index4.mjs.map +1 -0
- package/lib/index40.cjs +130 -0
- package/lib/index40.cjs.map +1 -0
- package/lib/index40.mjs +126 -0
- package/lib/index40.mjs.map +1 -0
- package/lib/index41.cjs +60 -0
- package/lib/index41.cjs.map +1 -0
- package/lib/index41.mjs +58 -0
- package/lib/index41.mjs.map +1 -0
- package/lib/index42.cjs +105 -0
- package/lib/index42.cjs.map +1 -0
- package/lib/index42.mjs +105 -0
- package/lib/index42.mjs.map +1 -0
- package/lib/index43.cjs +47 -0
- package/lib/index43.cjs.map +1 -0
- package/lib/index43.mjs +42 -0
- package/lib/index43.mjs.map +1 -0
- package/lib/index44.cjs +40 -0
- package/lib/index44.cjs.map +1 -0
- package/lib/index44.mjs +35 -0
- package/lib/index44.mjs.map +1 -0
- package/lib/index45.cjs +91 -0
- package/lib/index45.cjs.map +1 -0
- package/lib/index45.mjs +91 -0
- package/lib/index45.mjs.map +1 -0
- package/lib/index46.cjs +180 -0
- package/lib/index46.cjs.map +1 -0
- package/lib/index46.mjs +180 -0
- package/lib/index46.mjs.map +1 -0
- package/lib/index47.cjs +61 -0
- package/lib/index47.cjs.map +1 -0
- package/lib/index47.mjs +61 -0
- package/lib/index47.mjs.map +1 -0
- package/lib/index48.cjs +165 -0
- package/lib/index48.cjs.map +1 -0
- package/lib/index48.mjs +161 -0
- package/lib/index48.mjs.map +1 -0
- package/lib/index49.cjs +83 -0
- package/lib/index49.cjs.map +1 -0
- package/lib/index49.mjs +83 -0
- package/lib/index49.mjs.map +1 -0
- package/lib/index5.cjs +39 -0
- package/lib/index5.cjs.map +1 -0
- package/lib/index5.mjs +39 -0
- package/lib/index5.mjs.map +1 -0
- package/lib/index50.cjs +100 -0
- package/lib/index50.cjs.map +1 -0
- package/lib/index50.mjs +100 -0
- package/lib/index50.mjs.map +1 -0
- package/lib/index51.cjs +116 -0
- package/lib/index51.cjs.map +1 -0
- package/lib/index51.mjs +113 -0
- package/lib/index51.mjs.map +1 -0
- package/lib/index52.cjs +93 -0
- package/lib/index52.cjs.map +1 -0
- package/lib/index52.mjs +93 -0
- package/lib/index52.mjs.map +1 -0
- package/lib/index53.cjs +120 -0
- package/lib/index53.cjs.map +1 -0
- package/lib/index53.mjs +120 -0
- package/lib/index53.mjs.map +1 -0
- package/lib/index54.cjs +53 -0
- package/lib/index54.cjs.map +1 -0
- package/lib/index54.mjs +50 -0
- package/lib/index54.mjs.map +1 -0
- package/lib/index55.cjs +130 -0
- package/lib/index55.cjs.map +1 -0
- package/lib/index55.mjs +127 -0
- package/lib/index55.mjs.map +1 -0
- package/lib/index56.cjs +36 -0
- package/lib/index56.cjs.map +1 -0
- package/lib/index56.mjs +35 -0
- package/lib/index56.mjs.map +1 -0
- package/lib/index57.cjs +47 -0
- package/lib/index57.cjs.map +1 -0
- package/lib/index57.mjs +47 -0
- package/lib/index57.mjs.map +1 -0
- package/lib/index58.cjs +97 -0
- package/lib/index58.cjs.map +1 -0
- package/lib/index58.mjs +97 -0
- package/lib/index58.mjs.map +1 -0
- package/lib/index59.cjs +120 -0
- package/lib/index59.cjs.map +1 -0
- package/lib/index59.mjs +116 -0
- package/lib/index59.mjs.map +1 -0
- package/lib/index6.cjs +29 -0
- package/lib/index6.cjs.map +1 -0
- package/lib/index6.mjs +29 -0
- package/lib/index6.mjs.map +1 -0
- package/lib/index60.cjs +34 -0
- package/lib/index60.cjs.map +1 -0
- package/lib/index60.mjs +34 -0
- package/lib/index60.mjs.map +1 -0
- package/lib/index61.cjs +62 -0
- package/lib/index61.cjs.map +1 -0
- package/lib/index61.mjs +62 -0
- package/lib/index61.mjs.map +1 -0
- package/lib/index62.cjs +213 -0
- package/lib/index62.cjs.map +1 -0
- package/lib/index62.mjs +213 -0
- package/lib/index62.mjs.map +1 -0
- package/lib/index63.cjs +42 -0
- package/lib/index63.cjs.map +1 -0
- package/lib/index63.mjs +42 -0
- package/lib/index63.mjs.map +1 -0
- package/lib/index64.cjs +86 -0
- package/lib/index64.cjs.map +1 -0
- package/lib/index64.mjs +86 -0
- package/lib/index64.mjs.map +1 -0
- package/lib/index65.cjs +156 -0
- package/lib/index65.cjs.map +1 -0
- package/lib/index65.mjs +156 -0
- package/lib/index65.mjs.map +1 -0
- package/lib/index66.cjs +107 -0
- package/lib/index66.cjs.map +1 -0
- package/lib/index66.mjs +106 -0
- package/lib/index66.mjs.map +1 -0
- package/lib/index67.cjs +52 -0
- package/lib/index67.cjs.map +1 -0
- package/lib/index67.mjs +52 -0
- package/lib/index67.mjs.map +1 -0
- package/lib/index68.cjs +125 -0
- package/lib/index68.cjs.map +1 -0
- package/lib/index68.mjs +115 -0
- package/lib/index68.mjs.map +1 -0
- package/lib/index69.cjs +34 -0
- package/lib/index69.cjs.map +1 -0
- package/lib/index69.mjs +29 -0
- package/lib/index69.mjs.map +1 -0
- package/lib/index7.cjs +17 -0
- package/lib/index7.cjs.map +1 -0
- package/lib/index7.mjs +17 -0
- package/lib/index7.mjs.map +1 -0
- package/lib/index8.cjs +86 -0
- package/lib/index8.cjs.map +1 -0
- package/lib/index8.mjs +86 -0
- package/lib/index8.mjs.map +1 -0
- package/lib/index9.cjs +29 -0
- package/lib/index9.cjs.map +1 -0
- package/lib/index9.mjs +29 -0
- package/lib/index9.mjs.map +1 -0
- package/lib/types/index.d.ts +1 -0
- package/package.json +68 -0
package/lib/index46.mjs
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useId, useRef, useState } from "react";
|
|
3
|
+
import { Command, Search } from "lucide-react";
|
|
4
|
+
import { createPortal } from "react-dom";
|
|
5
|
+
//#region src/ui-library/gallery/command-palette/CommandPalette.tsx
|
|
6
|
+
/**
|
|
7
|
+
* CommandPalette — Design System Component
|
|
8
|
+
*
|
|
9
|
+
* A keyboard-driven command launcher overlay. Opens via a trigger
|
|
10
|
+
* (typically Cmd+K / Ctrl+K), shows a search input, and renders
|
|
11
|
+
* grouped command items.
|
|
12
|
+
*
|
|
13
|
+
* Accessibility:
|
|
14
|
+
* - role="dialog" + aria-modal="true" + aria-label
|
|
15
|
+
* - Search input has aria-label and aria-controls pointing to results
|
|
16
|
+
* - Results list uses role="listbox" with role="option" items
|
|
17
|
+
* - aria-selected on the highlighted item
|
|
18
|
+
* - Keyboard: ArrowUp/Down navigates, Enter activates, Escape closes
|
|
19
|
+
*
|
|
20
|
+
* This component is presentation-only: callers provide commands and
|
|
21
|
+
* handle the query / selection logic.
|
|
22
|
+
*/
|
|
23
|
+
function CommandPalette({ open, onClose, items, query, onQueryChange, placeholder = "Search commands…", "aria-label": ariaLabel = "Command palette" }) {
|
|
24
|
+
const inputRef = useRef(null);
|
|
25
|
+
const panelRef = useRef(null);
|
|
26
|
+
const listboxId = useId();
|
|
27
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
setActiveIndex(0);
|
|
30
|
+
}, [items]);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!open) return;
|
|
33
|
+
const prev = document.body.style.overflow;
|
|
34
|
+
document.body.style.overflow = "hidden";
|
|
35
|
+
const timer = window.setTimeout(() => inputRef.current?.focus(), 0);
|
|
36
|
+
return () => {
|
|
37
|
+
clearTimeout(timer);
|
|
38
|
+
document.body.style.overflow = prev;
|
|
39
|
+
};
|
|
40
|
+
}, [open]);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!open) return;
|
|
43
|
+
const handle = (e) => {
|
|
44
|
+
if (e.key === "Escape") {
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
onClose();
|
|
47
|
+
} else if (e.key === "ArrowDown") {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
setActiveIndex((i) => Math.min(i + 1, items.length - 1));
|
|
50
|
+
} else if (e.key === "ArrowUp") {
|
|
51
|
+
e.preventDefault();
|
|
52
|
+
setActiveIndex((i) => Math.max(i - 1, 0));
|
|
53
|
+
} else if (e.key === "Enter") {
|
|
54
|
+
e.preventDefault();
|
|
55
|
+
items[activeIndex]?.onSelect();
|
|
56
|
+
onClose();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
document.addEventListener("keydown", handle);
|
|
60
|
+
return () => document.removeEventListener("keydown", handle);
|
|
61
|
+
}, [
|
|
62
|
+
open,
|
|
63
|
+
items,
|
|
64
|
+
activeIndex,
|
|
65
|
+
onClose
|
|
66
|
+
]);
|
|
67
|
+
if (!open) return null;
|
|
68
|
+
const groups = items.reduce((acc, item) => {
|
|
69
|
+
const g = item.group ?? "";
|
|
70
|
+
if (!acc[g]) acc[g] = [];
|
|
71
|
+
acc[g].push(item);
|
|
72
|
+
return acc;
|
|
73
|
+
}, {});
|
|
74
|
+
const groupEntries = Object.entries(groups);
|
|
75
|
+
return createPortal(/* @__PURE__ */ jsxs("div", {
|
|
76
|
+
className: "fixed inset-0 z-50 flex items-start justify-center pt-[10vh] px-4",
|
|
77
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
78
|
+
className: "absolute inset-0 bg-slate-900/50 backdrop-blur-sm",
|
|
79
|
+
"aria-hidden": "true",
|
|
80
|
+
onClick: onClose
|
|
81
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
82
|
+
ref: panelRef,
|
|
83
|
+
role: "dialog",
|
|
84
|
+
"aria-modal": "true",
|
|
85
|
+
"aria-label": ariaLabel,
|
|
86
|
+
className: "relative z-10 w-full max-w-lg rounded-2xl border border-slate-200 bg-white shadow-2xl overflow-hidden",
|
|
87
|
+
children: [
|
|
88
|
+
/* @__PURE__ */ jsxs("div", {
|
|
89
|
+
className: "flex items-center gap-3 px-4 py-3 border-b border-slate-100",
|
|
90
|
+
children: [
|
|
91
|
+
/* @__PURE__ */ jsx(Search, {
|
|
92
|
+
size: 16,
|
|
93
|
+
className: "shrink-0 text-slate-400",
|
|
94
|
+
"aria-hidden": "true"
|
|
95
|
+
}),
|
|
96
|
+
/* @__PURE__ */ jsx("input", {
|
|
97
|
+
ref: inputRef,
|
|
98
|
+
type: "text",
|
|
99
|
+
role: "combobox",
|
|
100
|
+
"aria-expanded": items.length > 0,
|
|
101
|
+
"aria-controls": listboxId,
|
|
102
|
+
"aria-autocomplete": "list",
|
|
103
|
+
"aria-label": "Search commands",
|
|
104
|
+
value: query,
|
|
105
|
+
onChange: (e) => onQueryChange(e.target.value),
|
|
106
|
+
placeholder,
|
|
107
|
+
className: "flex-1 bg-transparent text-sm font-medium text-slate-900 outline-none placeholder:text-slate-400"
|
|
108
|
+
}),
|
|
109
|
+
/* @__PURE__ */ jsx("kbd", {
|
|
110
|
+
className: "hidden shrink-0 rounded border border-slate-200 px-1.5 py-0.5 text-[10px] font-bold text-slate-400 sm:block",
|
|
111
|
+
children: "ESC"
|
|
112
|
+
})
|
|
113
|
+
]
|
|
114
|
+
}),
|
|
115
|
+
items.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
116
|
+
id: listboxId,
|
|
117
|
+
role: "listbox",
|
|
118
|
+
"aria-label": "Commands",
|
|
119
|
+
className: "max-h-72 overflow-y-auto py-1",
|
|
120
|
+
children: groupEntries.map(([group, groupItems]) => /* @__PURE__ */ jsxs("div", { children: [group && /* @__PURE__ */ jsx("div", {
|
|
121
|
+
className: "px-4 py-1.5 text-[10px] font-bold uppercase tracking-widest text-slate-400",
|
|
122
|
+
children: group
|
|
123
|
+
}), groupItems.map((item) => {
|
|
124
|
+
const globalIdx = items.indexOf(item);
|
|
125
|
+
const isActive = globalIdx === activeIndex;
|
|
126
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
127
|
+
role: "option",
|
|
128
|
+
"aria-selected": isActive,
|
|
129
|
+
onClick: () => {
|
|
130
|
+
item.onSelect();
|
|
131
|
+
onClose();
|
|
132
|
+
},
|
|
133
|
+
onMouseEnter: () => setActiveIndex(globalIdx),
|
|
134
|
+
className: `flex cursor-pointer items-center gap-3 px-4 py-2.5 transition ${isActive ? "bg-blue-50" : "hover:bg-slate-50"}`,
|
|
135
|
+
children: [
|
|
136
|
+
item.icon && /* @__PURE__ */ jsx("span", {
|
|
137
|
+
className: `shrink-0 ${isActive ? "text-brand-blue" : "text-slate-400"}`,
|
|
138
|
+
"aria-hidden": "true",
|
|
139
|
+
children: item.icon
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ jsxs("div", {
|
|
142
|
+
className: "min-w-0 flex-1",
|
|
143
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
144
|
+
className: `text-sm font-semibold ${isActive ? "text-brand-blue" : "text-slate-700"}`,
|
|
145
|
+
children: item.label
|
|
146
|
+
}), item.description && /* @__PURE__ */ jsx("p", {
|
|
147
|
+
className: "text-xs font-medium text-slate-400",
|
|
148
|
+
children: item.description
|
|
149
|
+
})]
|
|
150
|
+
}),
|
|
151
|
+
isActive && /* @__PURE__ */ jsx("kbd", {
|
|
152
|
+
className: "shrink-0 rounded border border-brand-blue/25 bg-blue-50 px-1.5 py-0.5 text-[10px] font-bold text-brand-blue",
|
|
153
|
+
children: "↵"
|
|
154
|
+
})
|
|
155
|
+
]
|
|
156
|
+
}, item.id);
|
|
157
|
+
})] }, group))
|
|
158
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
159
|
+
className: "px-4 py-8 text-center text-sm font-medium text-slate-400",
|
|
160
|
+
children: query ? `No results for "${query}"` : "Type to search commands"
|
|
161
|
+
}),
|
|
162
|
+
/* @__PURE__ */ jsxs("div", {
|
|
163
|
+
className: "flex items-center gap-3 border-t border-slate-100 px-4 py-2",
|
|
164
|
+
children: [/* @__PURE__ */ jsx(Command, {
|
|
165
|
+
size: 11,
|
|
166
|
+
className: "text-slate-300",
|
|
167
|
+
"aria-hidden": "true"
|
|
168
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
169
|
+
className: "text-[10px] font-medium text-slate-400",
|
|
170
|
+
children: "↑↓ navigate · ↵ select · Esc close"
|
|
171
|
+
})]
|
|
172
|
+
})
|
|
173
|
+
]
|
|
174
|
+
})]
|
|
175
|
+
}), document.body);
|
|
176
|
+
}
|
|
177
|
+
//#endregion
|
|
178
|
+
export { CommandPalette };
|
|
179
|
+
|
|
180
|
+
//# sourceMappingURL=index46.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index46.mjs","names":[],"sources":["../src/ui-library/gallery/command-palette/CommandPalette.tsx"],"sourcesContent":["/**\n * CommandPalette — Design System Component\n *\n * A keyboard-driven command launcher overlay. Opens via a trigger\n * (typically Cmd+K / Ctrl+K), shows a search input, and renders\n * grouped command items.\n *\n * Accessibility:\n * - role=\"dialog\" + aria-modal=\"true\" + aria-label\n * - Search input has aria-label and aria-controls pointing to results\n * - Results list uses role=\"listbox\" with role=\"option\" items\n * - aria-selected on the highlighted item\n * - Keyboard: ArrowUp/Down navigates, Enter activates, Escape closes\n *\n * This component is presentation-only: callers provide commands and\n * handle the query / selection logic.\n */\n\nimport { useEffect, useId, useRef, useState, type ReactNode } from 'react';\nimport { createPortal } from 'react-dom';\nimport { Search, Command } from 'lucide-react';\n\nexport interface CommandItem {\n id: string;\n label: string;\n description?: string;\n icon?: ReactNode;\n group?: string;\n onSelect: () => void;\n}\n\nexport interface CommandPaletteProps {\n open: boolean;\n onClose: () => void;\n /** All available commands — consumer filters by query. */\n items: CommandItem[];\n /** Current search query. */\n query: string;\n /** Called when search query changes. */\n onQueryChange: (q: string) => void;\n /** Placeholder in the search input. Default: \"Search commands…\" */\n placeholder?: string;\n /** aria-label for the dialog. Default: \"Command palette\" */\n 'aria-label'?: string;\n}\n\nexport function CommandPalette({\n open,\n onClose,\n items,\n query,\n onQueryChange,\n placeholder = 'Search commands\\u2026',\n 'aria-label': ariaLabel = 'Command palette',\n}: CommandPaletteProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const panelRef = useRef<HTMLDivElement>(null);\n const listboxId = useId();\n const [activeIndex, setActiveIndex] = useState(0);\n\n // Reset active index when items change\n // eslint-disable-next-line react-hooks/set-state-in-effect\n useEffect(() => { setActiveIndex(0); }, [items]);\n\n // Scroll lock + initial focus\n useEffect(() => {\n if (!open) return;\n const prev = document.body.style.overflow;\n document.body.style.overflow = 'hidden';\n const timer = window.setTimeout(() => inputRef.current?.focus(), 0);\n return () => {\n clearTimeout(timer);\n document.body.style.overflow = prev;\n };\n }, [open]);\n\n // Keyboard navigation\n useEffect(() => {\n if (!open) return;\n const handle = (e: KeyboardEvent) => {\n if (e.key === 'Escape') { e.preventDefault(); onClose(); }\n else if (e.key === 'ArrowDown') {\n e.preventDefault();\n setActiveIndex((i) => Math.min(i + 1, items.length - 1));\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n setActiveIndex((i) => Math.max(i - 1, 0));\n } else if (e.key === 'Enter') {\n e.preventDefault();\n items[activeIndex]?.onSelect();\n onClose();\n }\n };\n document.addEventListener('keydown', handle);\n return () => document.removeEventListener('keydown', handle);\n }, [open, items, activeIndex, onClose]);\n\n if (!open) return null;\n\n // Group items\n const groups = items.reduce<Record<string, CommandItem[]>>((acc, item) => {\n const g = item.group ?? '';\n if (!acc[g]) acc[g] = [];\n acc[g]!.push(item);\n return acc;\n }, {});\n\n const groupEntries = Object.entries(groups);\n\n return createPortal(\n <div className=\"fixed inset-0 z-50 flex items-start justify-center pt-[10vh] px-4\">\n {/* Backdrop */}\n <div\n className=\"absolute inset-0 bg-slate-900/50 backdrop-blur-sm\"\n aria-hidden=\"true\"\n onClick={onClose}\n />\n\n {/* Panel */}\n <div\n ref={panelRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={ariaLabel}\n className=\"relative z-10 w-full max-w-lg rounded-2xl border border-slate-200 bg-white shadow-2xl overflow-hidden\"\n >\n {/* Search row */}\n <div className=\"flex items-center gap-3 px-4 py-3 border-b border-slate-100\">\n <Search size={16} className=\"shrink-0 text-slate-400\" aria-hidden=\"true\" />\n <input\n ref={inputRef}\n type=\"text\"\n role=\"combobox\"\n aria-expanded={items.length > 0}\n aria-controls={listboxId}\n aria-autocomplete=\"list\"\n aria-label=\"Search commands\"\n value={query}\n onChange={(e) => onQueryChange(e.target.value)}\n placeholder={placeholder}\n className=\"flex-1 bg-transparent text-sm font-medium text-slate-900 outline-none placeholder:text-slate-400\"\n />\n <kbd className=\"hidden shrink-0 rounded border border-slate-200 px-1.5 py-0.5 text-[10px] font-bold text-slate-400 sm:block\">\n ESC\n </kbd>\n </div>\n\n {/* Results */}\n {items.length > 0 ? (\n <div\n id={listboxId}\n role=\"listbox\"\n aria-label=\"Commands\"\n className=\"max-h-72 overflow-y-auto py-1\"\n >\n {groupEntries.map(([group, groupItems]) => (\n <div key={group}>\n {group && (\n <div className=\"px-4 py-1.5 text-[10px] font-bold uppercase tracking-widest text-slate-400\">\n {group}\n </div>\n )}\n {groupItems.map((item) => {\n const globalIdx = items.indexOf(item);\n const isActive = globalIdx === activeIndex;\n return (\n <div\n key={item.id}\n role=\"option\"\n aria-selected={isActive}\n onClick={() => { item.onSelect(); onClose(); }}\n onMouseEnter={() => setActiveIndex(globalIdx)}\n className={`flex cursor-pointer items-center gap-3 px-4 py-2.5 transition ${\n isActive ? 'bg-blue-50' : 'hover:bg-slate-50'\n }`}\n >\n {item.icon && (\n <span className={`shrink-0 ${isActive ? 'text-brand-blue' : 'text-slate-400'}`} aria-hidden=\"true\">\n {item.icon}\n </span>\n )}\n <div className=\"min-w-0 flex-1\">\n <p className={`text-sm font-semibold ${isActive ? 'text-brand-blue' : 'text-slate-700'}`}>\n {item.label}\n </p>\n {item.description && (\n <p className=\"text-xs font-medium text-slate-400\">{item.description}</p>\n )}\n </div>\n {isActive && (\n <kbd className=\"shrink-0 rounded border border-brand-blue/25 bg-blue-50 px-1.5 py-0.5 text-[10px] font-bold text-brand-blue\">\n ↵\n </kbd>\n )}\n </div>\n );\n })}\n </div>\n ))}\n </div>\n ) : (\n <div className=\"px-4 py-8 text-center text-sm font-medium text-slate-400\">\n {query ? `No results for \"${query}\"` : 'Type to search commands'}\n </div>\n )}\n\n {/* Footer hint */}\n <div className=\"flex items-center gap-3 border-t border-slate-100 px-4 py-2\">\n <Command size={11} className=\"text-slate-300\" aria-hidden=\"true\" />\n <span className=\"text-[10px] font-medium text-slate-400\">\n ↑↓ navigate · ↵ select · Esc close\n </span>\n </div>\n </div>\n </div>,\n document.body,\n );\n}\n"],"mappings":"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"}
|
package/lib/index47.cjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
2
|
+
let lucide_react = require("lucide-react");
|
|
3
|
+
let react_router_dom = require("react-router-dom");
|
|
4
|
+
//#region src/ui-library/gallery/breadcrumb/Breadcrumb.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Breadcrumb — Design System Component
|
|
7
|
+
*
|
|
8
|
+
* A hierarchical location indicator. Renders a <nav> landmark with
|
|
9
|
+
* an accessible label. The last item receives aria-current="page".
|
|
10
|
+
*
|
|
11
|
+
* The component is purely presentational — it does not read from
|
|
12
|
+
* the router. The consuming feature provides the items array.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* <Breadcrumb
|
|
16
|
+
* items={[
|
|
17
|
+
* { label: 'Home', href: '/' },
|
|
18
|
+
* { label: 'Settings', href: '/settings' },
|
|
19
|
+
* { label: 'Roles' },
|
|
20
|
+
* ]}
|
|
21
|
+
* />
|
|
22
|
+
*/
|
|
23
|
+
function Breadcrumb({ items, showHome = true, ariaLabel = "Breadcrumb" }) {
|
|
24
|
+
if (items.length === 0) return null;
|
|
25
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("nav", {
|
|
26
|
+
"aria-label": ariaLabel,
|
|
27
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ol", {
|
|
28
|
+
className: "flex flex-wrap items-center gap-1 text-sm font-semibold text-slate-400",
|
|
29
|
+
children: [showHome && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
30
|
+
className: "flex items-center",
|
|
31
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.Home, {
|
|
32
|
+
size: 14,
|
|
33
|
+
className: "shrink-0 text-slate-400",
|
|
34
|
+
"aria-hidden": "true"
|
|
35
|
+
})
|
|
36
|
+
}), items.map((item, index) => {
|
|
37
|
+
const isLast = index === items.length - 1;
|
|
38
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
39
|
+
className: "flex items-center gap-1",
|
|
40
|
+
children: [(!(index === 0) || showHome) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronRight, {
|
|
41
|
+
size: 13,
|
|
42
|
+
className: "shrink-0 text-slate-300",
|
|
43
|
+
"aria-hidden": "true"
|
|
44
|
+
}), isLast ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
45
|
+
className: "text-slate-700",
|
|
46
|
+
"aria-current": "page",
|
|
47
|
+
children: item.label
|
|
48
|
+
}) : item.href ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_router_dom.Link, {
|
|
49
|
+
to: item.href,
|
|
50
|
+
className: "transition-colors hover:text-slate-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 rounded",
|
|
51
|
+
children: item.label
|
|
52
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: item.label })]
|
|
53
|
+
}, item.label);
|
|
54
|
+
})]
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
exports.Breadcrumb = Breadcrumb;
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=index47.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index47.cjs","names":[],"sources":["../src/ui-library/gallery/breadcrumb/Breadcrumb.tsx"],"sourcesContent":["/**\n * Breadcrumb — Design System Component\n *\n * A hierarchical location indicator. Renders a <nav> landmark with\n * an accessible label. The last item receives aria-current=\"page\".\n *\n * The component is purely presentational — it does not read from\n * the router. The consuming feature provides the items array.\n *\n * Usage:\n * <Breadcrumb\n * items={[\n * { label: 'Home', href: '/' },\n * { label: 'Settings', href: '/settings' },\n * { label: 'Roles' },\n * ]}\n * />\n */\n\nimport { ChevronRight, Home } from 'lucide-react';\nimport { Link } from 'react-router-dom';\n\nexport interface BreadcrumbItem {\n label: string;\n /** When provided, the item is rendered as a link. Omit for the current/last item. */\n href?: string;\n}\n\nexport interface BreadcrumbProps {\n items: BreadcrumbItem[];\n /** Show a Home icon before the first item (default: true) */\n showHome?: boolean;\n /** aria-label for the <nav> element (default: \"Breadcrumb\") */\n ariaLabel?: string;\n}\n\nexport function Breadcrumb({\n items,\n showHome = true,\n ariaLabel = 'Breadcrumb',\n}: BreadcrumbProps) {\n if (items.length === 0) return null;\n\n return (\n <nav aria-label={ariaLabel}>\n <ol className=\"flex flex-wrap items-center gap-1 text-sm font-semibold text-slate-400\">\n {/* Home icon — decorative visual anchor */}\n {showHome && (\n <li className=\"flex items-center\">\n <Home size={14} className=\"shrink-0 text-slate-400\" aria-hidden=\"true\" />\n </li>\n )}\n\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n const isFirst = index === 0;\n\n return (\n <li key={item.label} className=\"flex items-center gap-1\">\n {/* Separator — not first item, or when Home is shown */}\n {(!isFirst || showHome) && (\n <ChevronRight\n size={13}\n className=\"shrink-0 text-slate-300\"\n aria-hidden=\"true\"\n />\n )}\n\n {isLast ? (\n /* Current page — not a link */\n <span\n className=\"text-slate-700\"\n aria-current=\"page\"\n >\n {item.label}\n </span>\n ) : item.href ? (\n /* Ancestor with a link */\n <Link\n to={item.href}\n className=\"transition-colors hover:text-slate-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 rounded\"\n >\n {item.label}\n </Link>\n ) : (\n /* Ancestor without a link (non-navigable section label) */\n <span>{item.label}</span>\n )}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,WAAW,EACzB,OACA,WAAW,MACX,YAAY,gBACM;CAClB,IAAI,MAAM,WAAW,GAAG,OAAO;CAE/B,OACE,iBAAA,GAAA,kBAAA,IAAA,CAAC,OAAD;EAAK,cAAY;EACf,UAAA,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;GAAI,WAAU;GAAd,UAAA,CAEG,YACC,iBAAA,GAAA,kBAAA,IAAA,CAAC,MAAD;IAAI,WAAU;IACZ,UAAA,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAA,MAAD;KAAM,MAAM;KAAI,WAAU;KAA0B,eAAY;IAAQ,CAAA;GACtE,CAAA,GAGL,MAAM,KAAK,MAAM,UAAU;IAC1B,MAAM,SAAS,UAAU,MAAM,SAAS;IAGxC,OACE,iBAAA,GAAA,kBAAA,KAAA,CAAC,MAAD;KAAqB,WAAU;KAA/B,UAAA,EAEI,EALU,UAAU,MAKR,aACZ,iBAAA,GAAA,kBAAA,IAAA,CAAC,aAAA,cAAD;MACE,MAAM;MACN,WAAU;MACV,eAAY;KACb,CAAA,GAGF,SAEC,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD;MACE,WAAU;MACV,gBAAa;MAEZ,UAAA,KAAK;KACF,CAAA,IACJ,KAAK,OAEP,iBAAA,GAAA,kBAAA,IAAA,CAAC,iBAAA,MAAD;MACE,IAAI,KAAK;MACT,WAAU;MAET,UAAA,KAAK;KACF,CAAA,IAGN,iBAAA,GAAA,kBAAA,IAAA,CAAC,QAAD,EAAA,UAAO,KAAK,MAAY,CAAA,CAExB;IA9BK,GAAA,KAAK,KA8BV;GAER,CAAC,CACC;;CACD,CAAA;AAET"}
|
package/lib/index47.mjs
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronRight, Home } from "lucide-react";
|
|
3
|
+
import { Link } from "react-router-dom";
|
|
4
|
+
//#region src/ui-library/gallery/breadcrumb/Breadcrumb.tsx
|
|
5
|
+
/**
|
|
6
|
+
* Breadcrumb — Design System Component
|
|
7
|
+
*
|
|
8
|
+
* A hierarchical location indicator. Renders a <nav> landmark with
|
|
9
|
+
* an accessible label. The last item receives aria-current="page".
|
|
10
|
+
*
|
|
11
|
+
* The component is purely presentational — it does not read from
|
|
12
|
+
* the router. The consuming feature provides the items array.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* <Breadcrumb
|
|
16
|
+
* items={[
|
|
17
|
+
* { label: 'Home', href: '/' },
|
|
18
|
+
* { label: 'Settings', href: '/settings' },
|
|
19
|
+
* { label: 'Roles' },
|
|
20
|
+
* ]}
|
|
21
|
+
* />
|
|
22
|
+
*/
|
|
23
|
+
function Breadcrumb({ items, showHome = true, ariaLabel = "Breadcrumb" }) {
|
|
24
|
+
if (items.length === 0) return null;
|
|
25
|
+
return /* @__PURE__ */ jsx("nav", {
|
|
26
|
+
"aria-label": ariaLabel,
|
|
27
|
+
children: /* @__PURE__ */ jsxs("ol", {
|
|
28
|
+
className: "flex flex-wrap items-center gap-1 text-sm font-semibold text-slate-400",
|
|
29
|
+
children: [showHome && /* @__PURE__ */ jsx("li", {
|
|
30
|
+
className: "flex items-center",
|
|
31
|
+
children: /* @__PURE__ */ jsx(Home, {
|
|
32
|
+
size: 14,
|
|
33
|
+
className: "shrink-0 text-slate-400",
|
|
34
|
+
"aria-hidden": "true"
|
|
35
|
+
})
|
|
36
|
+
}), items.map((item, index) => {
|
|
37
|
+
const isLast = index === items.length - 1;
|
|
38
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
39
|
+
className: "flex items-center gap-1",
|
|
40
|
+
children: [(!(index === 0) || showHome) && /* @__PURE__ */ jsx(ChevronRight, {
|
|
41
|
+
size: 13,
|
|
42
|
+
className: "shrink-0 text-slate-300",
|
|
43
|
+
"aria-hidden": "true"
|
|
44
|
+
}), isLast ? /* @__PURE__ */ jsx("span", {
|
|
45
|
+
className: "text-slate-700",
|
|
46
|
+
"aria-current": "page",
|
|
47
|
+
children: item.label
|
|
48
|
+
}) : item.href ? /* @__PURE__ */ jsx(Link, {
|
|
49
|
+
to: item.href,
|
|
50
|
+
className: "transition-colors hover:text-slate-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 rounded",
|
|
51
|
+
children: item.label
|
|
52
|
+
}) : /* @__PURE__ */ jsx("span", { children: item.label })]
|
|
53
|
+
}, item.label);
|
|
54
|
+
})]
|
|
55
|
+
})
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { Breadcrumb };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=index47.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index47.mjs","names":[],"sources":["../src/ui-library/gallery/breadcrumb/Breadcrumb.tsx"],"sourcesContent":["/**\n * Breadcrumb — Design System Component\n *\n * A hierarchical location indicator. Renders a <nav> landmark with\n * an accessible label. The last item receives aria-current=\"page\".\n *\n * The component is purely presentational — it does not read from\n * the router. The consuming feature provides the items array.\n *\n * Usage:\n * <Breadcrumb\n * items={[\n * { label: 'Home', href: '/' },\n * { label: 'Settings', href: '/settings' },\n * { label: 'Roles' },\n * ]}\n * />\n */\n\nimport { ChevronRight, Home } from 'lucide-react';\nimport { Link } from 'react-router-dom';\n\nexport interface BreadcrumbItem {\n label: string;\n /** When provided, the item is rendered as a link. Omit for the current/last item. */\n href?: string;\n}\n\nexport interface BreadcrumbProps {\n items: BreadcrumbItem[];\n /** Show a Home icon before the first item (default: true) */\n showHome?: boolean;\n /** aria-label for the <nav> element (default: \"Breadcrumb\") */\n ariaLabel?: string;\n}\n\nexport function Breadcrumb({\n items,\n showHome = true,\n ariaLabel = 'Breadcrumb',\n}: BreadcrumbProps) {\n if (items.length === 0) return null;\n\n return (\n <nav aria-label={ariaLabel}>\n <ol className=\"flex flex-wrap items-center gap-1 text-sm font-semibold text-slate-400\">\n {/* Home icon — decorative visual anchor */}\n {showHome && (\n <li className=\"flex items-center\">\n <Home size={14} className=\"shrink-0 text-slate-400\" aria-hidden=\"true\" />\n </li>\n )}\n\n {items.map((item, index) => {\n const isLast = index === items.length - 1;\n const isFirst = index === 0;\n\n return (\n <li key={item.label} className=\"flex items-center gap-1\">\n {/* Separator — not first item, or when Home is shown */}\n {(!isFirst || showHome) && (\n <ChevronRight\n size={13}\n className=\"shrink-0 text-slate-300\"\n aria-hidden=\"true\"\n />\n )}\n\n {isLast ? (\n /* Current page — not a link */\n <span\n className=\"text-slate-700\"\n aria-current=\"page\"\n >\n {item.label}\n </span>\n ) : item.href ? (\n /* Ancestor with a link */\n <Link\n to={item.href}\n className=\"transition-colors hover:text-slate-600 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-blue/30 rounded\"\n >\n {item.label}\n </Link>\n ) : (\n /* Ancestor without a link (non-navigable section label) */\n <span>{item.label}</span>\n )}\n </li>\n );\n })}\n </ol>\n </nav>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAoCA,SAAgB,WAAW,EACzB,OACA,WAAW,MACX,YAAY,gBACM;CAClB,IAAI,MAAM,WAAW,GAAG,OAAO;CAE/B,OACE,oBAAC,OAAD;EAAK,cAAY;EACf,UAAA,qBAAC,MAAD;GAAI,WAAU;GAAd,UAAA,CAEG,YACC,oBAAC,MAAD;IAAI,WAAU;IACZ,UAAA,oBAAC,MAAD;KAAM,MAAM;KAAI,WAAU;KAA0B,eAAY;IAAQ,CAAA;GACtE,CAAA,GAGL,MAAM,KAAK,MAAM,UAAU;IAC1B,MAAM,SAAS,UAAU,MAAM,SAAS;IAGxC,OACE,qBAAC,MAAD;KAAqB,WAAU;KAA/B,UAAA,EAEI,EALU,UAAU,MAKR,aACZ,oBAAC,cAAD;MACE,MAAM;MACN,WAAU;MACV,eAAY;KACb,CAAA,GAGF,SAEC,oBAAC,QAAD;MACE,WAAU;MACV,gBAAa;MAEZ,UAAA,KAAK;KACF,CAAA,IACJ,KAAK,OAEP,oBAAC,MAAD;MACE,IAAI,KAAK;MACT,WAAU;MAET,UAAA,KAAK;KACF,CAAA,IAGN,oBAAC,QAAD,EAAA,UAAO,KAAK,MAAY,CAAA,CAExB;IA9BK,GAAA,KAAK,KA8BV;GAER,CAAC,CACC;;CACD,CAAA;AAET"}
|
package/lib/index48.cjs
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
2
|
+
let react = require("react");
|
|
3
|
+
//#region src/ui-library/gallery/tabs/Tabs.tsx
|
|
4
|
+
/**
|
|
5
|
+
* Tabs — Design System Component
|
|
6
|
+
*
|
|
7
|
+
* Composable tab interface with full WAI-ARIA Tabs pattern compliance.
|
|
8
|
+
*
|
|
9
|
+
* Responsibilities:
|
|
10
|
+
* - role="tablist" on the tab strip
|
|
11
|
+
* - role="tab" with aria-selected, aria-controls, aria-disabled on each tab
|
|
12
|
+
* - role="tabpanel" with aria-labelledby on each panel
|
|
13
|
+
* - Stable generated IDs for tab/panel cross-referencing
|
|
14
|
+
* - ArrowRight / ArrowLeft / Home / End keyboard navigation
|
|
15
|
+
* - Controlled and uncontrolled usage
|
|
16
|
+
* - Disabled tab support (skipped during keyboard navigation)
|
|
17
|
+
*
|
|
18
|
+
* Composition:
|
|
19
|
+
* <Tabs defaultValue="overview">
|
|
20
|
+
* <TabList aria-label="Section navigation">
|
|
21
|
+
* <Tab value="overview">Overview</Tab>
|
|
22
|
+
* <Tab value="details">Details</Tab>
|
|
23
|
+
* <Tab value="history" disabled>History</Tab>
|
|
24
|
+
* </TabList>
|
|
25
|
+
* <TabPanels>
|
|
26
|
+
* <TabPanel value="overview">…</TabPanel>
|
|
27
|
+
* <TabPanel value="details">…</TabPanel>
|
|
28
|
+
* <TabPanel value="history">…</TabPanel>
|
|
29
|
+
* </TabPanels>
|
|
30
|
+
* </Tabs>
|
|
31
|
+
*
|
|
32
|
+
* Keyboard model: "manual activation" — ArrowKey moves focus but the user
|
|
33
|
+
* must press Space/Enter to activate a new tab. This is the WAI-ARIA
|
|
34
|
+
* recommended default when tab panels contain complex content (forms, tables)
|
|
35
|
+
* because "automatic activation" can trigger expensive content fetches on
|
|
36
|
+
* every arrow press.
|
|
37
|
+
*
|
|
38
|
+
* To switch to "automatic activation" (Arrow key also activates),
|
|
39
|
+
* set activateOnFocus={true} on <Tabs>.
|
|
40
|
+
*/
|
|
41
|
+
var TabsContext = (0, react.createContext)(null);
|
|
42
|
+
function useTabsContext() {
|
|
43
|
+
const ctx = (0, react.useContext)(TabsContext);
|
|
44
|
+
if (!ctx) throw new Error("Tabs sub-component used outside <Tabs>");
|
|
45
|
+
return ctx;
|
|
46
|
+
}
|
|
47
|
+
function tabId(baseId, value) {
|
|
48
|
+
return `${baseId}-tab-${value}`;
|
|
49
|
+
}
|
|
50
|
+
function panelId(baseId, value) {
|
|
51
|
+
return `${baseId}-panel-${value}`;
|
|
52
|
+
}
|
|
53
|
+
function Tabs({ value: controlledValue, onValueChange, defaultValue = "", activateOnFocus = false, children, className = "" }) {
|
|
54
|
+
const [uncontrolledValue, setUncontrolledValue] = (0, react.useState)(defaultValue);
|
|
55
|
+
const baseId = (0, react.useId)();
|
|
56
|
+
const tabValues = (0, react.useRef)([]);
|
|
57
|
+
const isControlled = controlledValue !== void 0;
|
|
58
|
+
const activeValue = isControlled ? controlledValue : uncontrolledValue;
|
|
59
|
+
const disabledValues = (0, react.useRef)(/* @__PURE__ */ new Set()).current;
|
|
60
|
+
const activate = (value) => {
|
|
61
|
+
if (disabledValues.has(value)) return;
|
|
62
|
+
if (!isControlled) setUncontrolledValue(value);
|
|
63
|
+
onValueChange?.(value);
|
|
64
|
+
};
|
|
65
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TabsContext.Provider, {
|
|
66
|
+
value: {
|
|
67
|
+
activeValue,
|
|
68
|
+
activate,
|
|
69
|
+
baseId,
|
|
70
|
+
tabValues,
|
|
71
|
+
disabledValues,
|
|
72
|
+
activateOnFocus
|
|
73
|
+
},
|
|
74
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
75
|
+
className,
|
|
76
|
+
children
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function TabList({ "aria-label": ariaLabel, children, className = "" }) {
|
|
81
|
+
const { baseId, tabValues, disabledValues, activate, activateOnFocus } = useTabsContext();
|
|
82
|
+
const handleKeyDown = (e) => {
|
|
83
|
+
const enabled = tabValues.current.filter((v) => !disabledValues.has(v));
|
|
84
|
+
if (enabled.length === 0) return;
|
|
85
|
+
const currentFocused = document.activeElement;
|
|
86
|
+
const currentIdx = tabValues.current.findIndex((v) => document.getElementById(tabId(baseId, v)) === currentFocused);
|
|
87
|
+
const currentEnabledIdx = enabled.indexOf(tabValues.current[currentIdx] ?? "");
|
|
88
|
+
let nextValue;
|
|
89
|
+
if (e.key === "ArrowRight") {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
nextValue = enabled[(currentEnabledIdx + 1) % enabled.length];
|
|
92
|
+
} else if (e.key === "ArrowLeft") {
|
|
93
|
+
e.preventDefault();
|
|
94
|
+
nextValue = enabled[(currentEnabledIdx - 1 + enabled.length) % enabled.length];
|
|
95
|
+
} else if (e.key === "Home") {
|
|
96
|
+
e.preventDefault();
|
|
97
|
+
nextValue = enabled[0];
|
|
98
|
+
} else if (e.key === "End") {
|
|
99
|
+
e.preventDefault();
|
|
100
|
+
nextValue = enabled[enabled.length - 1];
|
|
101
|
+
}
|
|
102
|
+
if (nextValue !== void 0) {
|
|
103
|
+
document.getElementById(tabId(baseId, nextValue))?.focus();
|
|
104
|
+
if (activateOnFocus) activate(nextValue);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
108
|
+
role: "tablist",
|
|
109
|
+
"aria-label": ariaLabel,
|
|
110
|
+
onKeyDown: handleKeyDown,
|
|
111
|
+
className: `flex border-b-2 border-slate-200 ${className}`,
|
|
112
|
+
children
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function Tab({ value, disabled = false, children, className = "" }) {
|
|
116
|
+
const { activeValue, activate, baseId, tabValues, disabledValues } = useTabsContext();
|
|
117
|
+
if (!tabValues.current.includes(value)) tabValues.current.push(value);
|
|
118
|
+
if (disabled) disabledValues.add(value);
|
|
119
|
+
else disabledValues.delete(value);
|
|
120
|
+
const isActive = activeValue === value;
|
|
121
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
122
|
+
id: tabId(baseId, value),
|
|
123
|
+
type: "button",
|
|
124
|
+
role: "tab",
|
|
125
|
+
"aria-selected": isActive,
|
|
126
|
+
"aria-controls": panelId(baseId, value),
|
|
127
|
+
"aria-disabled": disabled || void 0,
|
|
128
|
+
disabled,
|
|
129
|
+
tabIndex: isActive ? 0 : -1,
|
|
130
|
+
onClick: () => activate(value),
|
|
131
|
+
className: [
|
|
132
|
+
"relative px-5 py-3 text-sm font-semibold font-heading border-b-4 transition-colors",
|
|
133
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30",
|
|
134
|
+
isActive ? "border-brand-blue text-brand-blue" : disabled ? "border-transparent text-slate-300 cursor-not-allowed" : "border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300",
|
|
135
|
+
className
|
|
136
|
+
].filter(Boolean).join(" "),
|
|
137
|
+
children
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
function TabPanels({ children, className = "" }) {
|
|
141
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
142
|
+
className,
|
|
143
|
+
children
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
function TabPanel({ value, children, className = "" }) {
|
|
147
|
+
const { activeValue, baseId } = useTabsContext();
|
|
148
|
+
if (activeValue !== value) return null;
|
|
149
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
150
|
+
id: panelId(baseId, value),
|
|
151
|
+
role: "tabpanel",
|
|
152
|
+
"aria-labelledby": tabId(baseId, value),
|
|
153
|
+
tabIndex: 0,
|
|
154
|
+
className: ["focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30 rounded-sm", className].filter(Boolean).join(" "),
|
|
155
|
+
children
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
//#endregion
|
|
159
|
+
exports.Tab = Tab;
|
|
160
|
+
exports.TabList = TabList;
|
|
161
|
+
exports.TabPanel = TabPanel;
|
|
162
|
+
exports.TabPanels = TabPanels;
|
|
163
|
+
exports.Tabs = Tabs;
|
|
164
|
+
|
|
165
|
+
//# sourceMappingURL=index48.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index48.cjs","names":[],"sources":["../src/ui-library/gallery/tabs/Tabs.tsx"],"sourcesContent":["/**\n * Tabs — Design System Component\n *\n * Composable tab interface with full WAI-ARIA Tabs pattern compliance.\n *\n * Responsibilities:\n * - role=\"tablist\" on the tab strip\n * - role=\"tab\" with aria-selected, aria-controls, aria-disabled on each tab\n * - role=\"tabpanel\" with aria-labelledby on each panel\n * - Stable generated IDs for tab/panel cross-referencing\n * - ArrowRight / ArrowLeft / Home / End keyboard navigation\n * - Controlled and uncontrolled usage\n * - Disabled tab support (skipped during keyboard navigation)\n *\n * Composition:\n * <Tabs defaultValue=\"overview\">\n * <TabList aria-label=\"Section navigation\">\n * <Tab value=\"overview\">Overview</Tab>\n * <Tab value=\"details\">Details</Tab>\n * <Tab value=\"history\" disabled>History</Tab>\n * </TabList>\n * <TabPanels>\n * <TabPanel value=\"overview\">…</TabPanel>\n * <TabPanel value=\"details\">…</TabPanel>\n * <TabPanel value=\"history\">…</TabPanel>\n * </TabPanels>\n * </Tabs>\n *\n * Keyboard model: \"manual activation\" — ArrowKey moves focus but the user\n * must press Space/Enter to activate a new tab. This is the WAI-ARIA\n * recommended default when tab panels contain complex content (forms, tables)\n * because \"automatic activation\" can trigger expensive content fetches on\n * every arrow press.\n *\n * To switch to \"automatic activation\" (Arrow key also activates),\n * set activateOnFocus={true} on <Tabs>.\n */\n\nimport {\n createContext,\n useContext,\n useId,\n useRef,\n useState,\n type KeyboardEvent,\n type ReactNode,\n} from 'react';\n\n// ── Context ───────────────────────────────────────────────────────────────────\n\ninterface TabsContextValue {\n /** Currently active tab value */\n activeValue: string;\n /** Activate a tab (does nothing if disabled) */\n activate: (value: string) => void;\n /** Base id prefix shared by all tabs and panels in this Tabs instance */\n baseId: string;\n /** Registered tab values in DOM order (built up by Tab children) */\n tabValues: React.MutableRefObject<string[]>;\n /** Set of disabled tab values */\n disabledValues: Set<string>;\n /** Whether arrow keys also activate (true) or only move focus (false) */\n activateOnFocus: boolean;\n}\n\nconst TabsContext = createContext<TabsContextValue | null>(null);\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = useContext(TabsContext);\n if (!ctx) throw new Error('Tabs sub-component used outside <Tabs>');\n return ctx;\n}\n\n// ── Stable ID helpers ─────────────────────────────────────────────────────────\n\nfunction tabId(baseId: string, value: string) {\n return `${baseId}-tab-${value}`;\n}\n\nfunction panelId(baseId: string, value: string) {\n return `${baseId}-panel-${value}`;\n}\n\n// ── Tabs (root) ───────────────────────────────────────────────────────────────\n\nexport interface TabsProps {\n /** Controlled: current active tab value */\n value?: string;\n /** Controlled: called when a tab is activated */\n onValueChange?: (value: string) => void;\n /** Uncontrolled: initial active tab value */\n defaultValue?: string;\n /** Whether ArrowKey navigation also activates the tab immediately */\n activateOnFocus?: boolean;\n children: ReactNode;\n className?: string;\n}\n\nexport function Tabs({\n value: controlledValue,\n onValueChange,\n defaultValue = '',\n activateOnFocus = false,\n children,\n className = '',\n}: TabsProps) {\n const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue);\n const baseId = useId();\n const tabValues = useRef<string[]>([]);\n\n const isControlled = controlledValue !== undefined;\n const activeValue = isControlled ? controlledValue : uncontrolledValue;\n\n // Collect disabled values from child Tab props via context\n // eslint-disable-next-line react-hooks/refs\n const disabledValues = useRef(new Set<string>()).current;\n\n const activate = (value: string) => {\n if (disabledValues.has(value)) return;\n if (!isControlled) setUncontrolledValue(value);\n onValueChange?.(value);\n };\n\n return (\n <TabsContext.Provider\n value={{ activeValue, activate, baseId, tabValues, disabledValues, activateOnFocus }}\n >\n <div className={className}>{children}</div>\n </TabsContext.Provider>\n );\n}\n\n// ── TabList ───────────────────────────────────────────────────────────────────\n\nexport interface TabListProps {\n /** Accessible label for the tablist landmark */\n 'aria-label'?: string;\n children: ReactNode;\n className?: string;\n}\n\nexport function TabList({\n 'aria-label': ariaLabel,\n children,\n className = '',\n}: TabListProps) {\n const { baseId, tabValues, disabledValues, activate, activateOnFocus } =\n useTabsContext();\n\n const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n const enabled = tabValues.current.filter((v) => !disabledValues.has(v));\n if (enabled.length === 0) return;\n\n const currentFocused = document.activeElement;\n const currentIdx = tabValues.current.findIndex(\n (v) => document.getElementById(tabId(baseId, v)) === currentFocused,\n );\n const currentEnabledIdx = enabled.indexOf(tabValues.current[currentIdx] ?? '');\n\n let nextValue: string | undefined;\n\n if (e.key === 'ArrowRight') {\n e.preventDefault();\n nextValue = enabled[(currentEnabledIdx + 1) % enabled.length];\n } else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n nextValue = enabled[(currentEnabledIdx - 1 + enabled.length) % enabled.length];\n } else if (e.key === 'Home') {\n e.preventDefault();\n nextValue = enabled[0];\n } else if (e.key === 'End') {\n e.preventDefault();\n nextValue = enabled[enabled.length - 1];\n }\n\n if (nextValue !== undefined) {\n // Always move focus to the tab element\n document.getElementById(tabId(baseId, nextValue))?.focus();\n // Activate immediately if activateOnFocus, otherwise wait for Space/Enter\n if (activateOnFocus) activate(nextValue);\n }\n };\n\n return (\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n onKeyDown={handleKeyDown}\n className={`flex border-b-2 border-slate-200 ${className}`}\n >\n {children}\n </div>\n );\n}\n\n// ── Tab ───────────────────────────────────────────────────────────────────────\n\nexport interface TabProps {\n /** Must match the value used in <TabPanel value=\"…\"> */\n value: string;\n disabled?: boolean;\n children: ReactNode;\n className?: string;\n}\n\nexport function Tab({ value, disabled = false, children, className = '' }: TabProps) {\n const { activeValue, activate, baseId, tabValues, disabledValues } = useTabsContext();\n\n // Register this tab's value in DOM order on first render.\n // Using a ref-mutation here avoids needing a reducer and is safe because\n // the tab list is stable (static children).\n if (!tabValues.current.includes(value)) {\n tabValues.current.push(value);\n }\n if (disabled) {\n disabledValues.add(value);\n } else {\n disabledValues.delete(value);\n }\n\n const isActive = activeValue === value;\n\n return (\n <button\n id={tabId(baseId, value)}\n type=\"button\"\n role=\"tab\"\n aria-selected={isActive}\n aria-controls={panelId(baseId, value)}\n aria-disabled={disabled || undefined}\n disabled={disabled}\n tabIndex={isActive ? 0 : -1}\n onClick={() => activate(value)}\n className={[\n 'relative px-5 py-3 text-sm font-semibold font-heading border-b-4 transition-colors',\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30',\n isActive\n ? 'border-brand-blue text-brand-blue'\n : disabled\n ? 'border-transparent text-slate-300 cursor-not-allowed'\n : 'border-transparent text-slate-500 hover:text-slate-700 hover:border-slate-300',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {children}\n </button>\n );\n}\n\n// ── TabPanels ─────────────────────────────────────────────────────────────────\n\nexport interface TabPanelsProps {\n children: ReactNode;\n className?: string;\n}\n\nexport function TabPanels({ children, className = '' }: TabPanelsProps) {\n return <div className={className}>{children}</div>;\n}\n\n// ── TabPanel ──────────────────────────────────────────────────────────────────\n\nexport interface TabPanelProps {\n /** Must match the value used in <Tab value=\"…\"> */\n value: string;\n children: ReactNode;\n className?: string;\n}\n\nexport function TabPanel({ value, children, className = '' }: TabPanelProps) {\n const { activeValue, baseId } = useTabsContext();\n\n if (activeValue !== value) return null;\n\n return (\n <div\n id={panelId(baseId, value)}\n role=\"tabpanel\"\n aria-labelledby={tabId(baseId, value)}\n tabIndex={0}\n className={[\n 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-brand-blue/30 rounded-sm',\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n >\n {children}\n </div>\n );\n}\n"],"mappings":"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"}
|