@estiva-app/ui 0.7.0 → 0.9.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 +23 -6
- package/dist/Button.d.ts +12 -5
- package/dist/Button.d.ts.map +1 -1
- package/dist/Checkbox.d.ts +19 -5
- package/dist/Checkbox.d.ts.map +1 -1
- package/dist/IconButton.d.ts +9 -2
- package/dist/IconButton.d.ts.map +1 -1
- package/dist/PersonTrigger.d.ts +2 -1
- package/dist/PersonTrigger.d.ts.map +1 -1
- package/dist/Tabs.d.ts +4 -1
- package/dist/Tabs.d.ts.map +1 -1
- package/dist/cn.d.ts +10 -1
- package/dist/cn.d.ts.map +1 -1
- package/dist/index.js +353 -326
- package/dist/index.js.map +4 -4
- package/package.json +17 -3
- package/src/AppShell.stories.tsx +7 -1
- package/src/AppShell.tsx +1 -1
- package/src/Avatar.stories.tsx +3 -1
- package/src/Banner.stories.tsx +6 -1
- package/src/Banner.tsx +2 -2
- package/src/Breadcrumb.stories.tsx +3 -0
- package/src/Button.mdx +17 -3
- package/src/Button.stories.tsx +4 -1
- package/src/Button.test.tsx +119 -0
- package/src/Button.tsx +37 -23
- package/src/Checkbox.mdx +17 -6
- package/src/Checkbox.stories.tsx +10 -5
- package/src/Checkbox.test.tsx +73 -0
- package/src/Checkbox.tsx +52 -25
- package/src/Chip.stories.tsx +4 -0
- package/src/Chip.tsx +5 -5
- package/src/ChipInput.stories.tsx +4 -0
- package/src/DialogShell.tsx +1 -1
- package/src/EditableText.stories.tsx +6 -1
- package/src/IconButton.mdx +12 -1
- package/src/IconButton.stories.tsx +9 -4
- package/src/IconButton.test.tsx +102 -0
- package/src/IconButton.tsx +30 -17
- package/src/IdentityMenu.stories.tsx +5 -1
- package/src/Kbd.tsx +2 -2
- package/src/NavItem.stories.tsx +3 -0
- package/src/Person.stories.tsx +3 -0
- package/src/PersonTrigger.mdx +9 -1
- package/src/PersonTrigger.stories.tsx +3 -0
- package/src/PersonTrigger.test.tsx +52 -0
- package/src/PersonTrigger.tsx +8 -9
- package/src/Select.stories.tsx +7 -2
- package/src/Sidebar.stories.tsx +6 -0
- package/src/Tabs.mdx +13 -4
- package/src/Tabs.test.tsx +117 -0
- package/src/Tabs.tsx +45 -34
- package/src/Toast.tsx +8 -8
- package/src/TopBar.stories.tsx +7 -1
- package/src/cn.test.ts +20 -1
- package/src/cn.ts +18 -2
- package/stories/Choosing.mdx +101 -0
- package/stories/DesignTokens.mdx +10 -0
- package/stories/GettingStarted.mdx +108 -0
- package/stories/Introduction.mdx +36 -0
- package/stories/TokensPage.tsx +297 -0
- package/tailwind-preset.js +22 -0
- package/tokens.css +56 -0
package/dist/index.js
CHANGED
|
@@ -19,8 +19,16 @@ var FONT_SIZE_TOKENS = [
|
|
|
19
19
|
"input-helper",
|
|
20
20
|
"chip"
|
|
21
21
|
];
|
|
22
|
+
var BOX_SHADOW_TOKENS = ["sm", "md", "lg", "focus-ring", "glow-warning", "highlight-inset"];
|
|
23
|
+
var DROP_SHADOW_TOKENS = ["glow-success", "glow-accent"];
|
|
22
24
|
var twMerge = extendTailwindMerge({
|
|
23
|
-
extend: {
|
|
25
|
+
extend: {
|
|
26
|
+
classGroups: {
|
|
27
|
+
"font-size": [{ text: FONT_SIZE_TOKENS }],
|
|
28
|
+
shadow: [{ shadow: BOX_SHADOW_TOKENS }],
|
|
29
|
+
"drop-shadow": [{ "drop-shadow": DROP_SHADOW_TOKENS }]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
24
32
|
});
|
|
25
33
|
function cn(...inputs) {
|
|
26
34
|
return twMerge(clsx(inputs));
|
|
@@ -64,7 +72,7 @@ function AppShell({ variant = "solid", menu, logo, search, identity, banner, nav
|
|
|
64
72
|
{
|
|
65
73
|
className: cn(
|
|
66
74
|
"flex min-w-0 flex-1 flex-col overflow-hidden rounded-2xl bg-bg-surface",
|
|
67
|
-
"signal:border signal:border-border-subtle signal:shadow-
|
|
75
|
+
"signal:border signal:border-border-subtle signal:shadow-highlight-inset"
|
|
68
76
|
),
|
|
69
77
|
children: [
|
|
70
78
|
banner,
|
|
@@ -155,18 +163,83 @@ function AvatarGroup({ members, size = 24 }) {
|
|
|
155
163
|
|
|
156
164
|
// src/Banner.tsx
|
|
157
165
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
158
|
-
var
|
|
166
|
+
var TONE_STYLES = {
|
|
159
167
|
ok: "bg-success-muted text-success-default",
|
|
160
168
|
error: "bg-error-muted text-error-default",
|
|
161
169
|
info: "bg-info-muted text-info-default",
|
|
162
170
|
warning: "bg-warning-muted text-warning-default"
|
|
163
171
|
};
|
|
164
172
|
function Banner({ tone, children, className }) {
|
|
165
|
-
return /* @__PURE__ */ jsx5("div", { role: tone === "error" ? "alert" : "status", className: cn("px-4 py-2 text-body-2",
|
|
173
|
+
return /* @__PURE__ */ jsx5("div", { role: tone === "error" ? "alert" : "status", className: cn("px-4 py-2 text-body-2", TONE_STYLES[tone], className), children });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// src/Button.tsx
|
|
177
|
+
import { Button as BaseButton } from "@base-ui/react/button";
|
|
178
|
+
|
|
179
|
+
// src/Tooltip.tsx
|
|
180
|
+
import { useCallback, useLayoutEffect, useRef, useState as useState2 } from "react";
|
|
181
|
+
import { createPortal } from "react-dom";
|
|
182
|
+
|
|
183
|
+
// src/Kbd.tsx
|
|
184
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
185
|
+
function Kbd({ children, className }) {
|
|
186
|
+
return /* @__PURE__ */ jsx6(
|
|
187
|
+
"kbd",
|
|
188
|
+
{
|
|
189
|
+
className: cn(
|
|
190
|
+
"inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans text-[12px] leading-[120%] font-normal text-text-secondary",
|
|
191
|
+
"signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-bg-wash signal:font-mono signal:text-[10px]",
|
|
192
|
+
"ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-bg-wash ship:font-mono ship:text-[10px]",
|
|
193
|
+
className
|
|
194
|
+
),
|
|
195
|
+
children
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// src/Tooltip.tsx
|
|
201
|
+
import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
202
|
+
function Tooltip({ label, shortcut, className }) {
|
|
203
|
+
return /* @__PURE__ */ jsxs3("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), children: [
|
|
204
|
+
/* @__PURE__ */ jsx7("span", { className: "text-caption text-text-primary whitespace-nowrap", children: label }),
|
|
205
|
+
shortcut && /* @__PURE__ */ jsx7(Kbd, { children: shortcut })
|
|
206
|
+
] });
|
|
207
|
+
}
|
|
208
|
+
var GAP = 6;
|
|
209
|
+
var VIEWPORT_PAD = 8;
|
|
210
|
+
function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, children }) {
|
|
211
|
+
const [show, setShow] = useState2(false);
|
|
212
|
+
const ref = useRef(null);
|
|
213
|
+
const tooltipRef = useRef(null);
|
|
214
|
+
const [style, setStyle] = useState2({ position: "fixed", zIndex: 9999, pointerEvents: "none", visibility: "hidden" });
|
|
215
|
+
const reposition = useCallback(() => {
|
|
216
|
+
const trigger = ref.current;
|
|
217
|
+
const tip = tooltipRef.current;
|
|
218
|
+
if (!trigger || !tip) return;
|
|
219
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
220
|
+
const tipRect = tip.getBoundingClientRect();
|
|
221
|
+
let top = placement === "bottom" ? triggerRect.bottom + GAP : triggerRect.top - tipRect.height - GAP;
|
|
222
|
+
if (placement === "top" && top < VIEWPORT_PAD) top = triggerRect.bottom + GAP;
|
|
223
|
+
else if (placement === "bottom" && top + tipRect.height > window.innerHeight - VIEWPORT_PAD) top = triggerRect.top - tipRect.height - GAP;
|
|
224
|
+
top = Math.max(VIEWPORT_PAD, Math.min(top, window.innerHeight - tipRect.height - VIEWPORT_PAD));
|
|
225
|
+
let left = triggerRect.left + triggerRect.width / 2 - tipRect.width / 2;
|
|
226
|
+
left = Math.max(VIEWPORT_PAD, Math.min(left, window.innerWidth - tipRect.width - VIEWPORT_PAD));
|
|
227
|
+
setStyle({ position: "fixed", top, left, zIndex: 9999, pointerEvents: "none", visibility: "visible" });
|
|
228
|
+
}, [placement]);
|
|
229
|
+
useLayoutEffect(() => {
|
|
230
|
+
if (show) reposition();
|
|
231
|
+
}, [show, reposition]);
|
|
232
|
+
return /* @__PURE__ */ jsxs3("div", { ref, className: cn("inline-flex shrink-0", wrapperClassName), onMouseEnter: () => setShow(true), onMouseLeave: () => setShow(false), children: [
|
|
233
|
+
children,
|
|
234
|
+
show && createPortal(
|
|
235
|
+
/* @__PURE__ */ jsx7("div", { ref: tooltipRef, style, children: /* @__PURE__ */ jsx7(Tooltip, { label, shortcut }) }),
|
|
236
|
+
document.body
|
|
237
|
+
)
|
|
238
|
+
] });
|
|
166
239
|
}
|
|
167
240
|
|
|
168
241
|
// src/Button.tsx
|
|
169
|
-
import { jsxs as
|
|
242
|
+
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
170
243
|
function Button({
|
|
171
244
|
variant = "muted",
|
|
172
245
|
size = "default",
|
|
@@ -174,30 +247,32 @@ function Button({
|
|
|
174
247
|
className,
|
|
175
248
|
children,
|
|
176
249
|
disabled,
|
|
250
|
+
disabledReason,
|
|
177
251
|
type = "button",
|
|
178
252
|
...props
|
|
179
253
|
}) {
|
|
180
254
|
const hasLeadingIcon = !!leadingIcon;
|
|
181
|
-
|
|
182
|
-
|
|
255
|
+
const button = /* @__PURE__ */ jsxs4(
|
|
256
|
+
BaseButton,
|
|
183
257
|
{
|
|
184
258
|
type,
|
|
185
|
-
|
|
259
|
+
disabled: disabled || !!disabledReason,
|
|
260
|
+
focusableWhenDisabled: !!disabledReason,
|
|
261
|
+
className: (state) => cn(
|
|
186
262
|
"inline-flex items-center justify-center gap-1 rounded-md transition-colors font-sans font-medium",
|
|
187
|
-
size === "default" && "h-8 text-
|
|
188
|
-
size === "small" && "h-6 text-
|
|
263
|
+
size === "default" && "h-8 text-btn-default",
|
|
264
|
+
size === "small" && "h-6 text-btn-small",
|
|
189
265
|
// Extra right padding beside a leading icon, for optical balance.
|
|
190
266
|
size === "default" && (hasLeadingIcon ? "pl-2 pr-3" : "px-2"),
|
|
191
267
|
size === "small" && (hasLeadingIcon ? "pl-1.5 pr-2" : "px-1.5"),
|
|
192
|
-
!disabled && variant === "primary" && "bg-accent-primary hover:bg-accent-hover text-text-inverse cursor-pointer signal:font-semibold",
|
|
193
|
-
!disabled && variant === "outlined" && "border border-border-default hover:bg-bg-hover text-text-primary cursor-pointer",
|
|
194
|
-
!disabled && variant === "muted" && "hover:bg-bg-hover text-text-primary cursor-pointer",
|
|
195
|
-
!disabled && variant === "destructive" && "hover:bg-error-muted text-error-default cursor-pointer",
|
|
196
|
-
disabled && "bg-bg-disabled text-text-disabled pointer-events-none",
|
|
197
|
-
disabled && variant === "outlined" && "border border-border-default",
|
|
268
|
+
!state.disabled && variant === "primary" && "bg-accent-primary hover:bg-accent-hover text-text-inverse cursor-pointer signal:font-semibold",
|
|
269
|
+
!state.disabled && variant === "outlined" && "border border-border-default hover:bg-bg-hover text-text-primary cursor-pointer",
|
|
270
|
+
!state.disabled && variant === "muted" && "hover:bg-bg-hover text-text-primary cursor-pointer",
|
|
271
|
+
!state.disabled && variant === "destructive" && "hover:bg-error-muted text-error-default cursor-pointer",
|
|
272
|
+
state.disabled && "bg-bg-disabled text-text-disabled pointer-events-none",
|
|
273
|
+
state.disabled && variant === "outlined" && "border border-border-default",
|
|
198
274
|
className
|
|
199
275
|
),
|
|
200
|
-
disabled,
|
|
201
276
|
...props,
|
|
202
277
|
children: [
|
|
203
278
|
leadingIcon,
|
|
@@ -205,62 +280,67 @@ function Button({
|
|
|
205
280
|
]
|
|
206
281
|
}
|
|
207
282
|
);
|
|
283
|
+
return disabledReason ? /* @__PURE__ */ jsx8(WithTooltip, { label: disabledReason, children: button }) : button;
|
|
208
284
|
}
|
|
209
285
|
|
|
210
286
|
// src/Checkbox.tsx
|
|
287
|
+
import { Checkbox as BaseCheckbox } from "@base-ui/react/checkbox";
|
|
211
288
|
import { IconCheck } from "@tabler/icons-react";
|
|
212
|
-
import { jsx as
|
|
289
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
290
|
+
function squareClasses(checked, disabled, interactive, className) {
|
|
291
|
+
return cn(
|
|
292
|
+
"inline-flex items-center justify-center size-4 shrink-0 rounded-[4px] border transition-colors",
|
|
293
|
+
checked ? "bg-accent-primary border-accent-primary text-text-inverse" : "bg-transparent border-border-strong hover:border-text-muted",
|
|
294
|
+
disabled && "opacity-50 pointer-events-none",
|
|
295
|
+
interactive ? "cursor-pointer" : "pointer-events-none",
|
|
296
|
+
className
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
var tickClasses = (checked) => cn("flex", !checked && "invisible");
|
|
213
300
|
function Checkbox({ checked, onChange, disabled = false, className, ...aria }) {
|
|
214
|
-
|
|
215
|
-
"
|
|
301
|
+
if (!onChange) {
|
|
302
|
+
return /* @__PURE__ */ jsx9("span", { "aria-hidden": "true", className: squareClasses(checked, disabled, false, className), children: /* @__PURE__ */ jsx9("span", { className: tickClasses(checked), children: /* @__PURE__ */ jsx9(IconCheck, { size: 12, stroke: 3 }) }) });
|
|
303
|
+
}
|
|
304
|
+
return /* @__PURE__ */ jsx9(
|
|
305
|
+
BaseCheckbox.Root,
|
|
216
306
|
{
|
|
217
|
-
|
|
218
|
-
role: "checkbox",
|
|
219
|
-
"aria-checked": checked,
|
|
220
|
-
"aria-label": aria["aria-label"],
|
|
307
|
+
checked,
|
|
221
308
|
disabled,
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
className:
|
|
227
|
-
"inline-flex items-center justify-center size-4 shrink-0 rounded-[4px] border transition-colors",
|
|
228
|
-
checked ? "bg-accent-primary border-accent-primary text-text-inverse" : "bg-transparent border-border-strong hover:border-text-muted",
|
|
229
|
-
disabled && "opacity-50 pointer-events-none",
|
|
230
|
-
onChange ? "cursor-pointer" : "pointer-events-none",
|
|
231
|
-
className
|
|
232
|
-
),
|
|
233
|
-
children: checked && /* @__PURE__ */ jsx6(IconCheck, { size: 12, stroke: 3 })
|
|
309
|
+
"aria-label": aria["aria-label"],
|
|
310
|
+
onCheckedChange: (next) => onChange(next),
|
|
311
|
+
onClick: (e) => e.stopPropagation(),
|
|
312
|
+
className: (state) => squareClasses(state.checked, state.disabled, true, className),
|
|
313
|
+
children: /* @__PURE__ */ jsx9(BaseCheckbox.Indicator, { keepMounted: true, className: (state) => tickClasses(state.checked), children: /* @__PURE__ */ jsx9(IconCheck, { size: 12, stroke: 3 }) })
|
|
234
314
|
}
|
|
235
315
|
);
|
|
236
316
|
}
|
|
237
317
|
|
|
238
318
|
// src/Chip.tsx
|
|
239
|
-
import { jsx as
|
|
319
|
+
import { jsx as jsx10, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
240
320
|
var typeStyles = {
|
|
241
321
|
neutral: "bg-bg-inset text-text-primary",
|
|
242
|
-
brand: "bg-accent-muted text-accent-primary signal:border signal:border-
|
|
243
|
-
info: "bg-info-muted text-info-default signal:border signal:border-
|
|
244
|
-
warning: "bg-warning-muted text-warning-default signal:border signal:border-
|
|
245
|
-
success: "bg-success-muted text-success-default signal:border signal:border-
|
|
246
|
-
error: "bg-error-muted text-error-default signal:border signal:border-
|
|
322
|
+
brand: "bg-accent-muted text-accent-primary signal:border signal:border-accent-outline",
|
|
323
|
+
info: "bg-info-muted text-info-default signal:border signal:border-info-outline",
|
|
324
|
+
warning: "bg-warning-muted text-warning-default signal:border signal:border-warning-outline signal:shadow-glow-warning",
|
|
325
|
+
success: "bg-success-muted text-success-default signal:border signal:border-success-outline",
|
|
326
|
+
error: "bg-error-muted text-error-default signal:border signal:border-error-outline"
|
|
247
327
|
};
|
|
248
328
|
function Chip({ type = "neutral", label, leadingIcon, trailingIcon, className }) {
|
|
249
|
-
return /* @__PURE__ */
|
|
250
|
-
leadingIcon && /* @__PURE__ */
|
|
251
|
-
label && /* @__PURE__ */
|
|
252
|
-
trailingIcon && /* @__PURE__ */
|
|
329
|
+
return /* @__PURE__ */ jsxs5("div", { className: cn("inline-flex items-center justify-center gap-1.5 rounded-full max-h-[20px] min-w-[16px] px-2 py-1", typeStyles[type], className), children: [
|
|
330
|
+
leadingIcon && /* @__PURE__ */ jsx10("span", { className: "flex size-3 shrink-0 items-center justify-center", children: leadingIcon }),
|
|
331
|
+
label && /* @__PURE__ */ jsx10("span", { className: "text-chip whitespace-nowrap signal:font-mono signal:text-[10px] signal:font-semibold signal:tracking-[0.02em] signal:tabular-nums", children: label }),
|
|
332
|
+
trailingIcon && /* @__PURE__ */ jsx10("span", { className: "flex size-3 shrink-0 items-center justify-center", children: trailingIcon })
|
|
253
333
|
] });
|
|
254
334
|
}
|
|
255
335
|
|
|
256
336
|
// src/ChipInput.tsx
|
|
257
|
-
import { useState as
|
|
258
|
-
import { createPortal as
|
|
337
|
+
import { useState as useState4, useRef as useRef3, useMemo, useEffect as useEffect2, useLayoutEffect as useLayoutEffect3 } from "react";
|
|
338
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
259
339
|
import { IconX } from "@tabler/icons-react";
|
|
260
340
|
|
|
261
341
|
// src/fit.ts
|
|
262
342
|
var MARGIN = 8;
|
|
263
|
-
var
|
|
343
|
+
var GAP2 = 4;
|
|
264
344
|
function fitMenu({
|
|
265
345
|
anchor,
|
|
266
346
|
menu,
|
|
@@ -268,11 +348,11 @@ function fitMenu({
|
|
|
268
348
|
cap = Number.POSITIVE_INFINITY
|
|
269
349
|
}) {
|
|
270
350
|
const left = Math.max(MARGIN, Math.min(anchor.left, viewport.width - menu.width - MARGIN));
|
|
271
|
-
const below = viewport.height - anchor.bottom -
|
|
272
|
-
const above = anchor.top -
|
|
351
|
+
const below = viewport.height - anchor.bottom - GAP2 - MARGIN;
|
|
352
|
+
const above = anchor.top - GAP2 - MARGIN;
|
|
273
353
|
const openUp = below < Math.min(menu.contentHeight, cap) && above > below;
|
|
274
354
|
const maxHeight = Math.max(Math.min(cap, openUp ? above : below), 120);
|
|
275
|
-
return openUp ? { left, bottom: viewport.height - anchor.top +
|
|
355
|
+
return openUp ? { left, bottom: viewport.height - anchor.top + GAP2, maxHeight } : { left, top: anchor.bottom + GAP2, maxHeight };
|
|
276
356
|
}
|
|
277
357
|
function clampBox({
|
|
278
358
|
box,
|
|
@@ -288,38 +368,21 @@ function fitSubmenu({
|
|
|
288
368
|
panel,
|
|
289
369
|
viewport
|
|
290
370
|
}) {
|
|
291
|
-
const fitsRight = row.right +
|
|
292
|
-
const left = Math.max(MARGIN, fitsRight ? row.right +
|
|
371
|
+
const fitsRight = row.right + GAP2 + panel.width <= viewport.width - MARGIN;
|
|
372
|
+
const left = Math.max(MARGIN, fitsRight ? row.right + GAP2 : row.left - GAP2 - panel.width);
|
|
293
373
|
const top = Math.max(MARGIN, Math.min(row.top, viewport.height - panel.height - MARGIN));
|
|
294
374
|
return { left, top };
|
|
295
375
|
}
|
|
296
376
|
|
|
297
377
|
// src/Menu.tsx
|
|
298
|
-
import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useRef, useState as
|
|
378
|
+
import { createContext, useCallback as useCallback2, useContext, useEffect, useLayoutEffect as useLayoutEffect2, useRef as useRef2, useState as useState3 } from "react";
|
|
299
379
|
import { IconChevronRight } from "@tabler/icons-react";
|
|
300
|
-
import { createPortal } from "react-dom";
|
|
301
|
-
|
|
302
|
-
// src/Kbd.tsx
|
|
303
|
-
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
304
|
-
function Kbd({ children, className }) {
|
|
305
|
-
return /* @__PURE__ */ jsx8(
|
|
306
|
-
"kbd",
|
|
307
|
-
{
|
|
308
|
-
className: cn(
|
|
309
|
-
"inline-flex shrink-0 items-center justify-center whitespace-nowrap rounded-sm border border-border-strong bg-bg-inset px-1 py-px font-sans text-[12px] leading-[120%] font-normal text-text-secondary",
|
|
310
|
-
"signal:border-b-2 signal:pt-[2px] signal:pb-px signal:bg-[rgba(255,255,255,.05)] signal:font-mono signal:text-[10px]",
|
|
311
|
-
"ship:border-b-2 ship:pt-[2px] ship:pb-px ship:bg-[rgba(255,255,255,.05)] ship:font-mono ship:text-[10px]",
|
|
312
|
-
className
|
|
313
|
-
),
|
|
314
|
-
children
|
|
315
|
-
}
|
|
316
|
-
);
|
|
317
|
-
}
|
|
380
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
318
381
|
|
|
319
382
|
// src/SectionLabel.tsx
|
|
320
|
-
import { jsx as
|
|
383
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
321
384
|
function SectionLabel({ children, className }) {
|
|
322
|
-
return /* @__PURE__ */
|
|
385
|
+
return /* @__PURE__ */ jsx11(
|
|
323
386
|
"span",
|
|
324
387
|
{
|
|
325
388
|
className: cn(
|
|
@@ -332,10 +395,10 @@ function SectionLabel({ children, className }) {
|
|
|
332
395
|
}
|
|
333
396
|
|
|
334
397
|
// src/Menu.tsx
|
|
335
|
-
import { jsx as
|
|
398
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
336
399
|
var MenuHoverContext = createContext(null);
|
|
337
400
|
function MenuPanel({ children, className, ...props }) {
|
|
338
|
-
return /* @__PURE__ */
|
|
401
|
+
return /* @__PURE__ */ jsx12(
|
|
339
402
|
"div",
|
|
340
403
|
{
|
|
341
404
|
className: cn("flex flex-col rounded-lg border border-border-default bg-bg-elevated p-2 shadow-lg", className),
|
|
@@ -345,17 +408,17 @@ function MenuPanel({ children, className, ...props }) {
|
|
|
345
408
|
);
|
|
346
409
|
}
|
|
347
410
|
function Menu({ onClose, anchor, align = "left", position, closeOnLeave = false, children, className }) {
|
|
348
|
-
const ref =
|
|
349
|
-
const leaveTimer =
|
|
350
|
-
const hold =
|
|
351
|
-
const release =
|
|
411
|
+
const ref = useRef2(null);
|
|
412
|
+
const leaveTimer = useRef2(void 0);
|
|
413
|
+
const hold = useCallback2(() => clearTimeout(leaveTimer.current), []);
|
|
414
|
+
const release = useCallback2(() => {
|
|
352
415
|
if (!closeOnLeave) return;
|
|
353
416
|
clearTimeout(leaveTimer.current);
|
|
354
417
|
leaveTimer.current = setTimeout(onClose, 150);
|
|
355
418
|
}, [closeOnLeave, onClose]);
|
|
356
419
|
useEffect(() => () => clearTimeout(leaveTimer.current), []);
|
|
357
420
|
const portalled = Boolean(anchor || position);
|
|
358
|
-
const [placed, setPlaced] =
|
|
421
|
+
const [placed, setPlaced] = useState3(null);
|
|
359
422
|
useEffect(() => {
|
|
360
423
|
const onDown = (event) => {
|
|
361
424
|
if (!ref.current?.contains(event.target)) onClose();
|
|
@@ -373,7 +436,7 @@ function Menu({ onClose, anchor, align = "left", position, closeOnLeave = false,
|
|
|
373
436
|
const posLeft = position && "left" in position ? position.left : void 0;
|
|
374
437
|
const posRight = position && "right" in position ? position.right : void 0;
|
|
375
438
|
const posTop = position?.top;
|
|
376
|
-
|
|
439
|
+
useLayoutEffect2(() => {
|
|
377
440
|
if (!portalled || !ref.current) return;
|
|
378
441
|
const viewport = { width: window.innerWidth, height: window.innerHeight };
|
|
379
442
|
const menu = ref.current;
|
|
@@ -409,7 +472,7 @@ function Menu({ onClose, anchor, align = "left", position, closeOnLeave = false,
|
|
|
409
472
|
// The provisional render: measured by the layout effect, never seen.
|
|
410
473
|
{ left: 0, top: 0, visibility: "hidden" }
|
|
411
474
|
) : void 0;
|
|
412
|
-
const node = /* @__PURE__ */
|
|
475
|
+
const node = /* @__PURE__ */ jsx12(MenuHoverContext.Provider, { value: { hold, release }, children: /* @__PURE__ */ jsx12(
|
|
413
476
|
MenuPanel,
|
|
414
477
|
{
|
|
415
478
|
ref,
|
|
@@ -427,14 +490,14 @@ function Menu({ onClose, anchor, align = "left", position, closeOnLeave = false,
|
|
|
427
490
|
children
|
|
428
491
|
}
|
|
429
492
|
) });
|
|
430
|
-
return portalled ?
|
|
493
|
+
return portalled ? createPortal2(node, document.body) : node;
|
|
431
494
|
}
|
|
432
495
|
function MenuSub({ label, leading, selected, children, className }) {
|
|
433
|
-
const [open, setOpen] =
|
|
434
|
-
const rowRef =
|
|
435
|
-
const panelRef =
|
|
436
|
-
const closeTimer =
|
|
437
|
-
const [placed, setPlaced] =
|
|
496
|
+
const [open, setOpen] = useState3(false);
|
|
497
|
+
const rowRef = useRef2(null);
|
|
498
|
+
const panelRef = useRef2(null);
|
|
499
|
+
const closeTimer = useRef2(void 0);
|
|
500
|
+
const [placed, setPlaced] = useState3(null);
|
|
438
501
|
const menuHover = useContext(MenuHoverContext);
|
|
439
502
|
const enter = () => {
|
|
440
503
|
clearTimeout(closeTimer.current);
|
|
@@ -446,7 +509,7 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
446
509
|
menuHover?.release();
|
|
447
510
|
};
|
|
448
511
|
useEffect(() => () => clearTimeout(closeTimer.current), []);
|
|
449
|
-
|
|
512
|
+
useLayoutEffect2(() => {
|
|
450
513
|
if (!open || !rowRef.current || !panelRef.current) {
|
|
451
514
|
setPlaced(null);
|
|
452
515
|
return;
|
|
@@ -460,10 +523,10 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
460
523
|
})
|
|
461
524
|
);
|
|
462
525
|
}, [open]);
|
|
463
|
-
return /* @__PURE__ */
|
|
464
|
-
/* @__PURE__ */
|
|
465
|
-
open &&
|
|
466
|
-
/* @__PURE__ */
|
|
526
|
+
return /* @__PURE__ */ jsxs6("div", { ref: rowRef, onMouseEnter: enter, onMouseLeave: leave, children: [
|
|
527
|
+
/* @__PURE__ */ jsx12(MenuItem, { label, leading, selected, submenu: true }),
|
|
528
|
+
open && createPortal2(
|
|
529
|
+
/* @__PURE__ */ jsx12(
|
|
467
530
|
MenuPanel,
|
|
468
531
|
{
|
|
469
532
|
ref: panelRef,
|
|
@@ -481,8 +544,8 @@ function MenuSub({ label, leading, selected, children, className }) {
|
|
|
481
544
|
] });
|
|
482
545
|
}
|
|
483
546
|
function MenuItem({ label, children, size = "default", description, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }) {
|
|
484
|
-
const edge = trailing ?? (shortcut ? /* @__PURE__ */
|
|
485
|
-
return /* @__PURE__ */
|
|
547
|
+
const edge = trailing ?? (shortcut ? /* @__PURE__ */ jsx12(Kbd, { children: shortcut }) : submenu ? /* @__PURE__ */ jsx12(IconChevronRight, { size: 16, stroke: 1.5, className: "shrink-0 text-text-muted" }) : null);
|
|
548
|
+
return /* @__PURE__ */ jsxs6(
|
|
486
549
|
"button",
|
|
487
550
|
{
|
|
488
551
|
type: "button",
|
|
@@ -513,43 +576,43 @@ function MenuItem({ label, children, size = "default", description, leading, tra
|
|
|
513
576
|
),
|
|
514
577
|
...props,
|
|
515
578
|
children: [
|
|
516
|
-
leading && /* @__PURE__ */
|
|
517
|
-
children ?? /* @__PURE__ */
|
|
518
|
-
/* @__PURE__ */
|
|
519
|
-
description && /* @__PURE__ */
|
|
579
|
+
leading && /* @__PURE__ */ jsx12("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
580
|
+
children ?? /* @__PURE__ */ jsxs6("span", { className: cn("flex min-w-0 flex-1 flex-col", size === "tall" && "gap-[2px]"), children: [
|
|
581
|
+
/* @__PURE__ */ jsx12("span", { className: cn("truncate text-[14px] leading-[140%]", destructive ? "text-error-default" : "text-text-primary"), children: label }),
|
|
582
|
+
description && /* @__PURE__ */ jsx12("span", { className: "truncate text-[12px] leading-[120%] text-text-secondary", children: description })
|
|
520
583
|
] }),
|
|
521
584
|
(edge || hint) && // One grid cell holding both, right-aligned: the slot is as wide as
|
|
522
585
|
// the wider of the two and never changes, so revealing the hint moves
|
|
523
586
|
// nothing. No transition here either — the hint switches on the same
|
|
524
587
|
// :hover / `selected` as the fill, in the same frame.
|
|
525
|
-
/* @__PURE__ */
|
|
526
|
-
edge && /* @__PURE__ */
|
|
527
|
-
hint && /* @__PURE__ */
|
|
588
|
+
/* @__PURE__ */ jsxs6("span", { className: "grid shrink-0 items-center justify-items-end [&>*]:col-start-1 [&>*]:row-start-1", children: [
|
|
589
|
+
edge && /* @__PURE__ */ jsx12("span", { className: cn("flex items-center", hint && "group-hover:opacity-0", hint && selected && "opacity-0"), children: edge }),
|
|
590
|
+
hint && /* @__PURE__ */ jsx12("span", { className: cn("flex items-center opacity-0 group-hover:opacity-100", selected && "opacity-100"), children: hint })
|
|
528
591
|
] })
|
|
529
592
|
]
|
|
530
593
|
}
|
|
531
594
|
);
|
|
532
595
|
}
|
|
533
596
|
function EnterHint({ target }) {
|
|
534
|
-
return /* @__PURE__ */
|
|
535
|
-
/* @__PURE__ */
|
|
536
|
-
target && /* @__PURE__ */
|
|
597
|
+
return /* @__PURE__ */ jsxs6("span", { className: "flex shrink-0 items-center gap-1.5 text-text-muted", children: [
|
|
598
|
+
/* @__PURE__ */ jsx12(Kbd, { children: "\u21A9 Enter" }),
|
|
599
|
+
target && /* @__PURE__ */ jsx12("span", { className: "text-[9px] font-medium leading-[115%] signal:font-mono signal:text-[9.5px] signal:tracking-[0.04em]", children: target })
|
|
537
600
|
] });
|
|
538
601
|
}
|
|
539
602
|
function MenuSection({ label, children, className }) {
|
|
540
|
-
return /* @__PURE__ */
|
|
541
|
-
/* @__PURE__ */
|
|
603
|
+
return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col", children: [
|
|
604
|
+
/* @__PURE__ */ jsx12("div", { className: cn("flex h-8 items-center px-2", className), children: /* @__PURE__ */ jsx12(SectionLabel, { className: "text-text-secondary", children: label }) }),
|
|
542
605
|
children
|
|
543
606
|
] });
|
|
544
607
|
}
|
|
545
608
|
function MenuRow({ children, className }) {
|
|
546
|
-
return /* @__PURE__ */
|
|
609
|
+
return /* @__PURE__ */ jsx12("div", { className: cn("flex items-center gap-2 px-2 py-1.5", className), children });
|
|
547
610
|
}
|
|
548
611
|
|
|
549
612
|
// src/ChipInput.tsx
|
|
550
|
-
import { jsx as
|
|
613
|
+
import { jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
551
614
|
function InputChip({ label, leading, onRemove, className }) {
|
|
552
|
-
return /* @__PURE__ */
|
|
615
|
+
return /* @__PURE__ */ jsxs7(
|
|
553
616
|
"div",
|
|
554
617
|
{
|
|
555
618
|
className: cn(
|
|
@@ -565,9 +628,9 @@ function InputChip({ label, leading, onRemove, className }) {
|
|
|
565
628
|
className
|
|
566
629
|
),
|
|
567
630
|
children: [
|
|
568
|
-
leading && /* @__PURE__ */
|
|
569
|
-
/* @__PURE__ */
|
|
570
|
-
onRemove && /* @__PURE__ */
|
|
631
|
+
leading && /* @__PURE__ */ jsx13("span", { className: "flex shrink-0 items-center", children: leading }),
|
|
632
|
+
/* @__PURE__ */ jsx13("span", { className: "text-caption font-medium text-text-primary", children: label }),
|
|
633
|
+
onRemove && /* @__PURE__ */ jsx13(
|
|
571
634
|
"button",
|
|
572
635
|
{
|
|
573
636
|
type: "button",
|
|
@@ -577,7 +640,7 @@ function InputChip({ label, leading, onRemove, className }) {
|
|
|
577
640
|
},
|
|
578
641
|
className: "size-4 flex items-center justify-center rounded-full hover:bg-bg-hover text-text-secondary",
|
|
579
642
|
"aria-label": `Remove ${label}`,
|
|
580
|
-
children: /* @__PURE__ */
|
|
643
|
+
children: /* @__PURE__ */ jsx13(IconX, { size: 10, stroke: 1.5 })
|
|
581
644
|
}
|
|
582
645
|
)
|
|
583
646
|
]
|
|
@@ -594,12 +657,12 @@ function ChipInput({
|
|
|
594
657
|
chipLeading,
|
|
595
658
|
rowLeading
|
|
596
659
|
}) {
|
|
597
|
-
const [query, setQuery] =
|
|
598
|
-
const [highlight, setHighlight] =
|
|
599
|
-
const [isFocused, setIsFocused] =
|
|
600
|
-
const [anchorRect, setAnchorRect] =
|
|
601
|
-
const wrapperRef =
|
|
602
|
-
const inputRef =
|
|
660
|
+
const [query, setQuery] = useState4("");
|
|
661
|
+
const [highlight, setHighlight] = useState4(0);
|
|
662
|
+
const [isFocused, setIsFocused] = useState4(false);
|
|
663
|
+
const [anchorRect, setAnchorRect] = useState4(null);
|
|
664
|
+
const wrapperRef = useRef3(null);
|
|
665
|
+
const inputRef = useRef3(null);
|
|
603
666
|
const matches = useMemo(() => {
|
|
604
667
|
const selectedIds = new Set(value.map((o) => o.id));
|
|
605
668
|
const excludedIds = new Set(excludeIds);
|
|
@@ -615,7 +678,7 @@ function ChipInput({
|
|
|
615
678
|
setHighlight(0);
|
|
616
679
|
}, [query, matches.length]);
|
|
617
680
|
const showDropdown = isFocused && query.trim().length > 0 && matches.length > 0;
|
|
618
|
-
|
|
681
|
+
useLayoutEffect3(() => {
|
|
619
682
|
if (!showDropdown) return;
|
|
620
683
|
const update = () => {
|
|
621
684
|
if (wrapperRef.current) setAnchorRect(wrapperRef.current.getBoundingClientRect());
|
|
@@ -665,16 +728,16 @@ function ChipInput({
|
|
|
665
728
|
}
|
|
666
729
|
}
|
|
667
730
|
}
|
|
668
|
-
return /* @__PURE__ */
|
|
669
|
-
/* @__PURE__ */
|
|
731
|
+
return /* @__PURE__ */ jsxs7("div", { className: "relative", children: [
|
|
732
|
+
/* @__PURE__ */ jsxs7(
|
|
670
733
|
"div",
|
|
671
734
|
{
|
|
672
735
|
ref: wrapperRef,
|
|
673
736
|
className: "bg-bg-inset border border-border-default hover:border-border-strong focus-within:border-border-focus focus-within:hover:border-border-focus rounded-lg px-3 py-1.5 flex flex-wrap items-center gap-1.5 transition-colors min-h-[38px] cursor-text signal:transition-shadow signal:focus-within:shadow-focus-ring",
|
|
674
737
|
onClick: () => inputRef.current?.focus(),
|
|
675
738
|
children: [
|
|
676
|
-
value.map((o) => /* @__PURE__ */
|
|
677
|
-
/* @__PURE__ */
|
|
739
|
+
value.map((o) => /* @__PURE__ */ jsx13(InputChip, { label: o.label, leading: chipLeading?.(o), onRemove: () => removeOption(o.id) }, o.id)),
|
|
740
|
+
/* @__PURE__ */ jsx13(
|
|
678
741
|
"input",
|
|
679
742
|
{
|
|
680
743
|
ref: inputRef,
|
|
@@ -694,8 +757,8 @@ function ChipInput({
|
|
|
694
757
|
]
|
|
695
758
|
}
|
|
696
759
|
),
|
|
697
|
-
showDropdown && anchorRect &&
|
|
698
|
-
/* @__PURE__ */
|
|
760
|
+
showDropdown && anchorRect && createPortal3(
|
|
761
|
+
/* @__PURE__ */ jsx13(
|
|
699
762
|
"div",
|
|
700
763
|
{
|
|
701
764
|
className: "fixed z-[60] overflow-y-auto bg-bg-elevated border border-border-default rounded-lg shadow-lg",
|
|
@@ -708,7 +771,7 @@ function ChipInput({
|
|
|
708
771
|
}),
|
|
709
772
|
width: anchorRect.width
|
|
710
773
|
},
|
|
711
|
-
children: matches.map((o, i) => /* @__PURE__ */
|
|
774
|
+
children: matches.map((o, i) => /* @__PURE__ */ jsx13(
|
|
712
775
|
MenuItem,
|
|
713
776
|
{
|
|
714
777
|
size: "tall",
|
|
@@ -732,84 +795,45 @@ function ChipInput({
|
|
|
732
795
|
] });
|
|
733
796
|
}
|
|
734
797
|
|
|
735
|
-
// src/Tooltip.tsx
|
|
736
|
-
import { useCallback as useCallback2, useLayoutEffect as useLayoutEffect3, useRef as useRef3, useState as useState4 } from "react";
|
|
737
|
-
import { createPortal as createPortal3 } from "react-dom";
|
|
738
|
-
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
739
|
-
function Tooltip({ label, shortcut, className }) {
|
|
740
|
-
return /* @__PURE__ */ jsxs7("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), children: [
|
|
741
|
-
/* @__PURE__ */ jsx12("span", { className: "text-caption text-text-primary whitespace-nowrap", children: label }),
|
|
742
|
-
shortcut && /* @__PURE__ */ jsx12(Kbd, { children: shortcut })
|
|
743
|
-
] });
|
|
744
|
-
}
|
|
745
|
-
var GAP2 = 6;
|
|
746
|
-
var VIEWPORT_PAD = 8;
|
|
747
|
-
function WithTooltip({ label, shortcut, placement = "top", wrapperClassName, children }) {
|
|
748
|
-
const [show, setShow] = useState4(false);
|
|
749
|
-
const ref = useRef3(null);
|
|
750
|
-
const tooltipRef = useRef3(null);
|
|
751
|
-
const [style, setStyle] = useState4({ position: "fixed", zIndex: 9999, pointerEvents: "none", visibility: "hidden" });
|
|
752
|
-
const reposition = useCallback2(() => {
|
|
753
|
-
const trigger = ref.current;
|
|
754
|
-
const tip = tooltipRef.current;
|
|
755
|
-
if (!trigger || !tip) return;
|
|
756
|
-
const triggerRect = trigger.getBoundingClientRect();
|
|
757
|
-
const tipRect = tip.getBoundingClientRect();
|
|
758
|
-
let top = placement === "bottom" ? triggerRect.bottom + GAP2 : triggerRect.top - tipRect.height - GAP2;
|
|
759
|
-
if (placement === "top" && top < VIEWPORT_PAD) top = triggerRect.bottom + GAP2;
|
|
760
|
-
else if (placement === "bottom" && top + tipRect.height > window.innerHeight - VIEWPORT_PAD) top = triggerRect.top - tipRect.height - GAP2;
|
|
761
|
-
top = Math.max(VIEWPORT_PAD, Math.min(top, window.innerHeight - tipRect.height - VIEWPORT_PAD));
|
|
762
|
-
let left = triggerRect.left + triggerRect.width / 2 - tipRect.width / 2;
|
|
763
|
-
left = Math.max(VIEWPORT_PAD, Math.min(left, window.innerWidth - tipRect.width - VIEWPORT_PAD));
|
|
764
|
-
setStyle({ position: "fixed", top, left, zIndex: 9999, pointerEvents: "none", visibility: "visible" });
|
|
765
|
-
}, [placement]);
|
|
766
|
-
useLayoutEffect3(() => {
|
|
767
|
-
if (show) reposition();
|
|
768
|
-
}, [show, reposition]);
|
|
769
|
-
return /* @__PURE__ */ jsxs7("div", { ref, className: cn("inline-flex shrink-0", wrapperClassName), onMouseEnter: () => setShow(true), onMouseLeave: () => setShow(false), children: [
|
|
770
|
-
children,
|
|
771
|
-
show && createPortal3(
|
|
772
|
-
/* @__PURE__ */ jsx12("div", { ref: tooltipRef, style, children: /* @__PURE__ */ jsx12(Tooltip, { label, shortcut }) }),
|
|
773
|
-
document.body
|
|
774
|
-
)
|
|
775
|
-
] });
|
|
776
|
-
}
|
|
777
|
-
|
|
778
798
|
// src/IconButton.tsx
|
|
779
|
-
import {
|
|
799
|
+
import { Button as BaseButton2 } from "@base-ui/react/button";
|
|
800
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
780
801
|
function IconButton({
|
|
781
802
|
variant = "muted",
|
|
782
803
|
className,
|
|
783
804
|
children,
|
|
784
805
|
disabled,
|
|
806
|
+
disabledReason,
|
|
785
807
|
tooltip,
|
|
786
808
|
tooltipShortcut,
|
|
787
809
|
tooltipPlacement,
|
|
788
810
|
type = "button",
|
|
789
811
|
...props
|
|
790
812
|
}) {
|
|
791
|
-
const button = /* @__PURE__ */
|
|
792
|
-
|
|
813
|
+
const button = /* @__PURE__ */ jsx14(
|
|
814
|
+
BaseButton2,
|
|
793
815
|
{
|
|
794
816
|
type,
|
|
795
|
-
|
|
817
|
+
disabled: disabled || !!disabledReason,
|
|
818
|
+
focusableWhenDisabled: !!disabledReason,
|
|
819
|
+
className: (state) => cn(
|
|
796
820
|
"flex items-center justify-center p-1 rounded-lg transition-colors shrink-0 cursor-pointer",
|
|
797
|
-
!disabled && variant === "primary" && "bg-accent-primary hover:bg-accent-hover text-text-inverse",
|
|
798
|
-
!disabled && variant === "muted" && "text-text-secondary hover:bg-bg-hover hover:text-text-primary",
|
|
799
|
-
!disabled && variant === "outlined" && "border border-border-default hover:bg-bg-hover text-text-secondary",
|
|
800
|
-
disabled && variant === "primary" && "bg-bg-disabled text-text-disabled",
|
|
801
|
-
disabled && variant === "muted" && "text-text-disabled",
|
|
802
|
-
disabled && variant === "outlined" && "border border-border-default text-text-disabled",
|
|
803
|
-
disabled && "pointer-events-none cursor-not-allowed",
|
|
821
|
+
!state.disabled && variant === "primary" && "bg-accent-primary hover:bg-accent-hover text-text-inverse",
|
|
822
|
+
!state.disabled && variant === "muted" && "text-text-secondary hover:bg-bg-hover hover:text-text-primary",
|
|
823
|
+
!state.disabled && variant === "outlined" && "border border-border-default hover:bg-bg-hover text-text-secondary",
|
|
824
|
+
state.disabled && variant === "primary" && "bg-bg-disabled text-text-disabled",
|
|
825
|
+
state.disabled && variant === "muted" && "text-text-disabled",
|
|
826
|
+
state.disabled && variant === "outlined" && "border border-border-default text-text-disabled",
|
|
827
|
+
state.disabled && "pointer-events-none cursor-not-allowed",
|
|
804
828
|
className
|
|
805
829
|
),
|
|
806
|
-
disabled,
|
|
807
830
|
...props,
|
|
808
831
|
children
|
|
809
832
|
}
|
|
810
833
|
);
|
|
811
|
-
|
|
812
|
-
|
|
834
|
+
const label = disabledReason ?? tooltip;
|
|
835
|
+
if (label) {
|
|
836
|
+
return /* @__PURE__ */ jsx14(WithTooltip, { label, shortcut: disabledReason ? void 0 : tooltipShortcut, placement: tooltipPlacement, children: button });
|
|
813
837
|
}
|
|
814
838
|
return button;
|
|
815
839
|
}
|
|
@@ -818,9 +842,9 @@ function IconButton({
|
|
|
818
842
|
import { useRef as useRef4, useState as useState5 } from "react";
|
|
819
843
|
|
|
820
844
|
// src/Divider.tsx
|
|
821
|
-
import { jsx as
|
|
845
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
822
846
|
function Divider({ orientation = "horizontal", className }) {
|
|
823
|
-
return /* @__PURE__ */
|
|
847
|
+
return /* @__PURE__ */ jsx15(
|
|
824
848
|
"div",
|
|
825
849
|
{
|
|
826
850
|
role: "separator",
|
|
@@ -831,61 +855,59 @@ function Divider({ orientation = "horizontal", className }) {
|
|
|
831
855
|
}
|
|
832
856
|
|
|
833
857
|
// src/Person.tsx
|
|
834
|
-
import { jsx as
|
|
858
|
+
import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
835
859
|
function Person({ name, picture, fallback = "\u2014", size = 20, className }) {
|
|
836
860
|
return (
|
|
837
861
|
// gap-2: the face-to-name distance is one rule (8px) wherever a person
|
|
838
862
|
// appears — Katerina, 2026-09-01, set on Person so PersonTrigger and every
|
|
839
863
|
// row agree by construction.
|
|
840
864
|
/* @__PURE__ */ jsxs8("span", { className: cn("flex min-w-0 items-center gap-2", className), children: [
|
|
841
|
-
/* @__PURE__ */
|
|
842
|
-
/* @__PURE__ */
|
|
865
|
+
/* @__PURE__ */ jsx16(Avatar, { name, src: picture, size }),
|
|
866
|
+
/* @__PURE__ */ jsx16("span", { className: cn("truncate", !name && "text-text-muted"), children: name ?? fallback })
|
|
843
867
|
] })
|
|
844
868
|
);
|
|
845
869
|
}
|
|
846
870
|
|
|
847
871
|
// src/PersonTrigger.tsx
|
|
872
|
+
import { Button as BaseButton3 } from "@base-ui/react/button";
|
|
848
873
|
import { IconChevronDown } from "@tabler/icons-react";
|
|
849
|
-
import { jsx as
|
|
874
|
+
import { jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
850
875
|
function PersonTrigger({ name, picture, fallback, size, open = false, compact = false, className, ...props }) {
|
|
851
876
|
if (compact) {
|
|
852
|
-
return /* @__PURE__ */
|
|
853
|
-
|
|
877
|
+
return /* @__PURE__ */ jsx17(
|
|
878
|
+
BaseButton3,
|
|
854
879
|
{
|
|
855
880
|
type: "button",
|
|
856
881
|
"aria-haspopup": "menu",
|
|
857
882
|
"aria-expanded": open,
|
|
858
883
|
className: cn("cursor-pointer rounded-full focus:outline-none", className),
|
|
859
884
|
...props,
|
|
860
|
-
children: /* @__PURE__ */
|
|
885
|
+
children: /* @__PURE__ */ jsx17(Avatar, { name, src: picture, size: size ?? 36 })
|
|
861
886
|
}
|
|
862
887
|
);
|
|
863
888
|
}
|
|
864
889
|
return /* @__PURE__ */ jsxs9(
|
|
865
|
-
|
|
890
|
+
BaseButton3,
|
|
866
891
|
{
|
|
867
892
|
type: "button",
|
|
868
893
|
"aria-haspopup": "menu",
|
|
869
894
|
"aria-expanded": open,
|
|
870
895
|
className: cn(
|
|
871
|
-
|
|
872
|
-
// cn(), and tw-merge silently drops a custom text-{size} once a
|
|
873
|
-
// text-{colour} follows it. Measured: the name rendered 16px.
|
|
874
|
-
"flex h-8 cursor-pointer items-center gap-1.5 rounded-md pl-1.5 pr-1.5 text-[14px] leading-[140%] text-text-primary transition-colors hover:bg-bg-hover",
|
|
896
|
+
"flex h-8 cursor-pointer items-center gap-1.5 rounded-md pl-1.5 pr-1.5 text-body-2 text-text-primary transition-colors hover:bg-bg-hover",
|
|
875
897
|
open && "bg-bg-hover",
|
|
876
898
|
className
|
|
877
899
|
),
|
|
878
900
|
...props,
|
|
879
901
|
children: [
|
|
880
|
-
/* @__PURE__ */
|
|
881
|
-
/* @__PURE__ */
|
|
902
|
+
/* @__PURE__ */ jsx17(Person, { name, picture, fallback, size: size ?? 22 }),
|
|
903
|
+
/* @__PURE__ */ jsx17(IconChevronDown, { size: 14, stroke: 1.5, className: "shrink-0 text-text-muted" })
|
|
882
904
|
]
|
|
883
905
|
}
|
|
884
906
|
);
|
|
885
907
|
}
|
|
886
908
|
|
|
887
909
|
// src/IdentityMenu.tsx
|
|
888
|
-
import { Fragment, jsx as
|
|
910
|
+
import { Fragment, jsx as jsx18, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
889
911
|
function IdentityPanel({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, onClose, anchor, className, children }) {
|
|
890
912
|
const act = (action) => () => {
|
|
891
913
|
onClose();
|
|
@@ -894,41 +916,41 @@ function IdentityPanel({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, o
|
|
|
894
916
|
const appRows = typeof children === "function" ? children(onClose) : children;
|
|
895
917
|
return /* @__PURE__ */ jsxs10(Menu, { onClose, anchor, align: "right", className: cn("w-72", className), children: [
|
|
896
918
|
/* @__PURE__ */ jsxs10(MenuSection, { label: signedIn ? "Signed in as" : "Acting as", children: [
|
|
897
|
-
/* @__PURE__ */
|
|
898
|
-
/* @__PURE__ */
|
|
919
|
+
/* @__PURE__ */ jsx18(MenuRow, { children: /* @__PURE__ */ jsx18(Person, { name: me.name, picture: me.picture, fallback: "Anonymous", size: 28, className: "text-body-2-strong" }) }),
|
|
920
|
+
/* @__PURE__ */ jsx18(Note, { children: signedIn ? "Your Estiva ID. The same person you are in every Estiva app." : "A key held by this browser only. Nobody else knows who you are." }),
|
|
899
921
|
me.email && /* @__PURE__ */ jsxs10(Note, { children: [
|
|
900
922
|
me.email,
|
|
901
923
|
" \xB7 known to Estiva, never published to the relay"
|
|
902
924
|
] })
|
|
903
925
|
] }),
|
|
904
926
|
relayUrl && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
905
|
-
/* @__PURE__ */
|
|
927
|
+
/* @__PURE__ */ jsx18(Divider, { className: "mx-0 my-2" }),
|
|
906
928
|
/* @__PURE__ */ jsxs10(MenuSection, { label: "Workspace", children: [
|
|
907
|
-
/* @__PURE__ */
|
|
908
|
-
/* @__PURE__ */
|
|
929
|
+
/* @__PURE__ */ jsx18(MenuRow, { children: /* @__PURE__ */ jsx18("span", { className: "break-all font-mono text-caption text-text-primary", children: relayUrl }) }),
|
|
930
|
+
/* @__PURE__ */ jsx18(Note, { children: "Everyone on this relay shares this workspace, in every app." })
|
|
909
931
|
] })
|
|
910
932
|
] }),
|
|
911
933
|
appRows && /* @__PURE__ */ jsxs10(Fragment, { children: [
|
|
912
|
-
/* @__PURE__ */
|
|
934
|
+
/* @__PURE__ */ jsx18(Divider, { className: "mx-0 my-2" }),
|
|
913
935
|
appRows
|
|
914
936
|
] }),
|
|
915
|
-
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */
|
|
916
|
-
signedIn && idBase && /* @__PURE__ */
|
|
937
|
+
signedIn && idBase || onCopyKey || idBase && onSignOut ? /* @__PURE__ */ jsx18(Divider, { className: "mx-0 my-2" }) : null,
|
|
938
|
+
signedIn && idBase && /* @__PURE__ */ jsx18(
|
|
917
939
|
MenuItem,
|
|
918
940
|
{
|
|
919
941
|
label: "Edit your profile in Estiva ID",
|
|
920
942
|
onClick: act(() => window.open(idBase, "_blank", "noopener,noreferrer"))
|
|
921
943
|
}
|
|
922
944
|
),
|
|
923
|
-
onCopyKey && /* @__PURE__ */
|
|
924
|
-
idBase && onSignOut && /* @__PURE__ */
|
|
945
|
+
onCopyKey && /* @__PURE__ */ jsx18(MenuItem, { label: "Copy public key", onClick: act(onCopyKey) }),
|
|
946
|
+
idBase && onSignOut && /* @__PURE__ */ jsx18(MenuItem, { label: "Sign out", onClick: act(onSignOut) })
|
|
925
947
|
] });
|
|
926
948
|
}
|
|
927
949
|
function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, compact = false, className, children }) {
|
|
928
950
|
const [open, setOpen] = useState5(false);
|
|
929
951
|
const anchorRef = useRef4(null);
|
|
930
952
|
return /* @__PURE__ */ jsxs10("div", { ref: anchorRef, className: cn("relative", className), children: [
|
|
931
|
-
/* @__PURE__ */
|
|
953
|
+
/* @__PURE__ */ jsx18(
|
|
932
954
|
PersonTrigger,
|
|
933
955
|
{
|
|
934
956
|
name: me.name,
|
|
@@ -942,7 +964,7 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
942
964
|
"aria-label": compact ? "Account menu" : void 0
|
|
943
965
|
}
|
|
944
966
|
),
|
|
945
|
-
open && /* @__PURE__ */
|
|
967
|
+
open && /* @__PURE__ */ jsx18(
|
|
946
968
|
IdentityPanel,
|
|
947
969
|
{
|
|
948
970
|
me,
|
|
@@ -959,12 +981,12 @@ function IdentityMenu({ me, signedIn, relayUrl, idBase, onCopyKey, onSignOut, co
|
|
|
959
981
|
] });
|
|
960
982
|
}
|
|
961
983
|
function Note({ children }) {
|
|
962
|
-
return /* @__PURE__ */
|
|
984
|
+
return /* @__PURE__ */ jsx18("span", { className: "px-2 pb-1.5 text-caption text-text-secondary", children });
|
|
963
985
|
}
|
|
964
986
|
|
|
965
987
|
// src/Field.tsx
|
|
966
988
|
import { createContext as createContext2, useContext as useContext2, useId } from "react";
|
|
967
|
-
import { jsx as
|
|
989
|
+
import { jsx as jsx19, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
968
990
|
var FieldControlIdContext = createContext2(void 0);
|
|
969
991
|
function useFieldControlId(ownId) {
|
|
970
992
|
const fromField = useContext2(FieldControlIdContext);
|
|
@@ -981,11 +1003,11 @@ function Field({ label, required = false, htmlFor, children }) {
|
|
|
981
1003
|
className: `text-input-label text-text-primary${required ? " flex items-center" : ""}`,
|
|
982
1004
|
children: [
|
|
983
1005
|
label,
|
|
984
|
-
required && /* @__PURE__ */
|
|
1006
|
+
required && /* @__PURE__ */ jsx19("span", { className: "text-error-default ml-0.5", children: "*" })
|
|
985
1007
|
]
|
|
986
1008
|
}
|
|
987
1009
|
),
|
|
988
|
-
/* @__PURE__ */
|
|
1010
|
+
/* @__PURE__ */ jsx19(FieldControlIdContext.Provider, { value: id, children })
|
|
989
1011
|
] });
|
|
990
1012
|
}
|
|
991
1013
|
|
|
@@ -993,7 +1015,7 @@ function Field({ label, required = false, htmlFor, children }) {
|
|
|
993
1015
|
import { IconCheck as IconCheck2, IconChevronDown as IconChevronDown2 } from "@tabler/icons-react";
|
|
994
1016
|
import { useCallback as useCallback3, useEffect as useEffect3, useId as useId2, useLayoutEffect as useLayoutEffect4, useMemo as useMemo2, useRef as useRef5, useState as useState6 } from "react";
|
|
995
1017
|
import { createPortal as createPortal4 } from "react-dom";
|
|
996
|
-
import { Fragment as Fragment2, jsx as
|
|
1018
|
+
import { Fragment as Fragment2, jsx as jsx20, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
997
1019
|
function Select({ value, onChange, options, size = "default", ariaLabel, placeholder = "Select\u2026", disabled, className }) {
|
|
998
1020
|
const id = useId2();
|
|
999
1021
|
const triggerRef = useRef5(null);
|
|
@@ -1133,15 +1155,15 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1133
1155
|
),
|
|
1134
1156
|
children: [
|
|
1135
1157
|
/* @__PURE__ */ jsxs12("span", { className: cn("flex min-w-0 items-center gap-2", !selected && "text-text-muted"), children: [
|
|
1136
|
-
selected?.leading && /* @__PURE__ */
|
|
1137
|
-
/* @__PURE__ */
|
|
1158
|
+
selected?.leading && /* @__PURE__ */ jsx20("span", { className: "flex shrink-0 items-center", children: selected.leading }),
|
|
1159
|
+
/* @__PURE__ */ jsx20("span", { className: "truncate", children: selected?.label ?? placeholder })
|
|
1138
1160
|
] }),
|
|
1139
|
-
/* @__PURE__ */
|
|
1161
|
+
/* @__PURE__ */ jsx20(IconChevronDown2, { size: size === "small" ? 14 : 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1140
1162
|
]
|
|
1141
1163
|
}
|
|
1142
1164
|
),
|
|
1143
1165
|
open && rect && createPortal4(
|
|
1144
|
-
/* @__PURE__ */
|
|
1166
|
+
/* @__PURE__ */ jsx20(
|
|
1145
1167
|
"div",
|
|
1146
1168
|
{
|
|
1147
1169
|
ref: menuRef,
|
|
@@ -1174,10 +1196,10 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1174
1196
|
),
|
|
1175
1197
|
children: [
|
|
1176
1198
|
/* @__PURE__ */ jsxs12("span", { className: "flex min-w-0 items-center gap-2", children: [
|
|
1177
|
-
option.leading && /* @__PURE__ */
|
|
1178
|
-
/* @__PURE__ */
|
|
1199
|
+
option.leading && /* @__PURE__ */ jsx20("span", { className: "flex shrink-0 items-center", children: option.leading }),
|
|
1200
|
+
/* @__PURE__ */ jsx20("span", { className: "truncate", children: option.label })
|
|
1179
1201
|
] }),
|
|
1180
|
-
option.value === value && /* @__PURE__ */
|
|
1202
|
+
option.value === value && /* @__PURE__ */ jsx20(IconCheck2, { size: 16, stroke: 1.5, className: "shrink-0 text-text-secondary" })
|
|
1181
1203
|
]
|
|
1182
1204
|
},
|
|
1183
1205
|
option.value
|
|
@@ -1191,10 +1213,10 @@ function Select({ value, onChange, options, size = "default", ariaLabel, placeho
|
|
|
1191
1213
|
|
|
1192
1214
|
// src/TextInput.tsx
|
|
1193
1215
|
import { forwardRef } from "react";
|
|
1194
|
-
import { jsx as
|
|
1216
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1195
1217
|
var TextInput = forwardRef(function TextInput2({ className, type = "text", id, ...props }, ref) {
|
|
1196
1218
|
const controlId = useFieldControlId(id);
|
|
1197
|
-
return /* @__PURE__ */
|
|
1219
|
+
return /* @__PURE__ */ jsx21(
|
|
1198
1220
|
"input",
|
|
1199
1221
|
{
|
|
1200
1222
|
ref,
|
|
@@ -1215,10 +1237,10 @@ var TextInput = forwardRef(function TextInput2({ className, type = "text", id, .
|
|
|
1215
1237
|
|
|
1216
1238
|
// src/Textarea.tsx
|
|
1217
1239
|
import { forwardRef as forwardRef2 } from "react";
|
|
1218
|
-
import { jsx as
|
|
1240
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
1219
1241
|
var Textarea = forwardRef2(function Textarea2({ className, id, ...props }, ref) {
|
|
1220
1242
|
const controlId = useFieldControlId(id);
|
|
1221
|
-
return /* @__PURE__ */
|
|
1243
|
+
return /* @__PURE__ */ jsx22(
|
|
1222
1244
|
"textarea",
|
|
1223
1245
|
{
|
|
1224
1246
|
ref,
|
|
@@ -1243,7 +1265,7 @@ import { useState as useState7 } from "react";
|
|
|
1243
1265
|
import { useEffect as useEffect4 } from "react";
|
|
1244
1266
|
import { createPortal as createPortal5 } from "react-dom";
|
|
1245
1267
|
import { IconX as IconX2 } from "@tabler/icons-react";
|
|
1246
|
-
import { Fragment as Fragment3, jsx as
|
|
1268
|
+
import { Fragment as Fragment3, jsx as jsx23, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
1247
1269
|
function DialogShell({ title, onClose, headerContent, footer, children, bodyClassName, width = 502 }) {
|
|
1248
1270
|
useEffect4(() => {
|
|
1249
1271
|
const onKey = (event) => {
|
|
@@ -1254,8 +1276,8 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1254
1276
|
}, [onClose]);
|
|
1255
1277
|
return createPortal5(
|
|
1256
1278
|
/* @__PURE__ */ jsxs13(Fragment3, { children: [
|
|
1257
|
-
/* @__PURE__ */
|
|
1258
|
-
/* @__PURE__ */
|
|
1279
|
+
/* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-40 bg-scrim", onClick: onClose }),
|
|
1280
|
+
/* @__PURE__ */ jsx23("div", { className: "fixed inset-0 z-50 flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ jsxs13(
|
|
1259
1281
|
"div",
|
|
1260
1282
|
{
|
|
1261
1283
|
role: "dialog",
|
|
@@ -1265,11 +1287,11 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1265
1287
|
style: { width },
|
|
1266
1288
|
children: [
|
|
1267
1289
|
/* @__PURE__ */ jsxs13("div", { className: "h-12 flex items-center justify-between pl-5 pr-4 border-b border-border-subtle shrink-0", children: [
|
|
1268
|
-
headerContent ?? /* @__PURE__ */
|
|
1269
|
-
/* @__PURE__ */
|
|
1290
|
+
headerContent ?? /* @__PURE__ */ jsx23("span", { className: "text-h4 text-text-primary", children: title }),
|
|
1291
|
+
/* @__PURE__ */ jsx23(IconButton, { tooltip: "Close", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx23(IconX2, { size: 16, stroke: 1.5 }) })
|
|
1270
1292
|
] }),
|
|
1271
|
-
/* @__PURE__ */
|
|
1272
|
-
footer != null && /* @__PURE__ */
|
|
1293
|
+
/* @__PURE__ */ jsx23("div", { className: cn("pl-5 pr-4 py-4", footer != null && "border-b border-border-subtle", bodyClassName), children }),
|
|
1294
|
+
footer != null && /* @__PURE__ */ jsx23("div", { className: "h-12 flex items-center justify-end gap-2 pl-5 pr-4 shrink-0", children: footer })
|
|
1273
1295
|
]
|
|
1274
1296
|
}
|
|
1275
1297
|
) })
|
|
@@ -1279,7 +1301,7 @@ function DialogShell({ title, onClose, headerContent, footer, children, bodyClas
|
|
|
1279
1301
|
}
|
|
1280
1302
|
|
|
1281
1303
|
// src/ConfirmDialog.tsx
|
|
1282
|
-
import { Fragment as Fragment4, jsx as
|
|
1304
|
+
import { Fragment as Fragment4, jsx as jsx24, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1283
1305
|
function ConfirmDialog({ title, children, confirmLabel, destructive = false, onConfirm, onClose }) {
|
|
1284
1306
|
const [busy, setBusy] = useState7(false);
|
|
1285
1307
|
const confirm = async () => {
|
|
@@ -1291,15 +1313,15 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1291
1313
|
setBusy(false);
|
|
1292
1314
|
}
|
|
1293
1315
|
};
|
|
1294
|
-
return /* @__PURE__ */
|
|
1316
|
+
return /* @__PURE__ */ jsx24(
|
|
1295
1317
|
DialogShell,
|
|
1296
1318
|
{
|
|
1297
1319
|
title,
|
|
1298
1320
|
onClose,
|
|
1299
1321
|
bodyClassName: "flex flex-col gap-3 text-body-2 text-text-primary",
|
|
1300
1322
|
footer: /* @__PURE__ */ jsxs14(Fragment4, { children: [
|
|
1301
|
-
/* @__PURE__ */
|
|
1302
|
-
/* @__PURE__ */
|
|
1323
|
+
/* @__PURE__ */ jsx24(Button, { variant: "muted", onClick: onClose, disabled: busy, children: "Cancel" }),
|
|
1324
|
+
/* @__PURE__ */ jsx24(Button, { variant: destructive ? "destructive" : "primary", onClick: () => void confirm(), disabled: busy, children: confirmLabel })
|
|
1303
1325
|
] }),
|
|
1304
1326
|
children
|
|
1305
1327
|
}
|
|
@@ -1308,7 +1330,7 @@ function ConfirmDialog({ title, children, confirmLabel, destructive = false, onC
|
|
|
1308
1330
|
|
|
1309
1331
|
// src/EditableText.tsx
|
|
1310
1332
|
import { useEffect as useEffect5, useRef as useRef6, useState as useState8 } from "react";
|
|
1311
|
-
import { jsx as
|
|
1333
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1312
1334
|
function EditableText({ value, display, displayNode, placeholder, onCommit, multiline = false, className, label, readOnly = false }) {
|
|
1313
1335
|
const [editing, setEditing] = useState8(false);
|
|
1314
1336
|
const [draft, setDraft] = useState8(value);
|
|
@@ -1359,7 +1381,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1359
1381
|
className
|
|
1360
1382
|
);
|
|
1361
1383
|
if (readOnly) {
|
|
1362
|
-
return /* @__PURE__ */
|
|
1384
|
+
return /* @__PURE__ */ jsx25(
|
|
1363
1385
|
"div",
|
|
1364
1386
|
{
|
|
1365
1387
|
"aria-label": label,
|
|
@@ -1369,7 +1391,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1369
1391
|
);
|
|
1370
1392
|
}
|
|
1371
1393
|
if (editing) {
|
|
1372
|
-
return multiline ? /* @__PURE__ */
|
|
1394
|
+
return multiline ? /* @__PURE__ */ jsx25(
|
|
1373
1395
|
"textarea",
|
|
1374
1396
|
{
|
|
1375
1397
|
ref: fieldRef,
|
|
@@ -1382,7 +1404,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1382
1404
|
onBlur: () => void commit(),
|
|
1383
1405
|
className: fieldClass
|
|
1384
1406
|
}
|
|
1385
|
-
) : /* @__PURE__ */
|
|
1407
|
+
) : /* @__PURE__ */ jsx25(
|
|
1386
1408
|
"input",
|
|
1387
1409
|
{
|
|
1388
1410
|
ref: fieldRef,
|
|
@@ -1396,7 +1418,7 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1396
1418
|
}
|
|
1397
1419
|
);
|
|
1398
1420
|
}
|
|
1399
|
-
return /* @__PURE__ */
|
|
1421
|
+
return /* @__PURE__ */ jsx25(
|
|
1400
1422
|
"button",
|
|
1401
1423
|
{
|
|
1402
1424
|
type: "button",
|
|
@@ -1416,33 +1438,33 @@ function EditableText({ value, display, displayNode, placeholder, onCommit, mult
|
|
|
1416
1438
|
|
|
1417
1439
|
// src/EmptyState.tsx
|
|
1418
1440
|
import { IconMessage2 } from "@tabler/icons-react";
|
|
1419
|
-
import { jsx as
|
|
1441
|
+
import { jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1420
1442
|
function EmptyState({ icon, message, className }) {
|
|
1421
1443
|
return /* @__PURE__ */ jsxs15("div", { className: cn("flex flex-col gap-2 items-center", className), children: [
|
|
1422
|
-
/* @__PURE__ */
|
|
1423
|
-
/* @__PURE__ */
|
|
1444
|
+
/* @__PURE__ */ jsx26("span", { className: "text-text-secondary", children: icon ?? /* @__PURE__ */ jsx26(IconMessage2, { size: 16, stroke: 1.5 }) }),
|
|
1445
|
+
/* @__PURE__ */ jsx26("p", { className: "text-body-2 text-text-secondary text-center", children: message })
|
|
1424
1446
|
] });
|
|
1425
1447
|
}
|
|
1426
1448
|
|
|
1427
1449
|
// src/Skeleton.tsx
|
|
1428
|
-
import { jsx as
|
|
1450
|
+
import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
1429
1451
|
function SkeletonBar({ className, style }) {
|
|
1430
|
-
return /* @__PURE__ */
|
|
1452
|
+
return /* @__PURE__ */ jsx27("div", { className: cn("bg-bg-inset rounded-sm animate-pulse", className), style });
|
|
1431
1453
|
}
|
|
1432
1454
|
var ROW_BAR_WIDTHS = [150, 100, 170, 120, 90, 140, 110, 160];
|
|
1433
1455
|
function SkeletonRow({ barWidth = 130 }) {
|
|
1434
1456
|
return /* @__PURE__ */ jsxs16("div", { className: "flex items-center gap-2 px-2 h-[32px] rounded-lg", children: [
|
|
1435
|
-
/* @__PURE__ */
|
|
1436
|
-
/* @__PURE__ */
|
|
1457
|
+
/* @__PURE__ */ jsx27(SkeletonBar, { className: "w-4 h-4 shrink-0" }),
|
|
1458
|
+
/* @__PURE__ */ jsx27(SkeletonBar, { className: "h-3.5", style: { width: barWidth } })
|
|
1437
1459
|
] });
|
|
1438
1460
|
}
|
|
1439
1461
|
function SkeletonList({ rows = 8, className }) {
|
|
1440
|
-
return /* @__PURE__ */
|
|
1462
|
+
return /* @__PURE__ */ jsx27("div", { className: cn("flex flex-col gap-0.5 animate-skeleton-in", className), "aria-hidden": true, children: Array.from({ length: rows }, (_, i) => /* @__PURE__ */ jsx27(SkeletonRow, { barWidth: ROW_BAR_WIDTHS[i % ROW_BAR_WIDTHS.length] }, i)) });
|
|
1441
1463
|
}
|
|
1442
1464
|
|
|
1443
1465
|
// src/Breadcrumb.tsx
|
|
1444
1466
|
import { Fragment as Fragment5, useCallback as useCallback4, useLayoutEffect as useLayoutEffect5, useRef as useRef7, useState as useState9 } from "react";
|
|
1445
|
-
import { jsx as
|
|
1467
|
+
import { jsx as jsx28, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
1446
1468
|
function Breadcrumb({ items, className }) {
|
|
1447
1469
|
const navRef = useRef7(null);
|
|
1448
1470
|
const labelRefs = useRef7([]);
|
|
@@ -1462,7 +1484,7 @@ function Breadcrumb({ items, className }) {
|
|
|
1462
1484
|
observer.observe(nav);
|
|
1463
1485
|
return () => observer.disconnect();
|
|
1464
1486
|
}, [measure, items]);
|
|
1465
|
-
return /* @__PURE__ */
|
|
1487
|
+
return /* @__PURE__ */ jsx28("nav", { ref: navRef, "aria-label": "Breadcrumb", className: cn("flex min-w-0 items-center gap-1.5 text-[14px] leading-[140%]", className), children: items.map((item, index) => {
|
|
1466
1488
|
const last = index === items.length - 1;
|
|
1467
1489
|
const text = cn(
|
|
1468
1490
|
"truncate",
|
|
@@ -1475,21 +1497,21 @@ function Breadcrumb({ items, className }) {
|
|
|
1475
1497
|
const setLabelRef = (el) => {
|
|
1476
1498
|
labelRefs.current[index] = el;
|
|
1477
1499
|
};
|
|
1478
|
-
const crumb = item.href ? /* @__PURE__ */
|
|
1500
|
+
const crumb = item.href ? /* @__PURE__ */ jsx28("a", { ref: setLabelRef, href: item.href, className: cn(text, "hover:text-text-primary"), children: item.label }) : /* @__PURE__ */ jsx28("span", { ref: setLabelRef, className: text, "aria-current": last ? "page" : void 0, children: item.label });
|
|
1479
1501
|
return /* @__PURE__ */ jsxs17(Fragment5, { children: [
|
|
1480
|
-
index > 0 && /* @__PURE__ */
|
|
1502
|
+
index > 0 && /* @__PURE__ */ jsx28("span", { "aria-hidden": "true", className: "shrink-0 text-text-muted", children: "/" }),
|
|
1481
1503
|
truncated.has(index) ? (
|
|
1482
1504
|
// `min-w-0 shrink` undoes the wrapper's own shrink-0 — the crumb
|
|
1483
1505
|
// must keep truncating inside it, or wrapping it would widen the
|
|
1484
1506
|
// trail and the tooltip would never be needed again.
|
|
1485
|
-
/* @__PURE__ */
|
|
1507
|
+
/* @__PURE__ */ jsx28(WithTooltip, { label: item.label, wrapperClassName: "min-w-0 shrink", children: crumb })
|
|
1486
1508
|
) : crumb
|
|
1487
1509
|
] }, `${item.label}-${index}`);
|
|
1488
1510
|
}) });
|
|
1489
1511
|
}
|
|
1490
1512
|
|
|
1491
1513
|
// src/NavItem.tsx
|
|
1492
|
-
import { jsx as
|
|
1514
|
+
import { jsx as jsx29, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
1493
1515
|
function NavItem({ label, href, count, countLabel, active = false, icon, className, ...props }) {
|
|
1494
1516
|
return /* @__PURE__ */ jsxs18(
|
|
1495
1517
|
"a",
|
|
@@ -1506,22 +1528,22 @@ function NavItem({ label, href, count, countLabel, active = false, icon, classNa
|
|
|
1506
1528
|
),
|
|
1507
1529
|
...props,
|
|
1508
1530
|
children: [
|
|
1509
|
-
icon && /* @__PURE__ */
|
|
1510
|
-
/* @__PURE__ */
|
|
1511
|
-
count ? /* @__PURE__ */
|
|
1531
|
+
icon && /* @__PURE__ */ jsx29("span", { className: "flex shrink-0 items-center", children: icon }),
|
|
1532
|
+
/* @__PURE__ */ jsx29("span", { className: "flex-1 truncate", children: label }),
|
|
1533
|
+
count ? /* @__PURE__ */ jsx29(WithTooltip, { label: countLabel ?? `${count} open`, children: /* @__PURE__ */ jsx29("span", { className: "shrink-0 font-mono text-caption tabular-nums text-text-muted", children: count }) }) : null
|
|
1512
1534
|
]
|
|
1513
1535
|
}
|
|
1514
1536
|
);
|
|
1515
1537
|
}
|
|
1516
1538
|
|
|
1517
1539
|
// src/Rail.tsx
|
|
1518
|
-
import { jsx as
|
|
1540
|
+
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
1519
1541
|
function Rail({ "aria-label": ariaLabel = "Navigation", children, className }) {
|
|
1520
|
-
return /* @__PURE__ */
|
|
1542
|
+
return /* @__PURE__ */ jsx30("nav", { "aria-label": ariaLabel, className: cn("flex w-16 shrink-0 flex-col items-start gap-2 px-2 py-3", className), children });
|
|
1521
1543
|
}
|
|
1522
1544
|
|
|
1523
1545
|
// src/RailItem.tsx
|
|
1524
|
-
import { jsx as
|
|
1546
|
+
import { jsx as jsx31, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
1525
1547
|
function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
1526
1548
|
return /* @__PURE__ */ jsxs19(
|
|
1527
1549
|
"a",
|
|
@@ -1531,14 +1553,14 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
1531
1553
|
className: cn("group flex w-full shrink-0 flex-col items-center gap-0.5 px-2 py-0.5", className),
|
|
1532
1554
|
...props,
|
|
1533
1555
|
children: [
|
|
1534
|
-
/* @__PURE__ */
|
|
1556
|
+
/* @__PURE__ */ jsx31(
|
|
1535
1557
|
"div",
|
|
1536
1558
|
{
|
|
1537
1559
|
className: cn(
|
|
1538
1560
|
"flex items-center justify-center rounded-lg p-2 transition-colors",
|
|
1539
1561
|
active ? "bg-bg-selected" : "group-hover:bg-bg-hover"
|
|
1540
1562
|
),
|
|
1541
|
-
children: /* @__PURE__ */
|
|
1563
|
+
children: /* @__PURE__ */ jsx31(
|
|
1542
1564
|
"span",
|
|
1543
1565
|
{
|
|
1544
1566
|
className: cn(
|
|
@@ -1550,16 +1572,16 @@ function RailItem({ href, icon, label, active = false, className, ...props }) {
|
|
|
1550
1572
|
)
|
|
1551
1573
|
}
|
|
1552
1574
|
),
|
|
1553
|
-
/* @__PURE__ */
|
|
1575
|
+
/* @__PURE__ */ jsx31("span", { className: cn("text-center text-[9px] font-medium leading-[115%]", active ? "text-text-primary" : "text-text-secondary"), children: label })
|
|
1554
1576
|
]
|
|
1555
1577
|
}
|
|
1556
1578
|
);
|
|
1557
1579
|
}
|
|
1558
1580
|
|
|
1559
1581
|
// src/Sidebar.tsx
|
|
1560
|
-
import { jsx as
|
|
1582
|
+
import { jsx as jsx32 } from "react/jsx-runtime";
|
|
1561
1583
|
function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className }) {
|
|
1562
|
-
return /* @__PURE__ */
|
|
1584
|
+
return /* @__PURE__ */ jsx32(
|
|
1563
1585
|
"nav",
|
|
1564
1586
|
{
|
|
1565
1587
|
"aria-label": ariaLabel,
|
|
@@ -1573,7 +1595,7 @@ function Sidebar({ "aria-label": ariaLabel = "Workspace", children, className })
|
|
|
1573
1595
|
}
|
|
1574
1596
|
|
|
1575
1597
|
// src/Property.tsx
|
|
1576
|
-
import { jsx as
|
|
1598
|
+
import { jsx as jsx33, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
1577
1599
|
function Property({ label, layout = "row", children, className }) {
|
|
1578
1600
|
if (layout === "stacked") {
|
|
1579
1601
|
return (
|
|
@@ -1581,19 +1603,19 @@ function Property({ label, layout = "row", children, className }) {
|
|
|
1581
1603
|
// Peek's topic-details sections already sit at 12px, Ship's rail was
|
|
1582
1604
|
// 6px, and unifying means the bigger, calmer one.
|
|
1583
1605
|
/* @__PURE__ */ jsxs20("div", { className: cn("flex flex-col gap-3", className), children: [
|
|
1584
|
-
/* @__PURE__ */
|
|
1606
|
+
/* @__PURE__ */ jsx33("span", { className: "text-menu uppercase tracking-[0.08em] text-text-secondary", children: label }),
|
|
1585
1607
|
children
|
|
1586
1608
|
] })
|
|
1587
1609
|
);
|
|
1588
1610
|
}
|
|
1589
1611
|
return /* @__PURE__ */ jsxs20("div", { className: cn("flex items-center gap-2", className), children: [
|
|
1590
|
-
/* @__PURE__ */
|
|
1612
|
+
/* @__PURE__ */ jsx33("span", { className: "w-[68px] shrink-0 text-caption text-text-secondary", children: label }),
|
|
1591
1613
|
children
|
|
1592
1614
|
] });
|
|
1593
1615
|
}
|
|
1594
1616
|
|
|
1595
1617
|
// src/Reaction.tsx
|
|
1596
|
-
import { jsx as
|
|
1618
|
+
import { jsx as jsx34, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
1597
1619
|
function Reaction({ emoji, count, pressed = false, className, type, ...props }) {
|
|
1598
1620
|
return /* @__PURE__ */ jsxs21(
|
|
1599
1621
|
"button",
|
|
@@ -1611,8 +1633,8 @@ function Reaction({ emoji, count, pressed = false, className, type, ...props })
|
|
|
1611
1633
|
),
|
|
1612
1634
|
...props,
|
|
1613
1635
|
children: [
|
|
1614
|
-
/* @__PURE__ */
|
|
1615
|
-
/* @__PURE__ */
|
|
1636
|
+
/* @__PURE__ */ jsx34("span", { "aria-hidden": "true", className: "shrink-0 text-[16px] leading-none", children: emoji }),
|
|
1637
|
+
/* @__PURE__ */ jsx34("span", { className: "text-chip signal:font-mono signal:text-[10px] signal:font-semibold signal:tabular-nums", children: count })
|
|
1616
1638
|
]
|
|
1617
1639
|
}
|
|
1618
1640
|
);
|
|
@@ -1620,7 +1642,7 @@ function Reaction({ emoji, count, pressed = false, className, type, ...props })
|
|
|
1620
1642
|
|
|
1621
1643
|
// src/SearchInput.tsx
|
|
1622
1644
|
import "react";
|
|
1623
|
-
import { jsx as
|
|
1645
|
+
import { jsx as jsx35, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
1624
1646
|
function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...props }) {
|
|
1625
1647
|
return /* @__PURE__ */ jsxs22(
|
|
1626
1648
|
"div",
|
|
@@ -1632,7 +1654,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1632
1654
|
className
|
|
1633
1655
|
),
|
|
1634
1656
|
children: [
|
|
1635
|
-
/* @__PURE__ */
|
|
1657
|
+
/* @__PURE__ */ jsx35(
|
|
1636
1658
|
"input",
|
|
1637
1659
|
{
|
|
1638
1660
|
className: "flex-1 min-w-0 bg-transparent text-input-value text-text-primary placeholder:text-text-muted outline-none",
|
|
@@ -1640,7 +1662,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1640
1662
|
...props
|
|
1641
1663
|
}
|
|
1642
1664
|
),
|
|
1643
|
-
shortcut && /* @__PURE__ */
|
|
1665
|
+
shortcut && /* @__PURE__ */ jsx35(Kbd, { children: shortcut })
|
|
1644
1666
|
]
|
|
1645
1667
|
}
|
|
1646
1668
|
);
|
|
@@ -1649,7 +1671,7 @@ function SearchInput({ shortcut, className, placeholder = "Search\u2026", ...pro
|
|
|
1649
1671
|
// src/SectionHeader.tsx
|
|
1650
1672
|
import { useState as useState10 } from "react";
|
|
1651
1673
|
import { IconChevronRight as IconChevronRight2 } from "@tabler/icons-react";
|
|
1652
|
-
import { jsx as
|
|
1674
|
+
import { jsx as jsx36, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
1653
1675
|
function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, actions, showActions = "hover", className }) {
|
|
1654
1676
|
const [isHovered, setIsHovered] = useState10(false);
|
|
1655
1677
|
return /* @__PURE__ */ jsxs23(
|
|
@@ -1666,7 +1688,7 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
|
|
|
1666
1688
|
onMouseLeave: () => setIsHovered(false),
|
|
1667
1689
|
children: [
|
|
1668
1690
|
/* @__PURE__ */ jsxs23("div", { className: "flex shrink-0 items-center gap-1", children: [
|
|
1669
|
-
chevron && /* @__PURE__ */
|
|
1691
|
+
chevron && /* @__PURE__ */ jsx36(
|
|
1670
1692
|
IconChevronRight2,
|
|
1671
1693
|
{
|
|
1672
1694
|
size: 12,
|
|
@@ -1674,9 +1696,9 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
|
|
|
1674
1696
|
className: cn("text-text-secondary transition-transform duration-150", isExpanded && "rotate-90")
|
|
1675
1697
|
}
|
|
1676
1698
|
),
|
|
1677
|
-
/* @__PURE__ */
|
|
1699
|
+
/* @__PURE__ */ jsx36(SectionLabel, { children: title })
|
|
1678
1700
|
] }),
|
|
1679
|
-
(showActions === "always" || isHovered) && actions && actions.length > 0 && /* @__PURE__ */
|
|
1701
|
+
(showActions === "always" || isHovered) && actions && actions.length > 0 && /* @__PURE__ */ jsx36("div", { className: "flex items-center gap-1", children: actions.map((action) => /* @__PURE__ */ jsx36(
|
|
1680
1702
|
IconButton,
|
|
1681
1703
|
{
|
|
1682
1704
|
tooltip: action.tooltip,
|
|
@@ -1695,53 +1717,58 @@ function SectionHeader({ title, chevron = false, isExpanded = true, onToggle, ac
|
|
|
1695
1717
|
}
|
|
1696
1718
|
|
|
1697
1719
|
// src/Tabs.tsx
|
|
1698
|
-
import {
|
|
1720
|
+
import { Tabs as BaseTabs } from "@base-ui/react/tabs";
|
|
1721
|
+
import { jsx as jsx37, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
1699
1722
|
function Tabs({ tabs, active, onChange, size = "default", className }) {
|
|
1700
|
-
return /* @__PURE__ */
|
|
1701
|
-
|
|
1723
|
+
return /* @__PURE__ */ jsx37(
|
|
1724
|
+
BaseTabs.Root,
|
|
1702
1725
|
{
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
className
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1726
|
+
value: active,
|
|
1727
|
+
onValueChange: (value, details) => {
|
|
1728
|
+
if (details.reason === "none") onChange(value);
|
|
1729
|
+
},
|
|
1730
|
+
className,
|
|
1731
|
+
children: /* @__PURE__ */ jsx37(BaseTabs.List, { activateOnFocus: true, className: "flex items-center gap-2", children: tabs.map((tab) => /* @__PURE__ */ jsxs24(
|
|
1732
|
+
BaseTabs.Tab,
|
|
1733
|
+
{
|
|
1734
|
+
value: tab.id,
|
|
1735
|
+
className: (state) => cn(
|
|
1736
|
+
"flex cursor-pointer items-center transition-colors",
|
|
1737
|
+
// gap: default is Ship's 6px; small keeps Peek's original 4px, or
|
|
1738
|
+
// "small is Peek's geometry" stops being true.
|
|
1739
|
+
size === "default" ? "gap-1.5 rounded-md px-2 py-1 text-body-2" : "gap-1 rounded px-1.5 py-0.5 text-caption",
|
|
1740
|
+
state.active ? "bg-bg-active text-text-primary" : "text-text-secondary hover:bg-bg-hover"
|
|
1741
|
+
),
|
|
1742
|
+
children: [
|
|
1743
|
+
tab.icon,
|
|
1744
|
+
/* @__PURE__ */ jsxs24("span", { className: "flex items-baseline", children: [
|
|
1745
|
+
tab.label,
|
|
1746
|
+
tab.count !== void 0 ? /* @__PURE__ */ jsx37("span", { className: "ml-2.5 font-mono text-caption tabular-nums text-text-secondary", children: tab.count }) : null
|
|
1747
|
+
] })
|
|
1748
|
+
]
|
|
1749
|
+
},
|
|
1750
|
+
tab.id
|
|
1751
|
+
)) })
|
|
1752
|
+
}
|
|
1753
|
+
);
|
|
1727
1754
|
}
|
|
1728
1755
|
|
|
1729
1756
|
// src/Toast.tsx
|
|
1730
1757
|
import { createContext as createContext3, useCallback as useCallback5, useContext as useContext3, useEffect as useEffect6, useMemo as useMemo3, useState as useState11 } from "react";
|
|
1731
1758
|
import { createPortal as createPortal6 } from "react-dom";
|
|
1732
1759
|
import { IconCircleCheck } from "@tabler/icons-react";
|
|
1733
|
-
import { jsx as
|
|
1734
|
-
var
|
|
1760
|
+
import { jsx as jsx38, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
1761
|
+
var SURFACE_STYLES = {
|
|
1735
1762
|
success: "bg-success-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
1736
1763
|
brand: "bg-accent-muted signal:bg-bg-inset signal:border signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]",
|
|
1737
1764
|
neutral: "bg-bg-inset border border-border-subtle signal:border-border-default signal:shadow-[shadow:var(--shadow-md)]"
|
|
1738
1765
|
};
|
|
1739
|
-
var
|
|
1740
|
-
success: "signal:text-success-default signal:drop-shadow-
|
|
1741
|
-
brand: "signal:text-text-interactive signal:drop-shadow-
|
|
1766
|
+
var ICON_STYLES = {
|
|
1767
|
+
success: "signal:text-success-default signal:drop-shadow-glow-success",
|
|
1768
|
+
brand: "signal:text-text-interactive signal:drop-shadow-glow-accent",
|
|
1742
1769
|
neutral: "signal:text-text-secondary"
|
|
1743
1770
|
};
|
|
1744
|
-
var
|
|
1771
|
+
var ACTION_BORDER_STYLES = {
|
|
1745
1772
|
success: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
1746
1773
|
brand: "signal:border signal:border-border-default signal:hover:border-border-strong",
|
|
1747
1774
|
neutral: "border border-border-default"
|
|
@@ -1756,25 +1783,25 @@ function Toast({ label, type = "neutral", leadingIcon = true, actionLabel, onAct
|
|
|
1756
1783
|
// Without an action the label needs real right padding; the action
|
|
1757
1784
|
// button brings its own edge, so the tight pr-1 only applies there.
|
|
1758
1785
|
hasAction ? "pr-1 gap-[46px]" : "pr-3",
|
|
1759
|
-
|
|
1786
|
+
SURFACE_STYLES[type],
|
|
1760
1787
|
className
|
|
1761
1788
|
),
|
|
1762
1789
|
children: [
|
|
1763
1790
|
/* @__PURE__ */ jsxs25("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
1764
|
-
leadingIcon && /* @__PURE__ */
|
|
1765
|
-
/* @__PURE__ */
|
|
1791
|
+
leadingIcon && /* @__PURE__ */ jsx38(IconCircleCheck, { size: 16, stroke: 1.5, className: cn("text-text-primary shrink-0", ICON_STYLES[type]) }),
|
|
1792
|
+
/* @__PURE__ */ jsx38("span", { className: "font-normal text-[14px] leading-[1.4] text-text-primary whitespace-nowrap", children: label })
|
|
1766
1793
|
] }),
|
|
1767
|
-
hasAction && /* @__PURE__ */
|
|
1794
|
+
hasAction && /* @__PURE__ */ jsx38(
|
|
1768
1795
|
"button",
|
|
1769
1796
|
{
|
|
1770
1797
|
type: "button",
|
|
1771
1798
|
onClick: onAction,
|
|
1772
1799
|
className: cn(
|
|
1773
1800
|
"h-6 flex items-center justify-center gap-1 px-1 py-1 rounded-md shrink-0 transition-colors",
|
|
1774
|
-
|
|
1801
|
+
ACTION_BORDER_STYLES[type],
|
|
1775
1802
|
type === "neutral" ? "hover:border-border-strong" : "hover:opacity-80"
|
|
1776
1803
|
),
|
|
1777
|
-
children: /* @__PURE__ */
|
|
1804
|
+
children: /* @__PURE__ */ jsx38("span", { className: "font-medium text-[12px] leading-[12px] text-text-primary whitespace-nowrap", children: actionLabel })
|
|
1778
1805
|
}
|
|
1779
1806
|
)
|
|
1780
1807
|
]
|
|
@@ -1804,7 +1831,7 @@ function ToastProvider({ children }) {
|
|
|
1804
1831
|
return /* @__PURE__ */ jsxs25(ToastContext.Provider, { value, children: [
|
|
1805
1832
|
children,
|
|
1806
1833
|
toast && createPortal6(
|
|
1807
|
-
/* @__PURE__ */
|
|
1834
|
+
/* @__PURE__ */ jsx38("div", { className: "fixed bottom-4 left-4 z-[100] pointer-events-none", children: /* @__PURE__ */ jsx38(
|
|
1808
1835
|
Toast,
|
|
1809
1836
|
{
|
|
1810
1837
|
className: "pointer-events-auto",
|