@estiva-app/ui 0.12.0 → 0.12.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.
- package/dist/AppShell.d.ts.map +1 -1
- package/dist/CollapsibleSection.d.ts +3 -1
- package/dist/CollapsibleSection.d.ts.map +1 -1
- package/dist/DialogShell.d.ts +14 -2
- package/dist/DialogShell.d.ts.map +1 -1
- package/dist/Field.d.ts +36 -0
- package/dist/Field.d.ts.map +1 -1
- package/dist/Popover.d.ts +11 -2
- package/dist/Popover.d.ts.map +1 -1
- package/dist/ScrollArea.d.ts +14 -2
- package/dist/ScrollArea.d.ts.map +1 -1
- package/dist/SectionHeader.d.ts +10 -1
- package/dist/SectionHeader.d.ts.map +1 -1
- package/dist/Toast.d.ts +17 -7
- package/dist/Toast.d.ts.map +1 -1
- package/dist/cn.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +138 -99
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
- package/src/AppShell.mdx +15 -0
- package/src/AppShell.stories.tsx +15 -0
- package/src/AppShell.test.tsx +39 -0
- package/src/AppShell.tsx +22 -7
- package/src/CollapsibleSection.tsx +4 -2
- package/src/DialogShell.mdx +9 -3
- package/src/DialogShell.stories.tsx +29 -0
- package/src/DialogShell.test.tsx +35 -0
- package/src/DialogShell.tsx +31 -4
- package/src/EmptyState.mdx +5 -4
- package/src/Field.mdx +3 -2
- package/src/Field.tsx +57 -2
- package/src/FieldLine.mdx +57 -0
- package/src/FieldLine.stories.tsx +80 -0
- package/src/FieldLine.test.tsx +56 -0
- package/src/Popover.mdx +3 -1
- package/src/Popover.stories.tsx +15 -0
- package/src/Popover.test.tsx +20 -0
- package/src/Popover.tsx +12 -3
- package/src/ScrollArea.mdx +5 -0
- package/src/ScrollArea.test.tsx +27 -1
- package/src/ScrollArea.tsx +16 -2
- package/src/SectionHeader.mdx +4 -0
- package/src/SectionHeader.stories.tsx +10 -1
- package/src/SectionHeader.test.tsx +25 -0
- package/src/SectionHeader.tsx +14 -1
- package/src/Toast.mdx +8 -2
- package/src/Toast.stories.tsx +13 -3
- package/src/Toast.tsx +44 -11
- package/src/cn.ts +1 -1
- package/src/index.ts +1 -1
- package/stories/Choosing.mdx +2 -0
- package/tailwind-preset.js +4 -0
package/dist/index.js
CHANGED
|
@@ -20,7 +20,7 @@ var FONT_SIZE_TOKENS = [
|
|
|
20
20
|
"chip"
|
|
21
21
|
];
|
|
22
22
|
var BOX_SHADOW_TOKENS = ["sm", "md", "lg", "focus-ring", "glow-warning", "glow-success", "glow-accent", "highlight-inset"];
|
|
23
|
-
var DROP_SHADOW_TOKENS = ["glow-success", "glow-accent"];
|
|
23
|
+
var DROP_SHADOW_TOKENS = ["glow-success", "glow-accent", "glow-warning"];
|
|
24
24
|
var twMerge = extendTailwindMerge({
|
|
25
25
|
extend: {
|
|
26
26
|
classGroups: {
|
|
@@ -34,11 +34,38 @@ function cn(...inputs) {
|
|
|
34
34
|
return twMerge(clsx(inputs));
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
// src/
|
|
37
|
+
// src/ScrollArea.tsx
|
|
38
|
+
import { ScrollArea as BaseScrollArea } from "@base-ui/react/scroll-area";
|
|
38
39
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
40
|
+
var BAR = "flex touch-none select-none rounded-full opacity-0 transition-opacity delay-300 data-[hovering]:opacity-100 data-[hovering]:delay-0 data-[scrolling]:opacity-100 data-[scrolling]:delay-0";
|
|
41
|
+
var THUMB = "rounded-full bg-border-strong";
|
|
42
|
+
function ScrollArea({ orientation = "vertical", className, viewportClassName, contentClassName, viewportRef, onScroll, children }) {
|
|
43
|
+
const vertical = orientation !== "horizontal";
|
|
44
|
+
const horizontal = orientation !== "vertical";
|
|
45
|
+
return /* @__PURE__ */ jsxs(BaseScrollArea.Root, { className: cn("relative min-h-0 min-w-0", className), children: [
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
BaseScrollArea.Viewport,
|
|
48
|
+
{
|
|
49
|
+
ref: viewportRef,
|
|
50
|
+
onScroll,
|
|
51
|
+
className: cn(
|
|
52
|
+
"h-full w-full outline-none data-[has-overflow-x]:overscroll-x-contain data-[has-overflow-y]:overscroll-y-contain",
|
|
53
|
+
viewportClassName
|
|
54
|
+
),
|
|
55
|
+
children: /* @__PURE__ */ jsx(BaseScrollArea.Content, { className: contentClassName, style: horizontal ? void 0 : { minWidth: 0 }, children })
|
|
56
|
+
}
|
|
57
|
+
),
|
|
58
|
+
vertical && /* @__PURE__ */ jsx(BaseScrollArea.Scrollbar, { orientation: "vertical", className: cn(BAR, "w-1.5 justify-center py-0.5 pr-0.5"), children: /* @__PURE__ */ jsx(BaseScrollArea.Thumb, { className: cn(THUMB, "w-full") }) }),
|
|
59
|
+
horizontal && /* @__PURE__ */ jsx(BaseScrollArea.Scrollbar, { orientation: "horizontal", className: cn(BAR, "h-1.5 flex-col justify-center px-0.5 pb-0.5"), children: /* @__PURE__ */ jsx(BaseScrollArea.Thumb, { className: cn(THUMB, "h-full") }) }),
|
|
60
|
+
vertical && horizontal && /* @__PURE__ */ jsx(BaseScrollArea.Corner, {})
|
|
61
|
+
] });
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/TopBar.tsx
|
|
65
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
39
66
|
function TopBar({ variant = "solid", menu, logo, search, right, className }) {
|
|
40
67
|
const floating = variant === "floating";
|
|
41
|
-
return /* @__PURE__ */
|
|
68
|
+
return /* @__PURE__ */ jsxs2(
|
|
42
69
|
"header",
|
|
43
70
|
{
|
|
44
71
|
className: cn(
|
|
@@ -47,27 +74,27 @@ function TopBar({ variant = "solid", menu, logo, search, right, className }) {
|
|
|
47
74
|
className
|
|
48
75
|
),
|
|
49
76
|
children: [
|
|
50
|
-
(menu || logo) && /* @__PURE__ */
|
|
77
|
+
(menu || logo) && /* @__PURE__ */ jsxs2("div", { className: cn("flex shrink-0 items-center gap-2", floating && "pointer-events-auto"), children: [
|
|
51
78
|
menu,
|
|
52
|
-
logo && /* @__PURE__ */
|
|
79
|
+
logo && /* @__PURE__ */ jsx2("div", { className: "flex items-center text-body-2-strong text-text-primary", children: logo })
|
|
53
80
|
] }),
|
|
54
|
-
/* @__PURE__ */
|
|
55
|
-
/* @__PURE__ */
|
|
81
|
+
/* @__PURE__ */ jsx2("div", { className: cn("flex min-w-0 flex-1 items-center justify-center", floating && "pointer-events-auto"), children: search }),
|
|
82
|
+
/* @__PURE__ */ jsx2("div", { className: cn("flex shrink-0 items-center gap-[6px]", floating && "pointer-events-auto"), children: right })
|
|
56
83
|
]
|
|
57
84
|
}
|
|
58
85
|
);
|
|
59
86
|
}
|
|
60
87
|
|
|
61
88
|
// src/AppShell.tsx
|
|
62
|
-
import { jsx as
|
|
89
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
63
90
|
function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav, children }) {
|
|
64
|
-
const bar = /* @__PURE__ */
|
|
91
|
+
const bar = /* @__PURE__ */ jsx3(TopBar, { variant, menu, logo, search, right: identity });
|
|
65
92
|
if (variant === "floating") {
|
|
66
|
-
return /* @__PURE__ */
|
|
93
|
+
return /* @__PURE__ */ jsxs3("div", { className: "relative h-full min-h-0 overflow-hidden bg-bg-base", children: [
|
|
67
94
|
bar,
|
|
68
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex h-full pb-4 pr-4 pt-[52px]", children: [
|
|
69
96
|
nav,
|
|
70
|
-
/* @__PURE__ */
|
|
97
|
+
/* @__PURE__ */ jsxs3(
|
|
71
98
|
"div",
|
|
72
99
|
{
|
|
73
100
|
className: cn(
|
|
@@ -76,7 +103,7 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
76
103
|
),
|
|
77
104
|
children: [
|
|
78
105
|
banner,
|
|
79
|
-
/* @__PURE__ */
|
|
106
|
+
/* @__PURE__ */ jsx3("main", { className: "flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden", children })
|
|
80
107
|
]
|
|
81
108
|
}
|
|
82
109
|
)
|
|
@@ -84,20 +111,22 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
84
111
|
] });
|
|
85
112
|
}
|
|
86
113
|
return (
|
|
87
|
-
/* `relative overflow-hidden` is the seal the floating manner already has
|
|
114
|
+
/* `relative overflow-hidden` is the seal the floating manner already has
|
|
115
|
+
(and the ScrollArea's own root is `relative`, so an absolutely placed
|
|
116
|
+
stray inside a page now belongs to the region and scrolls with it),
|
|
88
117
|
and it takes both halves: an absolutely positioned descendant with no
|
|
89
118
|
positioned ancestor belongs to the *viewport*, so a scroll container
|
|
90
119
|
never clips it and the document itself gains its position as scroll
|
|
91
120
|
range — the whole page scrolls, navigation and top bar included.
|
|
92
121
|
`relative` claims such strays for the shell; `overflow-hidden` clips
|
|
93
122
|
them at its edge. Either alone seals nothing. */
|
|
94
|
-
/* @__PURE__ */
|
|
123
|
+
/* @__PURE__ */ jsxs3("div", { className: "relative flex h-full min-h-0 flex-col overflow-hidden bg-bg-base text-text-primary", children: [
|
|
95
124
|
bar,
|
|
96
|
-
/* @__PURE__ */
|
|
125
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 flex-1", children: [
|
|
97
126
|
nav,
|
|
98
|
-
/* @__PURE__ */
|
|
127
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex min-h-0 min-w-0 flex-1 flex-col", children: [
|
|
99
128
|
banner,
|
|
100
|
-
/* @__PURE__ */
|
|
129
|
+
/* @__PURE__ */ jsx3(ScrollArea, { className: "min-h-0 flex-1", contentClassName: "flex min-h-full flex-col", children: /* @__PURE__ */ jsx3("main", { className: "flex min-w-0 flex-1 flex-col", children }) })
|
|
101
130
|
] })
|
|
102
131
|
] })
|
|
103
132
|
] })
|
|
@@ -107,7 +136,7 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
107
136
|
// src/Avatar.tsx
|
|
108
137
|
import { useState } from "react";
|
|
109
138
|
import { IconUserFilled } from "@tabler/icons-react";
|
|
110
|
-
import { jsx as
|
|
139
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
111
140
|
var HUES = ["#56c8ff", "#ff8f6b", "#4ade8c", "#b18cff", "#ffc94d", "#ff7eb0", "#7ea8ff", "#5fdfd6"];
|
|
112
141
|
var hueFor = (key) => {
|
|
113
142
|
let h = 0;
|
|
@@ -123,13 +152,13 @@ function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
|
|
|
123
152
|
const [broken, setBroken] = useState(false);
|
|
124
153
|
const label = name || alt;
|
|
125
154
|
const picture = src && !broken ? src : void 0;
|
|
126
|
-
return /* @__PURE__ */
|
|
155
|
+
return /* @__PURE__ */ jsx4(
|
|
127
156
|
"div",
|
|
128
157
|
{
|
|
129
158
|
...spoken ? { role: "img", "aria-label": spoken } : { "aria-hidden": true },
|
|
130
159
|
className: cn("rounded-sm overflow-hidden shrink-0 bg-bg-inset", className),
|
|
131
160
|
style: { width: size, height: size },
|
|
132
|
-
children: picture ? /* @__PURE__ */
|
|
161
|
+
children: picture ? /* @__PURE__ */ jsx4("img", { src: picture, alt: "", className: "w-full h-full object-cover", onError: () => setBroken(true) }) : label ? /* @__PURE__ */ jsx4(
|
|
133
162
|
"div",
|
|
134
163
|
{
|
|
135
164
|
className: "w-full h-full flex items-center justify-center font-semibold leading-none",
|
|
@@ -143,29 +172,29 @@ function Avatar({ src, name, alt = "", size = 36, label: spoken, className }) {
|
|
|
143
172
|
},
|
|
144
173
|
children: initialsFor(label)
|
|
145
174
|
}
|
|
146
|
-
) : /* @__PURE__ */
|
|
175
|
+
) : /* @__PURE__ */ jsx4("div", { className: "w-full h-full bg-accent-muted flex items-center justify-center text-text-muted", children: /* @__PURE__ */ jsx4(IconUserFilled, { size: Math.round(size * 0.5) }) })
|
|
147
176
|
}
|
|
148
177
|
);
|
|
149
178
|
}
|
|
150
179
|
|
|
151
180
|
// src/AvatarGroup.tsx
|
|
152
|
-
import { jsx as
|
|
181
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
153
182
|
function AvatarGroup({ members, size = 24 }) {
|
|
154
183
|
const visible = members.slice(0, 3);
|
|
155
184
|
const overlap = Math.round(size / 3);
|
|
156
185
|
const ring = size / 12;
|
|
157
|
-
return /* @__PURE__ */
|
|
186
|
+
return /* @__PURE__ */ jsx5("div", { className: "flex items-center", style: { paddingRight: overlap }, children: visible.map((member, i) => (
|
|
158
187
|
/*
|
|
159
188
|
The wrapper carries the overlap and the ring; the face carries
|
|
160
189
|
neither. It must never clip — see the note at the top of the file —
|
|
161
190
|
so it has the avatar's own radius and no overflow of its own.
|
|
162
191
|
*/
|
|
163
|
-
/* @__PURE__ */
|
|
192
|
+
/* @__PURE__ */ jsx5(
|
|
164
193
|
"span",
|
|
165
194
|
{
|
|
166
195
|
className: "relative flex rounded-sm",
|
|
167
196
|
style: { marginRight: -overlap, boxShadow: `0 0 0 ${ring}px var(--bg-surface)` },
|
|
168
|
-
children: /* @__PURE__ */
|
|
197
|
+
children: /* @__PURE__ */ jsx5(Avatar, { size, name: member.name, src: member.picture, label: member.name })
|
|
169
198
|
},
|
|
170
199
|
i
|
|
171
200
|
)
|
|
@@ -182,9 +211,9 @@ import { Button as BaseButton } from "@base-ui/react/button";
|
|
|
182
211
|
import { Tooltip as BaseTooltip } from "@base-ui/react/tooltip";
|
|
183
212
|
|
|
184
213
|
// src/Kbd.tsx
|
|
185
|
-
import { jsx as
|
|
214
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
186
215
|
function Kbd({ children, className }) {
|
|
187
|
-
return /* @__PURE__ */
|
|
216
|
+
return /* @__PURE__ */ jsx6(
|
|
188
217
|
"kbd",
|
|
189
218
|
{
|
|
190
219
|
className: cn(
|
|
@@ -199,21 +228,21 @@ function Kbd({ children, className }) {
|
|
|
199
228
|
}
|
|
200
229
|
|
|
201
230
|
// src/Tooltip.tsx
|
|
202
|
-
import { jsx as
|
|
231
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
203
232
|
var OPEN_DELAY = 300;
|
|
204
233
|
function TooltipProvider({ delay = OPEN_DELAY, closeDelay, timeout, children }) {
|
|
205
|
-
return /* @__PURE__ */
|
|
234
|
+
return /* @__PURE__ */ jsx7(BaseTooltip.Provider, { delay, closeDelay, timeout, children });
|
|
206
235
|
}
|
|
207
236
|
function Tooltip({ label, shortcut, className, ...props }) {
|
|
208
|
-
return /* @__PURE__ */
|
|
209
|
-
/* @__PURE__ */
|
|
210
|
-
shortcut && /* @__PURE__ */
|
|
237
|
+
return /* @__PURE__ */ jsxs4("div", { role: "tooltip", className: cn("bg-bg-elevated border border-border-default rounded-lg h-[30px] flex items-center justify-center gap-1.5 px-2 shadow-lg", className), ...props, children: [
|
|
238
|
+
/* @__PURE__ */ jsx7("span", { className: "text-caption text-text-primary whitespace-nowrap", children: label }),
|
|
239
|
+
shortcut && /* @__PURE__ */ jsx7(Kbd, { children: shortcut })
|
|
211
240
|
] });
|
|
212
241
|
}
|
|
213
242
|
var GAP = 6;
|
|
214
243
|
var VIEWPORT_PAD = 8;
|
|
215
244
|
function TooltipSurface({ label, shortcut, placement }) {
|
|
216
|
-
return /* @__PURE__ */
|
|
245
|
+
return /* @__PURE__ */ jsx7(BaseTooltip.Portal, { children: /* @__PURE__ */ jsx7(
|
|
217
246
|
BaseTooltip.Positioner,
|
|
218
247
|
{
|
|
219
248
|
side: placement,
|
|
@@ -222,10 +251,10 @@ function TooltipSurface({ label, shortcut, placement }) {
|
|
|
222
251
|
collisionPadding: VIEWPORT_PAD,
|
|
223
252
|
positionMethod: "fixed",
|
|
224
253
|
className: "pointer-events-none z-[9999]",
|
|
225
|
-
children: /* @__PURE__ */
|
|
254
|
+
children: /* @__PURE__ */ jsx7(
|
|
226
255
|
BaseTooltip.Popup,
|
|
227
256
|
{
|
|
228
|
-
render: /* @__PURE__ */
|
|
257
|
+
render: /* @__PURE__ */ jsx7(
|
|
229
258
|
Tooltip,
|
|
230
259
|
{
|
|
231
260
|
label,
|
|
@@ -245,20 +274,20 @@ function TooltipSurface({ label, shortcut, placement }) {
|
|
|
245
274
|
) });
|
|
246
275
|
}
|
|
247
276
|
function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, children }) {
|
|
248
|
-
return /* @__PURE__ */
|
|
249
|
-
/* @__PURE__ */
|
|
250
|
-
/* @__PURE__ */
|
|
277
|
+
return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
|
|
278
|
+
/* @__PURE__ */ jsx7(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: /* @__PURE__ */ jsx7("div", { className: cn("inline-flex shrink-0", wrapperClassName) }), children }),
|
|
279
|
+
/* @__PURE__ */ jsx7(TooltipSurface, { label, shortcut, placement })
|
|
251
280
|
] });
|
|
252
281
|
}
|
|
253
282
|
function TooltipTrigger({ label, shortcut, placement = "top", children }) {
|
|
254
|
-
return /* @__PURE__ */
|
|
255
|
-
/* @__PURE__ */
|
|
256
|
-
/* @__PURE__ */
|
|
283
|
+
return /* @__PURE__ */ jsxs4(BaseTooltip.Root, { disableHoverablePopup: true, children: [
|
|
284
|
+
/* @__PURE__ */ jsx7(BaseTooltip.Trigger, { delay: OPEN_DELAY, render: children }),
|
|
285
|
+
/* @__PURE__ */ jsx7(TooltipSurface, { label, shortcut, placement })
|
|
257
286
|
] });
|
|
258
287
|
}
|
|
259
288
|
|
|
260
289
|
// src/IconButton.tsx
|
|
261
|
-
import { jsx as
|
|
290
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
262
291
|
function IconButton({
|
|
263
292
|
variant = "muted",
|
|
264
293
|
className,
|
|
@@ -271,7 +300,7 @@ function IconButton({
|
|
|
271
300
|
type = "button",
|
|
272
301
|
...props
|
|
273
302
|
}) {
|
|
274
|
-
const button = /* @__PURE__ */
|
|
303
|
+
const button = /* @__PURE__ */ jsx8(
|
|
275
304
|
BaseButton,
|
|
276
305
|
{
|
|
277
306
|
type,
|
|
@@ -299,13 +328,13 @@ function IconButton({
|
|
|
299
328
|
);
|
|
300
329
|
const label = disabledReason ?? tooltip;
|
|
301
330
|
if (label) {
|
|
302
|
-
return /* @__PURE__ */
|
|
331
|
+
return /* @__PURE__ */ jsx8(TooltipTrigger, { label, shortcut: disabledReason ? void 0 : tooltipShortcut, placement: tooltipPlacement, children: button });
|
|
303
332
|
}
|
|
304
333
|
return button;
|
|
305
334
|
}
|
|
306
335
|
|
|
307
336
|
// src/Banner.tsx
|
|
308
|
-
import { jsx as
|
|
337
|
+
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
309
338
|
var TONE_STYLES = {
|
|
310
339
|
ok: "bg-success-muted text-success-default",
|
|
311
340
|
error: "bg-error-muted text-error-default",
|
|
@@ -315,17 +344,17 @@ var TONE_STYLES = {
|
|
|
315
344
|
function Banner({ tone, children, onDismiss, dismissLabel = "Dismiss", className }) {
|
|
316
345
|
const role = tone === "error" ? "alert" : "status";
|
|
317
346
|
if (!onDismiss) {
|
|
318
|
-
return /* @__PURE__ */
|
|
347
|
+
return /* @__PURE__ */ jsx9("div", { role, className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
|
|
319
348
|
}
|
|
320
|
-
return /* @__PURE__ */
|
|
321
|
-
/* @__PURE__ */
|
|
322
|
-
/* @__PURE__ */
|
|
349
|
+
return /* @__PURE__ */ jsxs5("div", { role, className: cn("flex items-center gap-3 px-4 py-2 text-body-2", TONE_STYLES[tone], className), children: [
|
|
350
|
+
/* @__PURE__ */ jsx9("span", { className: "min-w-0 flex-1", children }),
|
|
351
|
+
/* @__PURE__ */ jsx9(IconButton, { "aria-label": dismissLabel, onClick: onDismiss, className: "-mr-1 shrink-0 text-current hover:text-current", children: /* @__PURE__ */ jsx9(IconX, { size: 16, stroke: 1.5 }) })
|
|
323
352
|
] });
|
|
324
353
|
}
|
|
325
354
|
|
|
326
355
|
// src/Button.tsx
|
|
327
356
|
import { Button as BaseButton2 } from "@base-ui/react/button";
|
|
328
|
-
import { jsx as
|
|
357
|
+
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
329
358
|
function Button({
|
|
330
359
|
variant = "muted",
|
|
331
360
|
size = "default",
|
|
@@ -338,7 +367,7 @@ function Button({
|
|
|
338
367
|
...props
|
|
339
368
|
}) {
|
|
340
369
|
const hasLeadingIcon = !!leadingIcon;
|
|
341
|
-
const button = /* @__PURE__ */
|
|
370
|
+
const button = /* @__PURE__ */ jsxs6(
|
|
342
371
|
BaseButton2,
|
|
343
372
|
{
|
|
344
373
|
type,
|
|
@@ -372,13 +401,13 @@ function Button({
|
|
|
372
401
|
]
|
|
373
402
|
}
|
|
374
403
|
);
|
|
375
|
-
return disabledReason ? /* @__PURE__ */
|
|
404
|
+
return disabledReason ? /* @__PURE__ */ jsx10(TooltipTrigger, { label: disabledReason, children: button }) : button;
|
|
376
405
|
}
|
|
377
406
|
|
|
378
407
|
// src/Checkbox.tsx
|
|
379
408
|
import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
|
|
380
409
|
import { IconCheck } from "@tabler/icons-react";
|
|
381
|
-
import { jsx as
|
|
410
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
382
411
|
function squareClasses(checked, disabled, interactive, className) {
|
|
383
412
|
return cn(
|
|
384
413
|
"inline-flex items-center justify-center size-4 shrink-0 rounded-[4px] border transition-colors",
|
|
@@ -391,9 +420,9 @@ function squareClasses(checked, disabled, interactive, className) {
|
|
|
391
420
|
var tickClasses = (checked) => cn("flex", !checked && "invisible");
|
|
392
421
|
function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
|
|
393
422
|
if (!onChange) {
|
|
394
|
-
return /* @__PURE__ */
|
|
423
|
+
return /* @__PURE__ */ jsx11("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx11("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx11(IconCheck, { size: 12, stroke: 3 }) }) });
|
|
395
424
|
}
|
|
396
|
-
return /* @__PURE__ */
|
|
425
|
+
return /* @__PURE__ */ jsx11(
|
|
397
426
|
BaseCheckbox.Root,
|
|
398
427
|
{
|
|
399
428
|
checked,
|
|
@@ -403,13 +432,13 @@ function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
|
|
|
403
432
|
onCheckedChange: (next) => onChange(next),
|
|
404
433
|
onClick: (e) => e.stopPropagation(),
|
|
405
434
|
className: (state) => squareClasses(state.checked, state.disabled, true, className),
|
|
406
|
-
children: /* @__PURE__ */
|
|
435
|
+
children: /* @__PURE__ */ jsx11(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx11(IconCheck, { size: 12, stroke: 3 }) })
|
|
407
436
|
}
|
|
408
437
|
);
|
|
409
438
|
}
|
|
410
439
|
|
|
411
440
|
// src/Chip.tsx
|
|
412
|
-
import { jsx as
|
|
441
|
+
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
413
442
|
var typeStyles = {
|
|
414
443
|
neutral: "bg-bg-inset text-text-primary",
|
|
415
444
|
brand: "bg-accent-muted text-accent-primary signal:border signal:border-accent-outline",
|
|
@@ -419,8 +448,8 @@ var typeStyles = {
|
|
|
419
448
|
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
420
449
|
};
|
|
421
450
|
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className }) {
|
|
422
|
-
return /* @__PURE__ */
|
|
423
|
-
leadingIcon && /* @__PURE__ */
|
|
451
|
+
return /* @__PURE__ */ jsxs7("div", { className: cn("inline-flex min-w-0 items-center justify-center gap-1.5 rounded-full max-h-[20px] px-2 py-1", typeStyles[type], className), children: [
|
|
452
|
+
leadingIcon && /* @__PURE__ */ jsx12("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
424
453
|
label && // A chip given a `max-w-*` cuts a long label with an ellipsis instead
|
|
425
454
|
// of growing past it — Ship's project chip on an issue row
|
|
426
455
|
// (2026-09-09). Clipped sideways only: `overflow-x-clip`, not
|
|
@@ -429,8 +458,8 @@ function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className })
|
|
|
429
458
|
// the screenshot diff caught every descender cut off. `clip` is the
|
|
430
459
|
// one overflow that leaves the other axis visible. A chip with no cap
|
|
431
460
|
// draws exactly as before.
|
|
432
|
-
/* @__PURE__ */
|
|
433
|
-
trailingIcon && /* @__PURE__ */
|
|
461
|
+
/* @__PURE__ */ jsx12("span", { className: "min-w-0 overflow-x-clip text-ellipsis whitespace-nowrap text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tracking-[0.02em] signal:tabular-nums", children: label }),
|
|
462
|
+
trailingIcon && /* @__PURE__ */ jsx12("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
|
|
434
463
|
] });
|
|
435
464
|
}
|
|
436
465
|
|
|
@@ -467,31 +496,6 @@ function triggerDisabled(trigger) {
|
|
|
467
496
|
return !!(props.disabled || props.disabledReason);
|
|
468
497
|
}
|
|
469
498
|
|
|
470
|
-
// src/ScrollArea.tsx
|
|
471
|
-
import { ScrollArea as BaseScrollArea } from "@base-ui/react/scroll-area";
|
|
472
|
-
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
473
|
-
var BAR = "flex touch-none select-none rounded-full opacity-0 transition-opacity delay-300 data-[hovering]:opacity-100 data-[hovering]:delay-0 data-[scrolling]:opacity-100 data-[scrolling]:delay-0";
|
|
474
|
-
var THUMB = "rounded-full bg-border-strong";
|
|
475
|
-
function ScrollArea({ orientation = "vertical", className, viewportClassName, contentClassName, children }) {
|
|
476
|
-
const vertical = orientation !== "horizontal";
|
|
477
|
-
const horizontal = orientation !== "vertical";
|
|
478
|
-
return /* @__PURE__ */ jsxs7(BaseScrollArea.Root, { className: cn("relative min-h-0 min-w-0", className), children: [
|
|
479
|
-
/* @__PURE__ */ jsx12(
|
|
480
|
-
BaseScrollArea.Viewport,
|
|
481
|
-
{
|
|
482
|
-
className: cn(
|
|
483
|
-
"h-full w-full outline-none data-[has-overflow-x]:overscroll-x-contain data-[has-overflow-y]:overscroll-y-contain",
|
|
484
|
-
viewportClassName
|
|
485
|
-
),
|
|
486
|
-
children: /* @__PURE__ */ jsx12(BaseScrollArea.Content, { className: contentClassName, style: horizontal ? void 0 : { minWidth: 0 }, children })
|
|
487
|
-
}
|
|
488
|
-
),
|
|
489
|
-
vertical && /* @__PURE__ */ jsx12(BaseScrollArea.Scrollbar, { orientation: "vertical", className: cn(BAR, "w-1.5 justify-center py-0.5 pr-0.5"), children: /* @__PURE__ */ jsx12(BaseScrollArea.Thumb, { className: cn(THUMB, "w-full") }) }),
|
|
490
|
-
horizontal && /* @__PURE__ */ jsx12(BaseScrollArea.Scrollbar, { orientation: "horizontal", className: cn(BAR, "h-1.5 flex-col justify-center px-0.5 pb-0.5"), children: /* @__PURE__ */ jsx12(BaseScrollArea.Thumb, { className: cn(THUMB, "h-full") }) }),
|
|
491
|
-
vertical && horizontal && /* @__PURE__ */ jsx12(BaseScrollArea.Corner, {})
|
|
492
|
-
] });
|
|
493
|
-
}
|
|
494
|
-
|
|
495
499
|
// src/SectionLabel.tsx
|
|
496
500
|
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
497
501
|
function SectionLabel({ children, className }) {
|
|
@@ -1088,6 +1092,11 @@ function Note({ children }) {
|
|
|
1088
1092
|
import { cloneElement, isValidElement } from "react";
|
|
1089
1093
|
import { Field as BaseField } from "@base-ui/react/field";
|
|
1090
1094
|
import { jsx as jsx20, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1095
|
+
var LINE_STYLES = {
|
|
1096
|
+
helper: "text-caption text-text-muted",
|
|
1097
|
+
warning: "text-caption text-warning-default",
|
|
1098
|
+
error: "text-caption text-error-default"
|
|
1099
|
+
};
|
|
1091
1100
|
function Field({ label, required = false, helper, error, children }) {
|
|
1092
1101
|
const control = required && isValidElement(children) ? cloneElement(children, {
|
|
1093
1102
|
"aria-required": children.props["aria-required"] ?? true
|
|
@@ -1099,10 +1108,13 @@ function Field({ label, required = false, helper, error, children }) {
|
|
|
1099
1108
|
] }),
|
|
1100
1109
|
/* @__PURE__ */ jsxs14("div", { className: "flex flex-col gap-1.5", children: [
|
|
1101
1110
|
control,
|
|
1102
|
-
error != null ? /* @__PURE__ */ jsx20(BaseField.Error, { match: true, className:
|
|
1111
|
+
error != null ? /* @__PURE__ */ jsx20(BaseField.Error, { match: true, className: LINE_STYLES.error, children: error }) : helper != null ? /* @__PURE__ */ jsx20(BaseField.Description, { className: LINE_STYLES.helper, children: helper }) : null
|
|
1103
1112
|
] })
|
|
1104
1113
|
] });
|
|
1105
1114
|
}
|
|
1115
|
+
function FieldLine({ tone = "helper", children, className }) {
|
|
1116
|
+
return /* @__PURE__ */ jsx20("p", { role: tone === "error" ? "alert" : "status", className: cn(LINE_STYLES[tone], className), children });
|
|
1117
|
+
}
|
|
1106
1118
|
|
|
1107
1119
|
// src/Select.tsx
|
|
1108
1120
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
@@ -1257,7 +1269,7 @@ import { Dialog } from "@base-ui/react/dialog";
|
|
|
1257
1269
|
import { AlertDialog } from "@base-ui/react/alert-dialog";
|
|
1258
1270
|
import { IconX as IconX3 } from "@tabler/icons-react";
|
|
1259
1271
|
import { jsx as jsx24, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1260
|
-
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, width = 502, alert = false }) {
|
|
1272
|
+
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, bodyMaxHeight, width = 502, alert = false }) {
|
|
1261
1273
|
const Parts = alert ? AlertDialog : Dialog;
|
|
1262
1274
|
const popupRef = useRef3(null);
|
|
1263
1275
|
return /* @__PURE__ */ jsx24(
|
|
@@ -1287,7 +1299,15 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1287
1299
|
}
|
|
1288
1300
|
)
|
|
1289
1301
|
] }),
|
|
1290
|
-
/* @__PURE__ */ jsx24(
|
|
1302
|
+
bodyMaxHeight ? /* @__PURE__ */ jsx24(
|
|
1303
|
+
ScrollArea,
|
|
1304
|
+
{
|
|
1305
|
+
className: cn(footer != null && "border-b border-border-subtle"),
|
|
1306
|
+
viewportClassName: bodyMaxHeight,
|
|
1307
|
+
contentClassName: cn("pl-5 pr-4 py-4", bodyClassName),
|
|
1308
|
+
children
|
|
1309
|
+
}
|
|
1310
|
+
) : /* @__PURE__ */ jsx24("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
1291
1311
|
footer != null && /* @__PURE__ */ jsx24("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1292
1312
|
]
|
|
1293
1313
|
}
|
|
@@ -1573,7 +1593,7 @@ function Popover({ trigger, anchor, align = "left", side = "bottom", open, onOpe
|
|
|
1573
1593
|
{
|
|
1574
1594
|
anchor: anchorTarget,
|
|
1575
1595
|
side,
|
|
1576
|
-
align: align === "right" ? "end" : "start",
|
|
1596
|
+
align: align === "right" ? "end" : align === "center" ? "center" : "start",
|
|
1577
1597
|
sideOffset: GAP5,
|
|
1578
1598
|
collisionPadding: VIEWPORT_PAD4,
|
|
1579
1599
|
className: "z-50 data-[anchor-hidden]:hidden",
|
|
@@ -1843,7 +1863,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1843
1863
|
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
1844
1864
|
import { useRender } from "@base-ui/react/use-render";
|
|
1845
1865
|
import { Fragment as Fragment5, jsx as jsx41, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
1846
|
-
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, actions, showActions = "hover", render, className }) {
|
|
1866
|
+
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, trailing, actions, showActions = "hover", render, className }) {
|
|
1847
1867
|
const titleElement = useRender({
|
|
1848
1868
|
render: render ?? (chevron ? /* @__PURE__ */ jsx41("button", { type: "button", onClick: onToggle, "aria-expanded": isExpanded }) : /* @__PURE__ */ jsx41("span", {})),
|
|
1849
1869
|
props: {
|
|
@@ -1877,6 +1897,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
|
|
|
1877
1897
|
),
|
|
1878
1898
|
children: [
|
|
1879
1899
|
titleElement,
|
|
1900
|
+
trailing != null && /* @__PURE__ */ jsx41("div", { className: "flex shrink-0 items-center", children: trailing }),
|
|
1880
1901
|
actions && actions.length > 0 && /* @__PURE__ */ jsx41(
|
|
1881
1902
|
"div",
|
|
1882
1903
|
{
|
|
@@ -1914,7 +1935,7 @@ function writeStored(key, open) {
|
|
|
1914
1935
|
} catch {
|
|
1915
1936
|
}
|
|
1916
1937
|
}
|
|
1917
|
-
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, actions, showActions, children, className, contentClassName }) {
|
|
1938
|
+
function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenChange, storageKey, trailing, actions, showActions, children, className, contentClassName }) {
|
|
1918
1939
|
const [openState, setOpenState] = useState6(() => readStored(storageKey) ?? defaultOpen);
|
|
1919
1940
|
const open = openProp ?? openState;
|
|
1920
1941
|
const setOpen = (next) => {
|
|
@@ -1923,7 +1944,7 @@ function CollapsibleSection({ title, defaultOpen = true, open: openProp, onOpenC
|
|
|
1923
1944
|
onOpenChange?.(next);
|
|
1924
1945
|
};
|
|
1925
1946
|
return /* @__PURE__ */ jsxs29(Collapsible.Root, { open, onOpenChange: setOpen, className: cn("flex flex-col", className), children: [
|
|
1926
|
-
/* @__PURE__ */ jsx42(SectionHeader, { title, chevron: true, isExpanded: open, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx42(Collapsible.Trigger, {}) }),
|
|
1947
|
+
/* @__PURE__ */ jsx42(SectionHeader, { title, chevron: true, isExpanded: open, trailing, actions, showActions, className: "shrink-0", render: /* @__PURE__ */ jsx42(Collapsible.Trigger, {}) }),
|
|
1927
1948
|
/* @__PURE__ */ jsx42(
|
|
1928
1949
|
Collapsible.Panel,
|
|
1929
1950
|
{
|
|
@@ -1984,25 +2005,42 @@ function Tabs({ tabs, active, onChange, size = "default", className, ...aria })
|
|
|
1984
2005
|
// src/Toast.tsx
|
|
1985
2006
|
import { createContext as createContext2, useCallback as useCallback3, useContext as useContext2, useEffect as useEffect3, useMemo as useMemo3, useState as useState7 } from "react";
|
|
1986
2007
|
import { createPortal as createPortal2 } from "react-dom";
|
|
1987
|
-
import { IconCircleCheck } from "@tabler/icons-react";
|
|
2008
|
+
import { IconAlertCircle, IconCircleCheck, IconCircleX } from "@tabler/icons-react";
|
|
1988
2009
|
import { jsx as jsx44, jsxs as jsxs31 } from "react/jsx-runtime";
|
|
1989
2010
|
var SURFACE_STYLES = {
|
|
1990
2011
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
1991
2012
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
1992
|
-
neutral: "bg-bg-inset border border-border-subtle signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]"
|
|
2013
|
+
neutral: "bg-bg-inset border border-border-subtle signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
2014
|
+
warning: "bg-warning-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
2015
|
+
error: "bg-error-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]"
|
|
2016
|
+
};
|
|
2017
|
+
var ICONS = {
|
|
2018
|
+
success: IconCircleCheck,
|
|
2019
|
+
brand: IconCircleCheck,
|
|
2020
|
+
neutral: IconCircleCheck,
|
|
2021
|
+
warning: IconAlertCircle,
|
|
2022
|
+
error: IconCircleX
|
|
1993
2023
|
};
|
|
1994
2024
|
var ICON_STYLES = {
|
|
1995
2025
|
success: "signal:text-success-default signal:drop-shadow-glow-success",
|
|
1996
2026
|
brand: "signal:text-text-interactive signal:drop-shadow-glow-accent",
|
|
1997
|
-
neutral: "signal:text-text-secondary"
|
|
2027
|
+
neutral: "signal:text-text-secondary",
|
|
2028
|
+
warning: "signal:text-warning-default signal:drop-shadow-glow-warning",
|
|
2029
|
+
// No glow: the theme defines `--glow-warning`, `--glow-success` and
|
|
2030
|
+
// `--glow-accent` and no error glow, and a colour with no token is not
|
|
2031
|
+
// approximated here (D16).
|
|
2032
|
+
error: "signal:text-error-default"
|
|
1998
2033
|
};
|
|
1999
2034
|
var ACTION_BORDER_STYLES = {
|
|
2000
2035
|
success: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
2001
2036
|
brand: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
2002
|
-
neutral: "border border-border-default"
|
|
2037
|
+
neutral: "border border-border-default",
|
|
2038
|
+
warning: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
2039
|
+
error: "signal:border signal:border-border-default signal:hover:border-border-strong"
|
|
2003
2040
|
};
|
|
2004
2041
|
function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAction, className }) {
|
|
2005
2042
|
const hasAction = !!(actionLabel && onAction);
|
|
2043
|
+
const LeadingIcon = ICONS[type];
|
|
2006
2044
|
return /* @__PURE__ */ jsxs31(
|
|
2007
2045
|
"div",
|
|
2008
2046
|
{
|
|
@@ -2016,7 +2054,7 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
|
|
|
2016
2054
|
),
|
|
2017
2055
|
children: [
|
|
2018
2056
|
/* @__PURE__ */ jsxs31("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
2019
|
-
leadingIcon && /* @__PURE__ */ jsx44(
|
|
2057
|
+
leadingIcon && /* @__PURE__ */ jsx44(LeadingIcon, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) }),
|
|
2020
2058
|
/* @__PURE__ */ jsx44("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
|
|
2021
2059
|
] }),
|
|
2022
2060
|
hasAction && /* @__PURE__ */ jsx44(
|
|
@@ -2100,6 +2138,7 @@ export {
|
|
|
2100
2138
|
EmptyState,
|
|
2101
2139
|
EnterHint,
|
|
2102
2140
|
Field,
|
|
2141
|
+
FieldLine,
|
|
2103
2142
|
IconButton,
|
|
2104
2143
|
IdentityMenu,
|
|
2105
2144
|
IdentityPanel,
|