@bizapps/design-system-testing 1.11.0 → 1.12.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/dist/main.cjs +1386 -54
- package/dist/main.cjs.map +1 -1
- package/dist/main.d.cts +150 -3
- package/dist/main.d.ts +150 -3
- package/dist/main.js +1387 -57
- package/dist/main.js.map +1 -1
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -28,6 +28,7 @@ var reactHookForm = require('react-hook-form');
|
|
|
28
28
|
var zod = require('@hookform/resolvers/zod');
|
|
29
29
|
var confetti = require('canvas-confetti');
|
|
30
30
|
var reactTable = require('@tanstack/react-table');
|
|
31
|
+
var reactDom = require('react-dom');
|
|
31
32
|
var SignaturePadLib = require('signature_pad');
|
|
32
33
|
|
|
33
34
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -5430,10 +5431,11 @@ function SheetContent({
|
|
|
5430
5431
|
children,
|
|
5431
5432
|
side = "right",
|
|
5432
5433
|
showCloseButton = true,
|
|
5434
|
+
overlayClassName,
|
|
5433
5435
|
...props
|
|
5434
5436
|
}) {
|
|
5435
5437
|
return /* @__PURE__ */ jsxRuntime.jsxs(SheetPortal, { children: [
|
|
5436
|
-
/* @__PURE__ */ jsxRuntime.jsx(SheetOverlay, {}),
|
|
5438
|
+
/* @__PURE__ */ jsxRuntime.jsx(SheetOverlay, { className: overlayClassName }),
|
|
5437
5439
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
5438
5440
|
radixUi.Dialog.Content,
|
|
5439
5441
|
{
|
|
@@ -9207,6 +9209,7 @@ var DEFAULT_LABELS = {
|
|
|
9207
9209
|
collapse: "Collapse menu",
|
|
9208
9210
|
expand: "Expand menu",
|
|
9209
9211
|
openMenu: "Open menu",
|
|
9212
|
+
closeMenu: "Close menu",
|
|
9210
9213
|
currentPageSuffix: " (contains the current page)",
|
|
9211
9214
|
searchPlaceholder: () => "Filter links\u2026",
|
|
9212
9215
|
searchLabel: (moduleLabel) => `Filter links of ${moduleLabel}`,
|
|
@@ -9221,6 +9224,8 @@ var DEFAULT_LABELS = {
|
|
|
9221
9224
|
var EASE = "cubic-bezier(.2,.8,.2,1)";
|
|
9222
9225
|
var MOTION_MS = 240;
|
|
9223
9226
|
var FADE_MS = MOTION_MS / 2;
|
|
9227
|
+
var MORPH_MS = 360;
|
|
9228
|
+
var MORPH_EASE = "cubic-bezier(.65,0,.35,1)";
|
|
9224
9229
|
var BOUNCE_KEYFRAMES = [
|
|
9225
9230
|
{ transform: "translateY(0) scale(1)" },
|
|
9226
9231
|
{ transform: "translateY(-3px) scale(1.06)", offset: 0.35 },
|
|
@@ -9229,8 +9234,132 @@ var BOUNCE_KEYFRAMES = [
|
|
|
9229
9234
|
];
|
|
9230
9235
|
var BOUNCE_MS = 420;
|
|
9231
9236
|
var SUBTLE_SCROLLBAR = "[scrollbar-color:var(--floating-sidebar-scrollbar-thumb)_var(--floating-sidebar-scrollbar-track)]! [&::-webkit-scrollbar]:w-2.5! [&::-webkit-scrollbar-track]:bg-floating-sidebar-scrollbar-track! [&::-webkit-scrollbar-thumb]:rounded-full! [&::-webkit-scrollbar-thumb]:border-2! [&::-webkit-scrollbar-thumb]:border-solid! [&::-webkit-scrollbar-thumb]:border-floating-sidebar-scrollbar-track! [&::-webkit-scrollbar-thumb]:bg-floating-sidebar-scrollbar-thumb! [&::-webkit-scrollbar-thumb:hover]:bg-floating-sidebar-scrollbar-thumb-hover!";
|
|
9232
|
-
var
|
|
9237
|
+
var MORPH_SETTLE_MS = 120;
|
|
9238
|
+
function morphBox(element) {
|
|
9239
|
+
const rect = element.getBoundingClientRect();
|
|
9240
|
+
const computed = getComputedStyle(element);
|
|
9241
|
+
const drawer = element.closest('[data-slot="sheet-content"]');
|
|
9242
|
+
const drawerRect = drawer?.getBoundingClientRect();
|
|
9243
|
+
const offsetX = drawer && drawerRect ? drawerRect.left - drawer.offsetLeft : 0;
|
|
9244
|
+
const offsetY = drawer && drawerRect ? drawerRect.top - drawer.offsetTop : 0;
|
|
9245
|
+
const borderWidth = parseFloat(computed.borderTopWidth) || 0;
|
|
9246
|
+
return {
|
|
9247
|
+
left: rect.left - offsetX,
|
|
9248
|
+
top: rect.top - offsetY,
|
|
9249
|
+
width: rect.width,
|
|
9250
|
+
height: rect.height,
|
|
9251
|
+
// `rounded-full` resolves to an enormous radius that would not interpolate visibly;
|
|
9252
|
+
// half the height draws the same pill.
|
|
9253
|
+
borderRadius: `${Math.min(parseFloat(computed.borderTopLeftRadius) || 0, rect.height / 2)}px`,
|
|
9254
|
+
borderWidth: `${borderWidth}px`,
|
|
9255
|
+
borderColor: borderWidth > 0 ? computed.borderTopColor : "transparent",
|
|
9256
|
+
backgroundColor: computed.backgroundColor,
|
|
9257
|
+
boxShadow: computed.boxShadow
|
|
9258
|
+
};
|
|
9259
|
+
}
|
|
9260
|
+
var morphStyle = (b) => ({
|
|
9261
|
+
left: `${b.left}px`,
|
|
9262
|
+
top: `${b.top}px`,
|
|
9263
|
+
width: `${b.width}px`,
|
|
9264
|
+
height: `${b.height}px`,
|
|
9265
|
+
borderRadius: b.borderRadius,
|
|
9266
|
+
borderWidth: b.borderWidth,
|
|
9267
|
+
borderColor: b.borderColor,
|
|
9268
|
+
backgroundColor: b.backgroundColor,
|
|
9269
|
+
boxShadow: b.boxShadow
|
|
9270
|
+
});
|
|
9271
|
+
var sameBox = (a, b) => Math.abs(a.left - b.left) < 0.5 && Math.abs(a.top - b.top) < 0.5 && Math.abs(a.width - b.width) < 0.5 && Math.abs(a.height - b.height) < 0.5;
|
|
9272
|
+
function MobileMorph({ morph, side, ghostRef, getTarget, onDone }) {
|
|
9273
|
+
const chevronsRef = react.useRef(null);
|
|
9274
|
+
const menuRef = react.useRef(null);
|
|
9275
|
+
const onDoneRef = react.useRef(onDone);
|
|
9276
|
+
react.useLayoutEffect(() => {
|
|
9277
|
+
onDoneRef.current = onDone;
|
|
9278
|
+
});
|
|
9279
|
+
react.useLayoutEffect(() => {
|
|
9280
|
+
const ghost = ghostRef.current;
|
|
9281
|
+
if (!ghost) return;
|
|
9282
|
+
let frame = 0;
|
|
9283
|
+
let tries = 0;
|
|
9284
|
+
const animations = [];
|
|
9285
|
+
const options = {
|
|
9286
|
+
duration: MORPH_MS,
|
|
9287
|
+
easing: MORPH_EASE,
|
|
9288
|
+
fill: "forwards"
|
|
9289
|
+
};
|
|
9290
|
+
const start = () => {
|
|
9291
|
+
const target = getTarget();
|
|
9292
|
+
if (!target) {
|
|
9293
|
+
if (tries++ < 10) frame = requestAnimationFrame(start);
|
|
9294
|
+
else onDoneRef.current();
|
|
9295
|
+
return;
|
|
9296
|
+
}
|
|
9297
|
+
const to = morphBox(target);
|
|
9298
|
+
const chevrons = morph.to === "open" ? 1 : 0;
|
|
9299
|
+
animations.push(
|
|
9300
|
+
ghost.animate([morphStyle(morph.from), morphStyle(to)], options),
|
|
9301
|
+
chevronsRef.current.animate(
|
|
9302
|
+
[{ opacity: morph.chevrons }, { opacity: chevrons }],
|
|
9303
|
+
options
|
|
9304
|
+
),
|
|
9305
|
+
menuRef.current.animate(
|
|
9306
|
+
[{ opacity: 1 - morph.chevrons }, { opacity: 1 - chevrons }],
|
|
9307
|
+
options
|
|
9308
|
+
)
|
|
9309
|
+
);
|
|
9310
|
+
animations[0].onfinish = () => {
|
|
9311
|
+
const settled = getTarget();
|
|
9312
|
+
const end = settled && morphBox(settled);
|
|
9313
|
+
if (!end || sameBox(end, to)) return onDoneRef.current();
|
|
9314
|
+
const settle = ghost.animate([morphStyle(to), morphStyle(end)], {
|
|
9315
|
+
...options,
|
|
9316
|
+
duration: MORPH_SETTLE_MS
|
|
9317
|
+
});
|
|
9318
|
+
animations.push(settle);
|
|
9319
|
+
settle.onfinish = () => onDoneRef.current();
|
|
9320
|
+
};
|
|
9321
|
+
};
|
|
9322
|
+
start();
|
|
9323
|
+
return () => {
|
|
9324
|
+
cancelAnimationFrame(frame);
|
|
9325
|
+
animations.forEach((animation2) => animation2.cancel());
|
|
9326
|
+
};
|
|
9327
|
+
}, [morph, getTarget, ghostRef]);
|
|
9328
|
+
return reactDom.createPortal(
|
|
9329
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9330
|
+
"div",
|
|
9331
|
+
{
|
|
9332
|
+
ref: ghostRef,
|
|
9333
|
+
"aria-hidden": "true",
|
|
9334
|
+
"data-slot": "floating-sidebar-morph",
|
|
9335
|
+
"data-state": morph.to,
|
|
9336
|
+
className: "text-primary pointer-events-none fixed z-[60] flex items-center justify-center overflow-hidden border-solid",
|
|
9337
|
+
style: morphStyle(morph.from),
|
|
9338
|
+
children: [
|
|
9339
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9340
|
+
"span",
|
|
9341
|
+
{
|
|
9342
|
+
ref: chevronsRef,
|
|
9343
|
+
"data-slot": "floating-sidebar-morph-chevrons",
|
|
9344
|
+
className: "absolute flex",
|
|
9345
|
+
style: {
|
|
9346
|
+
opacity: morph.chevrons,
|
|
9347
|
+
// Same direction as the close button's chevrons in the drawer.
|
|
9348
|
+
transform: side === "right" ? "rotate(180deg)" : void 0
|
|
9349
|
+
},
|
|
9350
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronsLeft, { className: "size-5", strokeWidth: 1.5 })
|
|
9351
|
+
}
|
|
9352
|
+
),
|
|
9353
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { ref: menuRef, className: "absolute flex", style: { opacity: 1 - morph.chevrons }, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { className: "size-5", strokeWidth: 1.5 }) })
|
|
9354
|
+
]
|
|
9355
|
+
}
|
|
9356
|
+
),
|
|
9357
|
+
document.body
|
|
9358
|
+
);
|
|
9359
|
+
}
|
|
9360
|
+
var DEFAULT_WIDTH = 305;
|
|
9233
9361
|
var DEFAULT_COLLAPSED_WIDTH = 48;
|
|
9362
|
+
var TILE_ICON_SIZE = 22;
|
|
9234
9363
|
var MIN_COLLAPSED_WIDTH = 40;
|
|
9235
9364
|
var t = (prop, ms = 300, delay = 0) => `${prop} ${ms}ms ${EASE} ${delay}ms`;
|
|
9236
9365
|
function transition2(reduced, ...parts) {
|
|
@@ -9262,31 +9391,29 @@ function isEditableTarget(target) {
|
|
|
9262
9391
|
if (target.closest('[data-slot="floating-sidebar-search"]')) return false;
|
|
9263
9392
|
return target.closest('[contenteditable]:not([contenteditable="false"])') !== null || target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.tagName === "SELECT";
|
|
9264
9393
|
}
|
|
9394
|
+
var ICON_SIZES = {
|
|
9395
|
+
sm: "[&>svg]:size-[18px]",
|
|
9396
|
+
md: "[&>svg]:size-5",
|
|
9397
|
+
lg: "[&>svg]:size-[22px]"
|
|
9398
|
+
};
|
|
9265
9399
|
function SidebarIcon({
|
|
9266
9400
|
icon,
|
|
9267
9401
|
resolveIcon,
|
|
9268
|
-
|
|
9402
|
+
size = "md"
|
|
9269
9403
|
}) {
|
|
9270
9404
|
const resolved = typeof icon === "string" ? resolveIcon?.(icon) : icon;
|
|
9405
|
+
const sizeClass2 = cn(
|
|
9406
|
+
ICON_SIZES[size],
|
|
9407
|
+
"[&>svg]:transition-[width,height] [&>svg]:duration-240 [&>svg]:ease-[cubic-bezier(.2,.8,.2,1)] motion-reduce:[&>svg]:transition-none"
|
|
9408
|
+
);
|
|
9271
9409
|
if (resolved === void 0 || resolved === null) {
|
|
9272
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-slot": "floating-sidebar-fallback-icon", className: "flex", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9273
|
-
lucideReact.CircleDashed,
|
|
9274
|
-
{
|
|
9275
|
-
"aria-hidden": "true",
|
|
9276
|
-
className: small ? "size-[18px]" : "size-5",
|
|
9277
|
-
strokeWidth: 1.5
|
|
9278
|
-
}
|
|
9279
|
-
) });
|
|
9410
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { "data-slot": "floating-sidebar-fallback-icon", className: cn("flex", sizeClass2), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleDashed, { "aria-hidden": "true", strokeWidth: 1.5 }) });
|
|
9280
9411
|
}
|
|
9281
9412
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
9282
9413
|
"span",
|
|
9283
9414
|
{
|
|
9284
9415
|
"data-slot": "floating-sidebar-icon",
|
|
9285
|
-
className: cn(
|
|
9286
|
-
"flex",
|
|
9287
|
-
"[&>svg]:stroke-[1.5]",
|
|
9288
|
-
small ? "[&>svg]:size-[18px]" : "[&>svg]:size-5"
|
|
9289
|
-
),
|
|
9416
|
+
className: cn("flex [&>svg]:stroke-[1.5]", sizeClass2),
|
|
9290
9417
|
children: resolved
|
|
9291
9418
|
}
|
|
9292
9419
|
);
|
|
@@ -9352,6 +9479,51 @@ function FloatingSidebar({
|
|
|
9352
9479
|
defaultMobileOpen,
|
|
9353
9480
|
onMobileOpenChange
|
|
9354
9481
|
);
|
|
9482
|
+
const morphEnabled = isMobile && mobileOpenProp === void 0 && !reduced;
|
|
9483
|
+
const triggerRef = react.useRef(null);
|
|
9484
|
+
const toggleRef = react.useRef(null);
|
|
9485
|
+
const morphGhostRef = react.useRef(null);
|
|
9486
|
+
const deferredFocus = react.useRef(null);
|
|
9487
|
+
const [morph, setMorph] = react.useState(null);
|
|
9488
|
+
if (morph && !morphEnabled) setMorph(null);
|
|
9489
|
+
const prevMobileOpen = react.useRef(mobileOpen);
|
|
9490
|
+
react.useLayoutEffect(() => {
|
|
9491
|
+
if (prevMobileOpen.current === mobileOpen) return;
|
|
9492
|
+
prevMobileOpen.current = mobileOpen;
|
|
9493
|
+
const ghost = morphGhostRef.current;
|
|
9494
|
+
const source = ghost ?? (mobileOpen ? triggerRef.current : toggleRef.current);
|
|
9495
|
+
deferredFocus.current = null;
|
|
9496
|
+
if (!morphEnabled || !source || typeof source.animate !== "function") return;
|
|
9497
|
+
deferredFocus.current = mobileOpen ? "toggle" : "trigger";
|
|
9498
|
+
const chevrons = ghost?.querySelector(
|
|
9499
|
+
'[data-slot="floating-sidebar-morph-chevrons"]'
|
|
9500
|
+
);
|
|
9501
|
+
setMorph((current) => ({
|
|
9502
|
+
to: mobileOpen ? "open" : "closed",
|
|
9503
|
+
from: morphBox(source),
|
|
9504
|
+
chevrons: chevrons ? parseFloat(getComputedStyle(chevrons).opacity) : mobileOpen ? 0 : 1,
|
|
9505
|
+
key: (current?.key ?? 0) + 1
|
|
9506
|
+
}));
|
|
9507
|
+
}, [mobileOpen, morphEnabled]);
|
|
9508
|
+
const getMorphTarget = react.useCallback(
|
|
9509
|
+
() => morph?.to === "open" ? toggleRef.current : triggerRef.current,
|
|
9510
|
+
[morph?.to]
|
|
9511
|
+
);
|
|
9512
|
+
const endMorph = react.useCallback(() => setMorph(null), []);
|
|
9513
|
+
react.useLayoutEffect(() => {
|
|
9514
|
+
if (morph) return;
|
|
9515
|
+
const pending = deferredFocus.current;
|
|
9516
|
+
deferredFocus.current = null;
|
|
9517
|
+
const active = document.activeElement;
|
|
9518
|
+
if (pending === "toggle") {
|
|
9519
|
+
const toggle2 = toggleRef.current;
|
|
9520
|
+
if (toggle2 && active === toggle2.closest('[data-slot="sheet-content"]')) toggle2.focus();
|
|
9521
|
+
} else if (pending === "trigger" && (!active || active === document.body)) {
|
|
9522
|
+
triggerRef.current?.focus();
|
|
9523
|
+
}
|
|
9524
|
+
}, [morph]);
|
|
9525
|
+
const morphing = morphEnabled && morph !== null;
|
|
9526
|
+
const finePointer = useMediaQuery("(hover: hover) and (pointer: fine)");
|
|
9355
9527
|
const [queries, setQueries] = react.useState({});
|
|
9356
9528
|
const [flyoutId, setFlyoutId] = react.useState(null);
|
|
9357
9529
|
const [hoverId, setHoverId] = react.useState(null);
|
|
@@ -9409,7 +9581,7 @@ function FloatingSidebar({
|
|
|
9409
9581
|
renderLink,
|
|
9410
9582
|
onToggleFavorite: toggleFavorite
|
|
9411
9583
|
};
|
|
9412
|
-
const toggleLabel = collapsed ? labels.expand : labels.collapse;
|
|
9584
|
+
const toggleLabel = isMobile ? labels.closeMenu : collapsed ? labels.expand : labels.collapse;
|
|
9413
9585
|
const ability = useOptionalAbility();
|
|
9414
9586
|
const usesPermissions = modules.some(
|
|
9415
9587
|
(module) => module.permission || module.items.some((item) => item.permission)
|
|
@@ -9496,20 +9668,25 @@ function FloatingSidebar({
|
|
|
9496
9668
|
children: labels.title
|
|
9497
9669
|
}
|
|
9498
9670
|
),
|
|
9499
|
-
|
|
9671
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
9500
9672
|
"button",
|
|
9501
9673
|
{
|
|
9674
|
+
ref: toggleRef,
|
|
9502
9675
|
type: "button",
|
|
9503
9676
|
"data-slot": "floating-sidebar-toggle",
|
|
9504
9677
|
"aria-label": toggleLabel,
|
|
9505
|
-
"aria-expanded": !collapsed,
|
|
9506
|
-
title: shortcut ? `${toggleLabel} (Ctrl/\u2318 + B)` : toggleLabel,
|
|
9507
|
-
onClick: toggle,
|
|
9678
|
+
"aria-expanded": isMobile ? void 0 : !collapsed,
|
|
9679
|
+
title: shortcut && (!isMobile || finePointer) ? `${toggleLabel} (Ctrl/\u2318 + B)` : toggleLabel,
|
|
9680
|
+
onClick: isMobile ? () => setMobileOpen(false) : toggle,
|
|
9508
9681
|
className: cn(
|
|
9509
9682
|
"text-primary focus-visible:ring-primary bg-sidebar border-floating-sidebar-card-border hover:bg-floating-sidebar-toggle-hover flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-full border shadow-[0_2px_6px_color-mix(in_srgb,var(--color-primary)_6%,transparent)] outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
9510
9683
|
side === "right" ? "mr-auto" : "ml-auto"
|
|
9511
9684
|
),
|
|
9512
9685
|
style: {
|
|
9686
|
+
// Hidden, and out of reach of a stray tap, while the mobile morph stands in
|
|
9687
|
+
// for it.
|
|
9688
|
+
opacity: morphing ? 0 : void 0,
|
|
9689
|
+
pointerEvents: morphing ? "none" : void 0,
|
|
9513
9690
|
// The auto margin keeps the toggle on the edge while the width animates;
|
|
9514
9691
|
// only the outer margin changes, to center it on the collapsed rail.
|
|
9515
9692
|
// (`auto` cannot be interpolated, so animating it made the toggle jump.)
|
|
@@ -9595,36 +9772,65 @@ function FloatingSidebar({
|
|
|
9595
9772
|
}
|
|
9596
9773
|
);
|
|
9597
9774
|
if (isMobile) {
|
|
9598
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
|
|
9606
|
-
|
|
9607
|
-
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9775
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(TooltipProvider, { delayDuration: 300, children: [
|
|
9776
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open: mobileOpen, onOpenChange: setMobileOpen, children: [
|
|
9777
|
+
mobileOpenProp === void 0 && /* @__PURE__ */ jsxRuntime.jsx(SheetTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
9778
|
+
"button",
|
|
9779
|
+
{
|
|
9780
|
+
ref: triggerRef,
|
|
9781
|
+
type: "button",
|
|
9782
|
+
"data-slot": "floating-sidebar-mobile-trigger",
|
|
9783
|
+
"aria-label": labels.openMenu,
|
|
9784
|
+
style: {
|
|
9785
|
+
opacity: morphing ? 0 : void 0,
|
|
9786
|
+
pointerEvents: morphing ? "none" : void 0
|
|
9787
|
+
},
|
|
9788
|
+
className: "text-primary focus-visible:ring-primary bg-sidebar hover:bg-sidebar-accent flex size-10 cursor-pointer items-center justify-center rounded-[10px] shadow-[0_8px_24px_color-mix(in_srgb,var(--color-primary)_8%,transparent)] outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
9789
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Menu, { "aria-hidden": "true", className: "size-5", strokeWidth: 1.5 })
|
|
9790
|
+
}
|
|
9791
|
+
) }),
|
|
9792
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
9793
|
+
SheetContent,
|
|
9794
|
+
{
|
|
9795
|
+
side,
|
|
9796
|
+
"aria-describedby": void 0,
|
|
9797
|
+
showCloseButton: false,
|
|
9798
|
+
overlayClassName: "bg-primary/20",
|
|
9799
|
+
className: "bg-transparent p-3 pt-2 shadow-none data-[side=left]:border-r-0 data-[side=right]:border-l-0",
|
|
9800
|
+
style: { width: width + 24, maxWidth: "100%" },
|
|
9801
|
+
onOpenAutoFocus: (event) => {
|
|
9802
|
+
if (deferredFocus.current !== "toggle") return;
|
|
9803
|
+
event.preventDefault();
|
|
9804
|
+
event.currentTarget?.focus();
|
|
9805
|
+
},
|
|
9806
|
+
onCloseAutoFocus: (event) => {
|
|
9807
|
+
if (deferredFocus.current === "trigger") event.preventDefault();
|
|
9808
|
+
},
|
|
9809
|
+
onEscapeKeyDown: (event) => {
|
|
9810
|
+
const active = document.activeElement;
|
|
9811
|
+
if (active instanceof HTMLInputElement && active.value && active.closest('[data-slot="floating-sidebar-search"]')) {
|
|
9812
|
+
event.preventDefault();
|
|
9813
|
+
}
|
|
9814
|
+
},
|
|
9815
|
+
children: [
|
|
9816
|
+
/* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: labels.title }),
|
|
9817
|
+
nav
|
|
9818
|
+
]
|
|
9819
|
+
}
|
|
9820
|
+
)
|
|
9821
|
+
] }),
|
|
9822
|
+
morphing && /* @__PURE__ */ jsxRuntime.jsx(
|
|
9823
|
+
MobileMorph,
|
|
9611
9824
|
{
|
|
9825
|
+
morph,
|
|
9612
9826
|
side,
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
9617
|
-
|
|
9618
|
-
event.preventDefault();
|
|
9619
|
-
}
|
|
9620
|
-
},
|
|
9621
|
-
children: [
|
|
9622
|
-
/* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "sr-only", children: labels.title }),
|
|
9623
|
-
nav
|
|
9624
|
-
]
|
|
9625
|
-
}
|
|
9827
|
+
ghostRef: morphGhostRef,
|
|
9828
|
+
getTarget: getMorphTarget,
|
|
9829
|
+
onDone: endMorph
|
|
9830
|
+
},
|
|
9831
|
+
morph.key
|
|
9626
9832
|
)
|
|
9627
|
-
] })
|
|
9833
|
+
] });
|
|
9628
9834
|
}
|
|
9629
9835
|
return /* @__PURE__ */ jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: nav });
|
|
9630
9836
|
}
|
|
@@ -9758,7 +9964,8 @@ function ModuleCard({
|
|
|
9758
9964
|
const fillAfterCollapse = tileSelected && tileActive && settling && !reduced;
|
|
9759
9965
|
const fillTransition = fillAfterCollapse ? `0ms linear ${MOTION_MS}ms` : `${FADE_MS}ms linear 0ms`;
|
|
9760
9966
|
const iconFlipDelay = fillAfterCollapse ? MOTION_MS : FADE_MS / 2;
|
|
9761
|
-
const tilePadding = (tileSize - 2 -
|
|
9967
|
+
const tilePadding = (tileSize - 2 - TILE_ICON_SIZE) / 2;
|
|
9968
|
+
const iconHighlighted = collapsed ? tileSelected : open;
|
|
9762
9969
|
const cardRef = react.useRef(null);
|
|
9763
9970
|
const wasCollapsed = react.useRef(collapsed);
|
|
9764
9971
|
react.useEffect(() => {
|
|
@@ -9798,7 +10005,7 @@ function ModuleCard({
|
|
|
9798
10005
|
"border",
|
|
9799
10006
|
collapsed ? "rounded-[14px]" : "rounded-2xl",
|
|
9800
10007
|
tileSelected ? "border-primary bg-primary" : "bg-sidebar border-floating-sidebar-card-border",
|
|
9801
|
-
open ? "shadow-[
|
|
10008
|
+
open ? "shadow-[0_4px_14px_color-mix(in_srgb,var(--color-primary)_3%,transparent)]" : "shadow-[0_1px_4px_color-mix(in_srgb,var(--color-primary)_3%,transparent)]"
|
|
9802
10009
|
),
|
|
9803
10010
|
style: {
|
|
9804
10011
|
flex: open ? "0 1 auto" : "0 0 auto",
|
|
@@ -9866,8 +10073,24 @@ function ModuleCard({
|
|
|
9866
10073
|
"span",
|
|
9867
10074
|
{
|
|
9868
10075
|
"data-slot": "floating-sidebar-module-icon",
|
|
9869
|
-
className:
|
|
9870
|
-
|
|
10076
|
+
className: cn(
|
|
10077
|
+
"relative flex shrink-0 items-center justify-center",
|
|
10078
|
+
!iconHighlighted && "text-muted-foreground"
|
|
10079
|
+
),
|
|
10080
|
+
style: {
|
|
10081
|
+
transition: transition2(
|
|
10082
|
+
reduced,
|
|
10083
|
+
`color 0ms linear ${iconFlipDelay}ms`
|
|
10084
|
+
)
|
|
10085
|
+
},
|
|
10086
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10087
|
+
SidebarIcon,
|
|
10088
|
+
{
|
|
10089
|
+
icon: module.icon,
|
|
10090
|
+
resolveIcon,
|
|
10091
|
+
size: collapsed ? "lg" : "md"
|
|
10092
|
+
}
|
|
10093
|
+
)
|
|
9871
10094
|
}
|
|
9872
10095
|
),
|
|
9873
10096
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -10055,7 +10278,9 @@ function ModuleCard({
|
|
|
10055
10278
|
"data-slot": "floating-sidebar-flyout-list",
|
|
10056
10279
|
"data-scroll": "muted",
|
|
10057
10280
|
className: cn(
|
|
10058
|
-
|
|
10281
|
+
// Clip x: items nudge 2px right on hover, and a y-only scroller
|
|
10282
|
+
// would then scroll sideways.
|
|
10283
|
+
"max-h-[420px] min-h-0 overflow-x-hidden overflow-y-auto",
|
|
10059
10284
|
SUBTLE_SCROLLBAR
|
|
10060
10285
|
),
|
|
10061
10286
|
children: [
|
|
@@ -10120,7 +10345,7 @@ function ItemRow({ item, list, visible, staggerIndex, onSelect }) {
|
|
|
10120
10345
|
"span",
|
|
10121
10346
|
{
|
|
10122
10347
|
className: cn("flex shrink-0", active ? "text-primary" : "text-muted-foreground"),
|
|
10123
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(SidebarIcon, { icon: item.icon, resolveIcon,
|
|
10348
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(SidebarIcon, { icon: item.icon, resolveIcon, size: "sm" })
|
|
10124
10349
|
}
|
|
10125
10350
|
),
|
|
10126
10351
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 [overflow-wrap:anywhere]", children: item.label })
|
|
@@ -10229,6 +10454,1111 @@ function ItemRow({ item, list, visible, staggerIndex, onSelect }) {
|
|
|
10229
10454
|
}
|
|
10230
10455
|
);
|
|
10231
10456
|
}
|
|
10457
|
+
var AppHubContext = react.createContext(null);
|
|
10458
|
+
function useAppHubContext() {
|
|
10459
|
+
const context = react.use(AppHubContext);
|
|
10460
|
+
if (!context) throw new Error("AppHub parts must be rendered inside <AppHub>.");
|
|
10461
|
+
return context;
|
|
10462
|
+
}
|
|
10463
|
+
|
|
10464
|
+
// src/components/compounds/AppHub/app-hub.constants.ts
|
|
10465
|
+
var DEFAULT_APP_HUB_ID = "app-hub";
|
|
10466
|
+
var DEFAULT_STORAGE_KEY = "tcce-app-hub:open";
|
|
10467
|
+
var OPEN_CHANGE_EVENT = "tcce-app-hub:open-change";
|
|
10468
|
+
var ITEM_SELECTOR = "[data-app-hub-item]";
|
|
10469
|
+
var ENTRY_SELECTOR = "[data-app-hub-entry]";
|
|
10470
|
+
var FOCUS_RING = "outline-hidden focus-visible:outline-2 focus-visible:outline-solid focus-visible:outline-offset-3 focus-visible:outline-main-blue-primary";
|
|
10471
|
+
var TOOLTIP_CLASS = "rounded-lg px-2.75 py-1.75 text-[11px] leading-none font-semibold shadow-black-button motion-reduce:animate-none";
|
|
10472
|
+
var DEFAULT_APP_HUB_LABELS = {
|
|
10473
|
+
navigation: "Applications",
|
|
10474
|
+
allApps: "All applications",
|
|
10475
|
+
sheetTitle: "Applications",
|
|
10476
|
+
hideDock: "Hide dock",
|
|
10477
|
+
showDock: "show applications dock",
|
|
10478
|
+
tab: "Apps",
|
|
10479
|
+
fab: "Apps",
|
|
10480
|
+
pending: (count) => `${count} pending`,
|
|
10481
|
+
leaves: (appName) => `leaves ${appName}`,
|
|
10482
|
+
current: "Current",
|
|
10483
|
+
noAccess: "No access \xB7 ask your manager",
|
|
10484
|
+
searchLabel: "Search applications",
|
|
10485
|
+
searchPlaceholder: "Search apps",
|
|
10486
|
+
clearSearch: "Clear search",
|
|
10487
|
+
resultCount: (count) => count === 1 ? "1 application found" : `${count} applications found`,
|
|
10488
|
+
loading: "Loading applications",
|
|
10489
|
+
empty: "No applications found",
|
|
10490
|
+
noMatch: (query) => `No apps match \u201C${query}\u201D`,
|
|
10491
|
+
noMatchDescription: "Check the spelling or clear the search.",
|
|
10492
|
+
error: "Couldn\u2019t load applications",
|
|
10493
|
+
errorDescription: "The apps in the dock still work.",
|
|
10494
|
+
retry: "Try again",
|
|
10495
|
+
directory: "View all applications",
|
|
10496
|
+
close: "Close",
|
|
10497
|
+
dockHidden: "Applications dock hidden. Use the Apps tab on the right edge to show it again.",
|
|
10498
|
+
dockShown: "Applications dock shown"
|
|
10499
|
+
};
|
|
10500
|
+
|
|
10501
|
+
// src/components/compounds/AppHub/app-hub.utils.ts
|
|
10502
|
+
function mergeLabels(defaults, overrides = {}) {
|
|
10503
|
+
const defined = Object.entries(overrides).filter(([, value]) => value !== void 0);
|
|
10504
|
+
return { ...defaults, ...Object.fromEntries(defined) };
|
|
10505
|
+
}
|
|
10506
|
+
function areLabelsEqual(a, b) {
|
|
10507
|
+
const keys = Object.keys(a);
|
|
10508
|
+
return keys.every((key) => Object.is(a[key], b[key]));
|
|
10509
|
+
}
|
|
10510
|
+
function normalizePending(pending) {
|
|
10511
|
+
return typeof pending === "number" && Number.isFinite(pending) && pending >= 1 ? Math.floor(pending) : 0;
|
|
10512
|
+
}
|
|
10513
|
+
function formatPendingCount(count) {
|
|
10514
|
+
return count > 9 ? "9+" : String(count);
|
|
10515
|
+
}
|
|
10516
|
+
function sumPending(apps) {
|
|
10517
|
+
return apps.reduce((total, app) => total + (app.locked ? 0 : normalizePending(app.pending)), 0);
|
|
10518
|
+
}
|
|
10519
|
+
function getAppAccessibleName(app, labels, appName) {
|
|
10520
|
+
const pending = normalizePending(app.pending);
|
|
10521
|
+
return [
|
|
10522
|
+
app.label,
|
|
10523
|
+
pending > 0 && labels.pending(pending),
|
|
10524
|
+
app.external && labels.leaves(appName)
|
|
10525
|
+
].filter(Boolean).join(", ");
|
|
10526
|
+
}
|
|
10527
|
+
function getEntryElement(container) {
|
|
10528
|
+
return container?.querySelector(ENTRY_SELECTOR) ?? container?.querySelector(ITEM_SELECTOR) ?? null;
|
|
10529
|
+
}
|
|
10530
|
+
function groupApps(apps) {
|
|
10531
|
+
const sections = /* @__PURE__ */ new Map([[void 0, []]]);
|
|
10532
|
+
for (const app of apps) {
|
|
10533
|
+
const key = app.group || void 0;
|
|
10534
|
+
sections.set(key, [...sections.get(key) ?? [], app]);
|
|
10535
|
+
}
|
|
10536
|
+
return [...sections].filter(([, items]) => items.length > 0).map(([heading, items]) => ({ heading, apps: items }));
|
|
10537
|
+
}
|
|
10538
|
+
function filterApps(apps, query) {
|
|
10539
|
+
const needle = query.trim().toLowerCase();
|
|
10540
|
+
if (!needle) return apps;
|
|
10541
|
+
return apps.filter(
|
|
10542
|
+
(app) => `${app.label} ${app.description ?? ""}`.toLowerCase().includes(needle)
|
|
10543
|
+
);
|
|
10544
|
+
}
|
|
10545
|
+
var appHubIconVariants = classVarianceAuthority.cva("relative flex shrink-0 items-center justify-center", {
|
|
10546
|
+
variants: {
|
|
10547
|
+
tone: {
|
|
10548
|
+
green: "bg-green-100 text-green-800",
|
|
10549
|
+
yellow: "bg-yellow-200 text-yellow-800",
|
|
10550
|
+
navy: "bg-main-blue-primary/10 text-main-blue-primary",
|
|
10551
|
+
orange: "bg-orange-100 text-orange-800",
|
|
10552
|
+
purple: "bg-purple-100 text-purple-600",
|
|
10553
|
+
grey: "bg-light-200 text-main-grey"
|
|
10554
|
+
},
|
|
10555
|
+
size: {
|
|
10556
|
+
tile: "size-12 rounded-2xl [&_svg]:size-5",
|
|
10557
|
+
row: "size-9 rounded-xl [&_svg]:size-4.5",
|
|
10558
|
+
sheet: "size-10 rounded-xl [&_svg]:size-5"
|
|
10559
|
+
},
|
|
10560
|
+
// Declared last so `cn()` keeps the current fill over the tone.
|
|
10561
|
+
current: { true: "bg-main-blue-primary text-main-white", false: "" }
|
|
10562
|
+
},
|
|
10563
|
+
defaultVariants: { tone: "grey", size: "tile", current: false }
|
|
10564
|
+
});
|
|
10565
|
+
function AppHubLink({
|
|
10566
|
+
app,
|
|
10567
|
+
afterNavigate,
|
|
10568
|
+
onClick,
|
|
10569
|
+
...props
|
|
10570
|
+
}) {
|
|
10571
|
+
const { renderLink, onNavigate } = useAppHubContext();
|
|
10572
|
+
const linkProps = {
|
|
10573
|
+
...props,
|
|
10574
|
+
href: app.href,
|
|
10575
|
+
onClick: (event) => {
|
|
10576
|
+
onClick?.(event);
|
|
10577
|
+
const modified = event.defaultPrevented || event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey;
|
|
10578
|
+
if (modified) return;
|
|
10579
|
+
onNavigate?.(app, event);
|
|
10580
|
+
afterNavigate?.();
|
|
10581
|
+
}
|
|
10582
|
+
};
|
|
10583
|
+
return renderLink ? renderLink(linkProps, app) : /* @__PURE__ */ jsxRuntime.jsx("a", { ...linkProps });
|
|
10584
|
+
}
|
|
10585
|
+
function AppHubCounter({ count, className }) {
|
|
10586
|
+
if (count <= 0) return null;
|
|
10587
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10588
|
+
"span",
|
|
10589
|
+
{
|
|
10590
|
+
"aria-hidden": "true",
|
|
10591
|
+
"data-slot": "app-hub-counter",
|
|
10592
|
+
className: cn(
|
|
10593
|
+
"bg-main-orange-primary text-background ring-background absolute -top-1 -right-1 flex h-4.5 min-w-4.5 items-center justify-center rounded-full px-1 text-[11px] font-bold ring-2",
|
|
10594
|
+
className
|
|
10595
|
+
),
|
|
10596
|
+
children: formatPendingCount(count)
|
|
10597
|
+
}
|
|
10598
|
+
);
|
|
10599
|
+
}
|
|
10600
|
+
function AppHubTile({ app, current = false }) {
|
|
10601
|
+
const { labels, appName } = useAppHubContext();
|
|
10602
|
+
const name = getAppAccessibleName(app, labels, appName);
|
|
10603
|
+
const tone = app.tone ?? "grey";
|
|
10604
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
10605
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, "aria-describedby": void 0, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10606
|
+
AppHubLink,
|
|
10607
|
+
{
|
|
10608
|
+
app,
|
|
10609
|
+
"aria-label": name,
|
|
10610
|
+
"aria-current": current ? "page" : void 0,
|
|
10611
|
+
"data-slot": "app-hub-tile",
|
|
10612
|
+
"data-variant": tone,
|
|
10613
|
+
"data-current": current ? "" : void 0,
|
|
10614
|
+
"data-app-hub-item": "",
|
|
10615
|
+
"data-app-hub-entry": current ? "" : void 0,
|
|
10616
|
+
className: cn(
|
|
10617
|
+
appHubIconVariants({ tone, size: "tile", current }),
|
|
10618
|
+
"hover:shadow-black-button transition-[translate,box-shadow] hover:-translate-y-0.5 active:translate-y-px active:shadow-none motion-reduce:transition-none",
|
|
10619
|
+
"data-current:before:bg-main-orange-primary data-current:before:absolute data-current:before:-left-2.5 data-current:before:h-5 data-current:before:w-0.75 data-current:before:rounded-full",
|
|
10620
|
+
FOCUS_RING
|
|
10621
|
+
),
|
|
10622
|
+
children: [
|
|
10623
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", className: "contents", children: app.icon }),
|
|
10624
|
+
/* @__PURE__ */ jsxRuntime.jsx(AppHubCounter, { count: normalizePending(app.pending) })
|
|
10625
|
+
]
|
|
10626
|
+
}
|
|
10627
|
+
) }),
|
|
10628
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10629
|
+
TooltipContent,
|
|
10630
|
+
{
|
|
10631
|
+
"aria-hidden": "true",
|
|
10632
|
+
side: "left",
|
|
10633
|
+
variant: "primary",
|
|
10634
|
+
size: "sm",
|
|
10635
|
+
className: TOOLTIP_CLASS,
|
|
10636
|
+
children: app.label
|
|
10637
|
+
}
|
|
10638
|
+
)
|
|
10639
|
+
] });
|
|
10640
|
+
}
|
|
10641
|
+
var NAV_KEYS = /* @__PURE__ */ new Set(["ArrowDown", "ArrowUp", "Home", "End"]);
|
|
10642
|
+
function useArrowNavigation(containerRef) {
|
|
10643
|
+
return react.useCallback(
|
|
10644
|
+
(event) => {
|
|
10645
|
+
const container = containerRef.current;
|
|
10646
|
+
const target = event.target;
|
|
10647
|
+
if (event.defaultPrevented || !container || !NAV_KEYS.has(event.key)) return;
|
|
10648
|
+
if (!(target instanceof Element) || !container.contains(target)) return;
|
|
10649
|
+
const current = target.closest(ITEM_SELECTOR);
|
|
10650
|
+
if (!current) return;
|
|
10651
|
+
const items = Array.from(container.querySelectorAll(ITEM_SELECTOR)).filter(
|
|
10652
|
+
(item) => !item.closest("[inert]")
|
|
10653
|
+
);
|
|
10654
|
+
const index = items.indexOf(current);
|
|
10655
|
+
if (index === -1) return;
|
|
10656
|
+
event.preventDefault();
|
|
10657
|
+
const last = items.length - 1;
|
|
10658
|
+
const next = event.key === "Home" ? 0 : event.key === "End" ? last : event.key === "ArrowDown" ? (index + 1) % items.length : (index - 1 + items.length) % items.length;
|
|
10659
|
+
items[next]?.focus();
|
|
10660
|
+
},
|
|
10661
|
+
[containerRef]
|
|
10662
|
+
);
|
|
10663
|
+
}
|
|
10664
|
+
var SKELETON_ROWS = [
|
|
10665
|
+
["w-[58%]", "w-[82%]"],
|
|
10666
|
+
["w-[44%]", "w-[70%]"],
|
|
10667
|
+
["w-[64%]", "w-[76%]"]
|
|
10668
|
+
];
|
|
10669
|
+
function AppHubRow({
|
|
10670
|
+
app,
|
|
10671
|
+
current,
|
|
10672
|
+
variant,
|
|
10673
|
+
onActivate
|
|
10674
|
+
}) {
|
|
10675
|
+
const { labels, appName } = useAppHubContext();
|
|
10676
|
+
const descId = react.useId();
|
|
10677
|
+
const locked = app.locked === true;
|
|
10678
|
+
const pending = normalizePending(app.pending);
|
|
10679
|
+
const className = cn(
|
|
10680
|
+
"hover:bg-light-200 flex w-full items-center gap-3 rounded-xl p-2 text-left",
|
|
10681
|
+
variant === "panel" ? "min-h-13" : "min-h-14",
|
|
10682
|
+
current && "bg-light-200",
|
|
10683
|
+
FOCUS_RING
|
|
10684
|
+
);
|
|
10685
|
+
const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10686
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10687
|
+
"span",
|
|
10688
|
+
{
|
|
10689
|
+
"aria-hidden": "true",
|
|
10690
|
+
className: appHubIconVariants({
|
|
10691
|
+
tone: locked ? "grey" : app.tone ?? "grey",
|
|
10692
|
+
size: variant === "panel" ? "row" : "sheet"
|
|
10693
|
+
}),
|
|
10694
|
+
children: app.icon
|
|
10695
|
+
}
|
|
10696
|
+
),
|
|
10697
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
10698
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10699
|
+
"span",
|
|
10700
|
+
{
|
|
10701
|
+
className: cn(
|
|
10702
|
+
"text-light-1000 flex items-center gap-1.5 font-medium",
|
|
10703
|
+
variant === "panel" ? "text-sm" : "text-[15px]"
|
|
10704
|
+
),
|
|
10705
|
+
children: [
|
|
10706
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate", children: app.label }),
|
|
10707
|
+
app.external && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10708
|
+
lucideReact.ArrowUpRight,
|
|
10709
|
+
{
|
|
10710
|
+
"aria-hidden": "true",
|
|
10711
|
+
className: "text-main-grey size-3.25 shrink-0"
|
|
10712
|
+
}
|
|
10713
|
+
)
|
|
10714
|
+
]
|
|
10715
|
+
}
|
|
10716
|
+
),
|
|
10717
|
+
locked ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-main-grey flex items-center gap-1 text-xs", children: [
|
|
10718
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { "aria-hidden": "true", className: "size-3" }),
|
|
10719
|
+
labels.noAccess
|
|
10720
|
+
] }) : app.description && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10721
|
+
"span",
|
|
10722
|
+
{
|
|
10723
|
+
id: descId,
|
|
10724
|
+
className: cn(
|
|
10725
|
+
"text-main-grey truncate",
|
|
10726
|
+
variant === "panel" ? "text-xs" : "text-[13px]"
|
|
10727
|
+
),
|
|
10728
|
+
children: app.description
|
|
10729
|
+
}
|
|
10730
|
+
)
|
|
10731
|
+
] }),
|
|
10732
|
+
current && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10733
|
+
"span",
|
|
10734
|
+
{
|
|
10735
|
+
"aria-hidden": "true",
|
|
10736
|
+
className: "bg-main-blue-primary text-main-white shrink-0 rounded-full px-2 py-0.5 text-[11px] leading-tight font-semibold",
|
|
10737
|
+
children: labels.current
|
|
10738
|
+
}
|
|
10739
|
+
),
|
|
10740
|
+
pending > 0 && !locked && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10741
|
+
"span",
|
|
10742
|
+
{
|
|
10743
|
+
"aria-hidden": "true",
|
|
10744
|
+
"data-slot": "app-hub-row-counter",
|
|
10745
|
+
className: cn(
|
|
10746
|
+
"bg-main-orange-primary text-background flex shrink-0 items-center justify-center rounded-full font-bold",
|
|
10747
|
+
variant === "panel" ? "h-5 min-w-5 px-1.5 text-[11px]" : "h-5.5 min-w-5.5 px-1.75 text-xs"
|
|
10748
|
+
),
|
|
10749
|
+
children: formatPendingCount(pending)
|
|
10750
|
+
}
|
|
10751
|
+
)
|
|
10752
|
+
] });
|
|
10753
|
+
if (locked) {
|
|
10754
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10755
|
+
"button",
|
|
10756
|
+
{
|
|
10757
|
+
type: "button",
|
|
10758
|
+
"aria-disabled": "true",
|
|
10759
|
+
"data-slot": "app-hub-row",
|
|
10760
|
+
"data-app-hub-item": "",
|
|
10761
|
+
className: cn(className, "text-main-grey cursor-not-allowed"),
|
|
10762
|
+
children: body
|
|
10763
|
+
}
|
|
10764
|
+
);
|
|
10765
|
+
}
|
|
10766
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
10767
|
+
AppHubLink,
|
|
10768
|
+
{
|
|
10769
|
+
app,
|
|
10770
|
+
afterNavigate: onActivate,
|
|
10771
|
+
"aria-label": getAppAccessibleName(app, labels, appName),
|
|
10772
|
+
"aria-current": current ? "page" : void 0,
|
|
10773
|
+
"aria-describedby": app.description ? descId : void 0,
|
|
10774
|
+
"data-slot": "app-hub-row",
|
|
10775
|
+
"data-app-hub-item": "",
|
|
10776
|
+
className,
|
|
10777
|
+
children: body
|
|
10778
|
+
}
|
|
10779
|
+
);
|
|
10780
|
+
}
|
|
10781
|
+
function AppHubCatalog({
|
|
10782
|
+
variant,
|
|
10783
|
+
apps,
|
|
10784
|
+
currentAppId,
|
|
10785
|
+
status,
|
|
10786
|
+
onRetry,
|
|
10787
|
+
directoryHref,
|
|
10788
|
+
searchThreshold,
|
|
10789
|
+
onActivate
|
|
10790
|
+
}) {
|
|
10791
|
+
const { labels, renderLink } = useAppHubContext();
|
|
10792
|
+
const rootRef = react.useRef(null);
|
|
10793
|
+
const onKeyDown = useArrowNavigation(rootRef);
|
|
10794
|
+
const searchId = react.useId();
|
|
10795
|
+
const searchRef = react.useRef(null);
|
|
10796
|
+
const [query, setQuery] = react.useState("");
|
|
10797
|
+
const directoryProps = {
|
|
10798
|
+
href: directoryHref ?? "",
|
|
10799
|
+
"data-slot": "app-hub-directory",
|
|
10800
|
+
"data-app-hub-item": "",
|
|
10801
|
+
onClick: () => onActivate?.(),
|
|
10802
|
+
className: cn(
|
|
10803
|
+
"text-main-blue-primary flex items-center gap-2 font-semibold",
|
|
10804
|
+
variant === "panel" ? "border-light-200 hover:bg-light-200 justify-between border-t px-4 py-3 text-[13px]" : "border-light-300 mx-4 mb-4 min-h-13 justify-center rounded-full border text-sm",
|
|
10805
|
+
FOCUS_RING
|
|
10806
|
+
),
|
|
10807
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10808
|
+
labels.directory,
|
|
10809
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { "aria-hidden": "true", className: "size-4 shrink-0" })
|
|
10810
|
+
] })
|
|
10811
|
+
};
|
|
10812
|
+
const ready = status === "ready";
|
|
10813
|
+
const searchVisible = variant === "panel" && ready && apps.length >= searchThreshold;
|
|
10814
|
+
if (!searchVisible && query) setQuery("");
|
|
10815
|
+
const activeQuery = searchVisible ? query : "";
|
|
10816
|
+
const filtered = filterApps(apps, activeQuery);
|
|
10817
|
+
const message = status === "loading" ? labels.loading : activeQuery && labels.resultCount(filtered.length);
|
|
10818
|
+
const [live, setLive] = react.useState("");
|
|
10819
|
+
react.useEffect(() => setLive(message), [message]);
|
|
10820
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10821
|
+
"div",
|
|
10822
|
+
{
|
|
10823
|
+
ref: rootRef,
|
|
10824
|
+
"data-slot": "app-hub-catalog",
|
|
10825
|
+
"data-variant": variant,
|
|
10826
|
+
tabIndex: -1,
|
|
10827
|
+
onKeyDown,
|
|
10828
|
+
className: "flex min-h-0 flex-1 flex-col outline-none",
|
|
10829
|
+
children: [
|
|
10830
|
+
searchVisible && /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-slot": "app-hub-search", className: "relative shrink-0 px-3 pt-3", children: [
|
|
10831
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: searchId, className: "sr-only", children: labels.searchLabel }),
|
|
10832
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10833
|
+
lucideReact.Search,
|
|
10834
|
+
{
|
|
10835
|
+
"aria-hidden": "true",
|
|
10836
|
+
className: "text-main-grey pointer-events-none absolute top-[calc(50%+6px)] left-6 size-4 -translate-y-1/2"
|
|
10837
|
+
}
|
|
10838
|
+
),
|
|
10839
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10840
|
+
Input,
|
|
10841
|
+
{
|
|
10842
|
+
ref: searchRef,
|
|
10843
|
+
id: searchId,
|
|
10844
|
+
type: "search",
|
|
10845
|
+
value: query,
|
|
10846
|
+
placeholder: labels.searchPlaceholder,
|
|
10847
|
+
onChange: (event) => setQuery(event.target.value),
|
|
10848
|
+
className: "border-main-grey/70 bg-background h-10 rounded-lg px-9 text-sm [&::-webkit-search-cancel-button]:appearance-none"
|
|
10849
|
+
}
|
|
10850
|
+
),
|
|
10851
|
+
query && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10852
|
+
"button",
|
|
10853
|
+
{
|
|
10854
|
+
type: "button",
|
|
10855
|
+
"aria-label": labels.clearSearch,
|
|
10856
|
+
onClick: () => {
|
|
10857
|
+
setQuery("");
|
|
10858
|
+
searchRef.current?.focus();
|
|
10859
|
+
},
|
|
10860
|
+
className: cn(
|
|
10861
|
+
"text-main-grey hover:bg-light-200 absolute top-[calc(50%+6px)] right-4 flex size-8 -translate-y-1/2 items-center justify-center rounded-lg [&_svg]:size-3.5",
|
|
10862
|
+
FOCUS_RING
|
|
10863
|
+
),
|
|
10864
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": "true" })
|
|
10865
|
+
}
|
|
10866
|
+
)
|
|
10867
|
+
] }),
|
|
10868
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
10869
|
+
"div",
|
|
10870
|
+
{
|
|
10871
|
+
"data-slot": "app-hub-catalog-scroll",
|
|
10872
|
+
className: cn(
|
|
10873
|
+
"flex min-h-0 flex-1 flex-col gap-2 overflow-y-auto p-2",
|
|
10874
|
+
variant === "panel" && "max-h-74"
|
|
10875
|
+
),
|
|
10876
|
+
children: [
|
|
10877
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "status", className: "sr-only", children: live }),
|
|
10878
|
+
status === "loading" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10879
|
+
"div",
|
|
10880
|
+
{
|
|
10881
|
+
"data-slot": "app-hub-loading",
|
|
10882
|
+
"aria-hidden": "true",
|
|
10883
|
+
className: "flex flex-col gap-1",
|
|
10884
|
+
children: SKELETON_ROWS.map(([first, second]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 p-2", children: [
|
|
10885
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "bg-light-200 size-9 shrink-0 rounded-xl" }),
|
|
10886
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-1 flex-col gap-1.5", children: [
|
|
10887
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10888
|
+
"span",
|
|
10889
|
+
{
|
|
10890
|
+
className: cn("bg-light-200 h-2.5 rounded-[5px]", first)
|
|
10891
|
+
}
|
|
10892
|
+
),
|
|
10893
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("bg-light-200 h-2 rounded-sm", second) })
|
|
10894
|
+
] })
|
|
10895
|
+
] }, first))
|
|
10896
|
+
}
|
|
10897
|
+
),
|
|
10898
|
+
status === "error" && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10899
|
+
"div",
|
|
10900
|
+
{
|
|
10901
|
+
role: "alert",
|
|
10902
|
+
"data-slot": "app-hub-error",
|
|
10903
|
+
className: "flex flex-col items-start gap-2.5 px-2 pt-3 pb-2",
|
|
10904
|
+
children: [
|
|
10905
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10906
|
+
"span",
|
|
10907
|
+
{
|
|
10908
|
+
"aria-hidden": "true",
|
|
10909
|
+
className: "flex size-9 items-center justify-center rounded-xl bg-red-100 text-red-800",
|
|
10910
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.CircleAlert, { className: "size-4.5" })
|
|
10911
|
+
}
|
|
10912
|
+
),
|
|
10913
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col gap-1", children: [
|
|
10914
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-light-1000 text-sm font-semibold", children: labels.error }),
|
|
10915
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-main-grey text-[13px] leading-snug", children: labels.errorDescription })
|
|
10916
|
+
] }),
|
|
10917
|
+
onRetry && /* @__PURE__ */ jsxRuntime.jsx(
|
|
10918
|
+
Button,
|
|
10919
|
+
{
|
|
10920
|
+
size: "sm",
|
|
10921
|
+
variant: "outline",
|
|
10922
|
+
"data-app-hub-item": "",
|
|
10923
|
+
onClick: () => {
|
|
10924
|
+
rootRef.current?.focus();
|
|
10925
|
+
onRetry();
|
|
10926
|
+
},
|
|
10927
|
+
children: labels.retry
|
|
10928
|
+
}
|
|
10929
|
+
)
|
|
10930
|
+
]
|
|
10931
|
+
}
|
|
10932
|
+
),
|
|
10933
|
+
ready && filtered.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
10934
|
+
"div",
|
|
10935
|
+
{
|
|
10936
|
+
"data-slot": "app-hub-empty",
|
|
10937
|
+
className: "flex flex-col items-start gap-1.5 px-2 pt-4 pb-2",
|
|
10938
|
+
children: [
|
|
10939
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-light-1000 text-sm font-semibold", children: activeQuery ? labels.noMatch(activeQuery) : labels.empty }),
|
|
10940
|
+
activeQuery && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10941
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-main-grey text-[13px] leading-snug", children: labels.noMatchDescription }),
|
|
10942
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
10943
|
+
"button",
|
|
10944
|
+
{
|
|
10945
|
+
type: "button",
|
|
10946
|
+
"data-app-hub-item": "",
|
|
10947
|
+
onClick: () => {
|
|
10948
|
+
setQuery("");
|
|
10949
|
+
searchRef.current?.focus();
|
|
10950
|
+
},
|
|
10951
|
+
className: cn(
|
|
10952
|
+
"text-main-blue-primary mt-1 rounded-sm py-1.5 text-[13px] font-semibold underline underline-offset-3",
|
|
10953
|
+
FOCUS_RING
|
|
10954
|
+
),
|
|
10955
|
+
children: labels.clearSearch
|
|
10956
|
+
}
|
|
10957
|
+
)
|
|
10958
|
+
] })
|
|
10959
|
+
]
|
|
10960
|
+
}
|
|
10961
|
+
),
|
|
10962
|
+
ready && groupApps(filtered).map((section) => /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "flex flex-col gap-1", children: [
|
|
10963
|
+
section.heading && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-main-grey px-2 text-[11px] font-semibold uppercase", children: section.heading }),
|
|
10964
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { role: "list", className: "flex flex-col gap-1", children: section.apps.map((app) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
10965
|
+
AppHubRow,
|
|
10966
|
+
{
|
|
10967
|
+
app,
|
|
10968
|
+
current: app.id === currentAppId,
|
|
10969
|
+
variant,
|
|
10970
|
+
onActivate
|
|
10971
|
+
}
|
|
10972
|
+
) }, app.id)) })
|
|
10973
|
+
] }, section.heading ?? ""))
|
|
10974
|
+
]
|
|
10975
|
+
}
|
|
10976
|
+
),
|
|
10977
|
+
directoryHref && /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: renderLink ? renderLink(directoryProps, void 0) : /* @__PURE__ */ jsxRuntime.jsx("a", { ...directoryProps }) })
|
|
10978
|
+
]
|
|
10979
|
+
}
|
|
10980
|
+
);
|
|
10981
|
+
}
|
|
10982
|
+
function AppHubPanel({
|
|
10983
|
+
id,
|
|
10984
|
+
open,
|
|
10985
|
+
onOpenChange,
|
|
10986
|
+
onCloseAutoFocus,
|
|
10987
|
+
...catalog
|
|
10988
|
+
}) {
|
|
10989
|
+
const { labels } = useAppHubContext();
|
|
10990
|
+
const titleId = react.useId();
|
|
10991
|
+
const contentRef = react.useRef(null);
|
|
10992
|
+
const [tooltipOpen, setTooltipOpen] = react.useState(false);
|
|
10993
|
+
if (open && tooltipOpen) setTooltipOpen(false);
|
|
10994
|
+
const quietRef = react.useRef(false);
|
|
10995
|
+
react.useEffect(() => {
|
|
10996
|
+
if (open) return () => void (quietRef.current = true);
|
|
10997
|
+
}, [open]);
|
|
10998
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Popover, { open, onOpenChange, children: [
|
|
10999
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11000
|
+
Tooltip,
|
|
11001
|
+
{
|
|
11002
|
+
open: tooltipOpen,
|
|
11003
|
+
onOpenChange: (next) => setTooltipOpen(next && !open && !quietRef.current),
|
|
11004
|
+
children: [
|
|
11005
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, "aria-describedby": void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11006
|
+
PopoverTrigger,
|
|
11007
|
+
{
|
|
11008
|
+
"aria-label": labels.allApps,
|
|
11009
|
+
"aria-controls": id,
|
|
11010
|
+
"data-slot": "app-hub-panel-trigger",
|
|
11011
|
+
onPointerEnter: () => void (quietRef.current = false),
|
|
11012
|
+
onBlur: () => void (quietRef.current = false),
|
|
11013
|
+
"data-app-hub-item": "",
|
|
11014
|
+
className: cn(
|
|
11015
|
+
appHubIconVariants({ tone: "grey", size: "tile" }),
|
|
11016
|
+
// Both triggers write `data-state` through `asChild` and the tooltip's value
|
|
11017
|
+
// wins, so the open tint keys off `aria-expanded` instead.
|
|
11018
|
+
"aria-expanded:bg-main-blue-primary/10 aria-expanded:text-main-blue-primary",
|
|
11019
|
+
FOCUS_RING
|
|
11020
|
+
),
|
|
11021
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { "aria-hidden": "true" })
|
|
11022
|
+
}
|
|
11023
|
+
) }),
|
|
11024
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11025
|
+
TooltipContent,
|
|
11026
|
+
{
|
|
11027
|
+
"aria-hidden": "true",
|
|
11028
|
+
side: "left",
|
|
11029
|
+
variant: "primary",
|
|
11030
|
+
size: "sm",
|
|
11031
|
+
className: TOOLTIP_CLASS,
|
|
11032
|
+
children: labels.allApps
|
|
11033
|
+
}
|
|
11034
|
+
)
|
|
11035
|
+
]
|
|
11036
|
+
}
|
|
11037
|
+
),
|
|
11038
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11039
|
+
PopoverContent,
|
|
11040
|
+
{
|
|
11041
|
+
ref: contentRef,
|
|
11042
|
+
id,
|
|
11043
|
+
side: "left",
|
|
11044
|
+
align: "center",
|
|
11045
|
+
sideOffset: 22,
|
|
11046
|
+
collisionPadding: 8,
|
|
11047
|
+
"aria-labelledby": titleId,
|
|
11048
|
+
"data-slot": "app-hub-panel",
|
|
11049
|
+
onCloseAutoFocus,
|
|
11050
|
+
onOpenAutoFocus: (event) => {
|
|
11051
|
+
event.preventDefault();
|
|
11052
|
+
const content = contentRef.current;
|
|
11053
|
+
(content?.querySelector('input[type="search"]') ?? content?.querySelector(ITEM_SELECTOR) ?? content)?.focus();
|
|
11054
|
+
},
|
|
11055
|
+
className: "border-light-300 shadow-black-card max-h-(--radix-popover-content-available-height) w-75 gap-0 rounded-2xl border p-0 motion-reduce:data-[state=closed]:animate-none motion-reduce:data-[state=open]:animate-none",
|
|
11056
|
+
children: [
|
|
11057
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pt-3 pb-1", children: [
|
|
11058
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11059
|
+
"h2",
|
|
11060
|
+
{
|
|
11061
|
+
id: titleId,
|
|
11062
|
+
className: "font-heading text-main-blue-primary text-base leading-tight font-bold",
|
|
11063
|
+
children: labels.allApps
|
|
11064
|
+
}
|
|
11065
|
+
),
|
|
11066
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11067
|
+
"button",
|
|
11068
|
+
{
|
|
11069
|
+
type: "button",
|
|
11070
|
+
"aria-label": labels.close,
|
|
11071
|
+
onClick: () => onOpenChange(false),
|
|
11072
|
+
className: cn(
|
|
11073
|
+
"text-main-grey hover:bg-light-200 flex size-8 items-center justify-center rounded-xl [&_svg]:size-4",
|
|
11074
|
+
FOCUS_RING
|
|
11075
|
+
),
|
|
11076
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": "true" })
|
|
11077
|
+
}
|
|
11078
|
+
)
|
|
11079
|
+
] }),
|
|
11080
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11081
|
+
AppHubCatalog,
|
|
11082
|
+
{
|
|
11083
|
+
variant: "panel",
|
|
11084
|
+
onActivate: () => onOpenChange(false),
|
|
11085
|
+
...catalog
|
|
11086
|
+
}
|
|
11087
|
+
)
|
|
11088
|
+
]
|
|
11089
|
+
}
|
|
11090
|
+
)
|
|
11091
|
+
] });
|
|
11092
|
+
}
|
|
11093
|
+
function AppHubRail({
|
|
11094
|
+
id,
|
|
11095
|
+
apps,
|
|
11096
|
+
currentAppId,
|
|
11097
|
+
open,
|
|
11098
|
+
onHide,
|
|
11099
|
+
railRef,
|
|
11100
|
+
panel
|
|
11101
|
+
}) {
|
|
11102
|
+
const { labels } = useAppHubContext();
|
|
11103
|
+
const onKeyDown = useArrowNavigation(railRef);
|
|
11104
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11105
|
+
"div",
|
|
11106
|
+
{
|
|
11107
|
+
ref: railRef,
|
|
11108
|
+
id,
|
|
11109
|
+
"data-slot": "app-hub-rail",
|
|
11110
|
+
"data-state": open ? "open" : "closed",
|
|
11111
|
+
inert: !open,
|
|
11112
|
+
onKeyDown,
|
|
11113
|
+
className: cn(
|
|
11114
|
+
"pointer-events-auto flex flex-col items-center gap-2 px-2.5 py-3",
|
|
11115
|
+
"border-light-200 bg-background/95 shadow-black-card rounded-l-4xl border border-r-0",
|
|
11116
|
+
"transition-transform duration-300 data-[state=closed]:translate-x-[150%] motion-reduce:transition-none"
|
|
11117
|
+
),
|
|
11118
|
+
children: [
|
|
11119
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { role: "list", className: "flex flex-col items-center gap-2", children: apps.map((app) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(AppHubTile, { app, current: app.id === currentAppId }) }, app.id)) }),
|
|
11120
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", className: "bg-light-300 my-0.5 h-px w-6.5" }),
|
|
11121
|
+
panel,
|
|
11122
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", className: "bg-light-300 my-0.5 h-px w-6.5" }),
|
|
11123
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Tooltip, { children: [
|
|
11124
|
+
/* @__PURE__ */ jsxRuntime.jsx(TooltipTrigger, { asChild: true, "aria-describedby": void 0, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11125
|
+
"button",
|
|
11126
|
+
{
|
|
11127
|
+
type: "button",
|
|
11128
|
+
"aria-label": labels.hideDock,
|
|
11129
|
+
"aria-expanded": "true",
|
|
11130
|
+
"aria-controls": id,
|
|
11131
|
+
"data-slot": "app-hub-hide",
|
|
11132
|
+
"data-app-hub-item": "",
|
|
11133
|
+
onClick: onHide,
|
|
11134
|
+
className: cn(
|
|
11135
|
+
"text-main-grey hover:bg-light-200 hover:text-main-blue-primary flex size-8 items-center justify-center rounded-xl [&_svg]:size-4",
|
|
11136
|
+
FOCUS_RING
|
|
11137
|
+
),
|
|
11138
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PanelRightClose, { "aria-hidden": "true" })
|
|
11139
|
+
}
|
|
11140
|
+
) }),
|
|
11141
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11142
|
+
TooltipContent,
|
|
11143
|
+
{
|
|
11144
|
+
"aria-hidden": "true",
|
|
11145
|
+
side: "left",
|
|
11146
|
+
variant: "primary",
|
|
11147
|
+
size: "sm",
|
|
11148
|
+
className: TOOLTIP_CLASS,
|
|
11149
|
+
children: labels.hideDock
|
|
11150
|
+
}
|
|
11151
|
+
)
|
|
11152
|
+
] })
|
|
11153
|
+
]
|
|
11154
|
+
}
|
|
11155
|
+
);
|
|
11156
|
+
}
|
|
11157
|
+
function AppHubTab({ railId, open, pending, onShow, tabRef }) {
|
|
11158
|
+
const { labels } = useAppHubContext();
|
|
11159
|
+
const name = [`${labels.tab}, ${labels.showDock}`, pending > 0 && labels.pending(pending)].filter(Boolean).join(", ");
|
|
11160
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11161
|
+
"div",
|
|
11162
|
+
{
|
|
11163
|
+
"data-slot": "app-hub-tab-wrapper",
|
|
11164
|
+
"data-state": open ? "open" : "closed",
|
|
11165
|
+
inert: open,
|
|
11166
|
+
className: "pointer-events-auto transition-transform duration-300 data-[state=open]:translate-x-[150%] motion-reduce:transition-none",
|
|
11167
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11168
|
+
"button",
|
|
11169
|
+
{
|
|
11170
|
+
ref: tabRef,
|
|
11171
|
+
type: "button",
|
|
11172
|
+
"aria-label": name,
|
|
11173
|
+
"aria-expanded": "false",
|
|
11174
|
+
"aria-controls": railId,
|
|
11175
|
+
"data-slot": "app-hub-tab",
|
|
11176
|
+
"data-app-hub-entry": "",
|
|
11177
|
+
onClick: onShow,
|
|
11178
|
+
className: cn(
|
|
11179
|
+
"border-light-300 bg-background/95 text-main-blue-primary flex w-10 flex-col items-center gap-2 rounded-l-2xl border border-r-0 py-3.5",
|
|
11180
|
+
FOCUS_RING
|
|
11181
|
+
),
|
|
11182
|
+
children: [
|
|
11183
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { "aria-hidden": "true", className: "size-4.5" }),
|
|
11184
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11185
|
+
"span",
|
|
11186
|
+
{
|
|
11187
|
+
"aria-hidden": "true",
|
|
11188
|
+
className: "text-main-grey text-[11px] leading-none font-semibold tracking-[0.12em] uppercase [writing-mode:vertical-rl]",
|
|
11189
|
+
children: labels.tab
|
|
11190
|
+
}
|
|
11191
|
+
),
|
|
11192
|
+
pending > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11193
|
+
"span",
|
|
11194
|
+
{
|
|
11195
|
+
"aria-hidden": "true",
|
|
11196
|
+
"data-slot": "app-hub-counter",
|
|
11197
|
+
className: "bg-main-orange-primary text-background flex h-4.5 min-w-4.5 items-center justify-center rounded-full px-1.25 text-[11px] leading-none font-bold",
|
|
11198
|
+
children: formatPendingCount(pending)
|
|
11199
|
+
}
|
|
11200
|
+
)
|
|
11201
|
+
]
|
|
11202
|
+
}
|
|
11203
|
+
)
|
|
11204
|
+
}
|
|
11205
|
+
);
|
|
11206
|
+
}
|
|
11207
|
+
function AppHubSheet({ pending, ...catalog }) {
|
|
11208
|
+
const { labels } = useAppHubContext();
|
|
11209
|
+
const [open, setOpen] = react.useState(false);
|
|
11210
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Sheet, { open, onOpenChange: setOpen, children: [
|
|
11211
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11212
|
+
SheetTrigger,
|
|
11213
|
+
{
|
|
11214
|
+
"data-slot": "app-hub-fab",
|
|
11215
|
+
"data-app-hub-entry": "",
|
|
11216
|
+
className: cn(
|
|
11217
|
+
// Bottom-right, in the thumb zone and out of the reading area (the rail centers instead).
|
|
11218
|
+
"bg-main-blue-primary text-main-white shadow-black-button pointer-events-auto mr-4 mb-4 flex h-12 items-center gap-2 self-end rounded-full pr-4.5 pl-4 text-sm font-semibold",
|
|
11219
|
+
FOCUS_RING
|
|
11220
|
+
),
|
|
11221
|
+
children: [
|
|
11222
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutGrid, { "aria-hidden": "true", className: "size-4.5" }),
|
|
11223
|
+
labels.fab,
|
|
11224
|
+
pending > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "sr-only", children: [
|
|
11225
|
+
", ",
|
|
11226
|
+
labels.pending(pending)
|
|
11227
|
+
] }),
|
|
11228
|
+
pending > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11229
|
+
"span",
|
|
11230
|
+
{
|
|
11231
|
+
"aria-hidden": "true",
|
|
11232
|
+
"data-slot": "app-hub-counter",
|
|
11233
|
+
className: "bg-main-orange-primary text-background flex h-5 min-w-5 items-center justify-center rounded-full px-1.5 text-[11px] leading-none font-bold",
|
|
11234
|
+
children: formatPendingCount(pending)
|
|
11235
|
+
}
|
|
11236
|
+
)
|
|
11237
|
+
]
|
|
11238
|
+
}
|
|
11239
|
+
),
|
|
11240
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
11241
|
+
SheetContent,
|
|
11242
|
+
{
|
|
11243
|
+
side: "bottom",
|
|
11244
|
+
"aria-modal": "true",
|
|
11245
|
+
"aria-describedby": void 0,
|
|
11246
|
+
showCloseButton: false,
|
|
11247
|
+
onOpenAutoFocus: (event) => {
|
|
11248
|
+
event.preventDefault();
|
|
11249
|
+
event.currentTarget.querySelector('[data-slot="app-hub-sheet-close"]')?.focus();
|
|
11250
|
+
},
|
|
11251
|
+
className: "max-h-[85dvh] rounded-t-3xl motion-reduce:transition-none motion-reduce:data-closed:animate-none motion-reduce:data-open:animate-none",
|
|
11252
|
+
children: [
|
|
11253
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11254
|
+
"div",
|
|
11255
|
+
{
|
|
11256
|
+
"aria-hidden": "true",
|
|
11257
|
+
className: "bg-light-300 mx-auto mt-2 h-1 w-10 rounded-full"
|
|
11258
|
+
}
|
|
11259
|
+
),
|
|
11260
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-4 pt-2", children: [
|
|
11261
|
+
/* @__PURE__ */ jsxRuntime.jsx(SheetTitle, { className: "font-heading text-main-blue-primary text-xl leading-tight font-bold", children: labels.sheetTitle }),
|
|
11262
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11263
|
+
SheetClose,
|
|
11264
|
+
{
|
|
11265
|
+
"data-slot": "app-hub-sheet-close",
|
|
11266
|
+
"aria-label": labels.close,
|
|
11267
|
+
className: cn(
|
|
11268
|
+
"text-main-grey hover:bg-light-200 flex size-11 items-center justify-center rounded-xl [&_svg]:size-5",
|
|
11269
|
+
FOCUS_RING
|
|
11270
|
+
),
|
|
11271
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { "aria-hidden": "true" })
|
|
11272
|
+
}
|
|
11273
|
+
)
|
|
11274
|
+
] }),
|
|
11275
|
+
/* @__PURE__ */ jsxRuntime.jsx(AppHubCatalog, { ...catalog, variant: "sheet", onActivate: () => setOpen(false) })
|
|
11276
|
+
]
|
|
11277
|
+
}
|
|
11278
|
+
)
|
|
11279
|
+
] });
|
|
11280
|
+
}
|
|
11281
|
+
var noopSubscribe = () => () => {
|
|
11282
|
+
};
|
|
11283
|
+
var nullSnapshot = () => null;
|
|
11284
|
+
function useAppHubOpen({
|
|
11285
|
+
open: controlledOpen,
|
|
11286
|
+
defaultOpen,
|
|
11287
|
+
onOpenChange,
|
|
11288
|
+
storageKey: storageKey2,
|
|
11289
|
+
layoutDefault
|
|
11290
|
+
}) {
|
|
11291
|
+
const controlled = controlledOpen !== void 0;
|
|
11292
|
+
const persistedKey = !controlled ? storageKey2 : null;
|
|
11293
|
+
const fallback = defaultOpen ?? layoutDefault;
|
|
11294
|
+
const [memoryOpen, setMemoryOpen] = react.useState(void 0);
|
|
11295
|
+
const [sessionOverride, setSessionOverride] = react.useState(void 0);
|
|
11296
|
+
const store = react.useMemo(() => {
|
|
11297
|
+
if (persistedKey === null) return { subscribe: noopSubscribe, getSnapshot: nullSnapshot };
|
|
11298
|
+
const subscribe2 = (notify) => {
|
|
11299
|
+
const onStorage = (event) => {
|
|
11300
|
+
if (event.key === null || event.key === persistedKey) notify();
|
|
11301
|
+
};
|
|
11302
|
+
const onChange = (event) => {
|
|
11303
|
+
if (event.detail?.key === persistedKey) notify();
|
|
11304
|
+
};
|
|
11305
|
+
window.addEventListener("storage", onStorage);
|
|
11306
|
+
window.addEventListener(OPEN_CHANGE_EVENT, onChange);
|
|
11307
|
+
return () => {
|
|
11308
|
+
window.removeEventListener("storage", onStorage);
|
|
11309
|
+
window.removeEventListener(OPEN_CHANGE_EVENT, onChange);
|
|
11310
|
+
};
|
|
11311
|
+
};
|
|
11312
|
+
const getSnapshot2 = () => {
|
|
11313
|
+
try {
|
|
11314
|
+
const value = window.localStorage.getItem(persistedKey);
|
|
11315
|
+
return value === "true" ? true : value === "false" ? false : null;
|
|
11316
|
+
} catch {
|
|
11317
|
+
return null;
|
|
11318
|
+
}
|
|
11319
|
+
};
|
|
11320
|
+
return { subscribe: subscribe2, getSnapshot: getSnapshot2 };
|
|
11321
|
+
}, [persistedKey]);
|
|
11322
|
+
const stored = react.useSyncExternalStore(store.subscribe, store.getSnapshot, nullSnapshot);
|
|
11323
|
+
const setOpen = react.useCallback(
|
|
11324
|
+
(next) => {
|
|
11325
|
+
onOpenChange?.(next);
|
|
11326
|
+
if (controlled) return;
|
|
11327
|
+
if (storageKey2 === null) {
|
|
11328
|
+
setMemoryOpen(next);
|
|
11329
|
+
return;
|
|
11330
|
+
}
|
|
11331
|
+
try {
|
|
11332
|
+
window.localStorage.setItem(storageKey2, String(next));
|
|
11333
|
+
setSessionOverride(void 0);
|
|
11334
|
+
} catch {
|
|
11335
|
+
setSessionOverride(next);
|
|
11336
|
+
}
|
|
11337
|
+
window.dispatchEvent(
|
|
11338
|
+
new CustomEvent(OPEN_CHANGE_EVENT, { detail: { key: storageKey2 } })
|
|
11339
|
+
);
|
|
11340
|
+
},
|
|
11341
|
+
[controlled, onOpenChange, storageKey2]
|
|
11342
|
+
);
|
|
11343
|
+
let open;
|
|
11344
|
+
if (controlled) open = controlledOpen;
|
|
11345
|
+
else if (storageKey2 === null) open = memoryOpen ?? fallback;
|
|
11346
|
+
else open = sessionOverride ?? stored ?? fallback;
|
|
11347
|
+
return { open, setOpen };
|
|
11348
|
+
}
|
|
11349
|
+
var DESKTOP_QUERY = "(min-width: 1024px)";
|
|
11350
|
+
var TABLET_QUERY = "(min-width: 768px)";
|
|
11351
|
+
function hasMatchMedia() {
|
|
11352
|
+
return typeof window !== "undefined" && typeof window.matchMedia === "function";
|
|
11353
|
+
}
|
|
11354
|
+
function subscribe(notify) {
|
|
11355
|
+
if (!hasMatchMedia()) return () => {
|
|
11356
|
+
};
|
|
11357
|
+
const lists = [DESKTOP_QUERY, TABLET_QUERY].map((query) => window.matchMedia(query));
|
|
11358
|
+
lists.forEach((list) => list.addEventListener("change", notify));
|
|
11359
|
+
return () => lists.forEach((list) => list.removeEventListener("change", notify));
|
|
11360
|
+
}
|
|
11361
|
+
function getSnapshot() {
|
|
11362
|
+
if (!hasMatchMedia()) return "desktop";
|
|
11363
|
+
if (window.matchMedia(DESKTOP_QUERY).matches) return "desktop";
|
|
11364
|
+
return window.matchMedia(TABLET_QUERY).matches ? "tablet" : "mobile";
|
|
11365
|
+
}
|
|
11366
|
+
var getServerSnapshot = () => "desktop";
|
|
11367
|
+
function useAppHubViewport() {
|
|
11368
|
+
return react.useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
11369
|
+
}
|
|
11370
|
+
function AppHub({
|
|
11371
|
+
apps,
|
|
11372
|
+
appName,
|
|
11373
|
+
currentAppId,
|
|
11374
|
+
catalogStatus = "ready",
|
|
11375
|
+
onRetry,
|
|
11376
|
+
directoryHref,
|
|
11377
|
+
layout = "auto",
|
|
11378
|
+
searchThreshold = 7,
|
|
11379
|
+
position = "fixed",
|
|
11380
|
+
open: openProp,
|
|
11381
|
+
defaultOpen,
|
|
11382
|
+
onOpenChange,
|
|
11383
|
+
storageKey: storageKey2 = DEFAULT_STORAGE_KEY,
|
|
11384
|
+
onNavigate,
|
|
11385
|
+
renderLink,
|
|
11386
|
+
labels: labelOverrides,
|
|
11387
|
+
id = DEFAULT_APP_HUB_ID,
|
|
11388
|
+
className
|
|
11389
|
+
}) {
|
|
11390
|
+
const merged = mergeLabels(DEFAULT_APP_HUB_LABELS, labelOverrides);
|
|
11391
|
+
const [stableLabels, setStableLabels] = react.useState(merged);
|
|
11392
|
+
const labels = areLabelsEqual(stableLabels, merged) ? stableLabels : merged;
|
|
11393
|
+
if (labels !== stableLabels) setStableLabels(labels);
|
|
11394
|
+
const viewport = useAppHubViewport();
|
|
11395
|
+
const family = layout === "auto" ? viewport === "mobile" ? "sheet" : "dock" : layout;
|
|
11396
|
+
const { open, setOpen } = useAppHubOpen({
|
|
11397
|
+
open: openProp,
|
|
11398
|
+
defaultOpen,
|
|
11399
|
+
onOpenChange,
|
|
11400
|
+
storageKey: storageKey2,
|
|
11401
|
+
// Tablet starts collapsed only when the layout follows the viewport.
|
|
11402
|
+
layoutDefault: !(layout === "auto" && viewport === "tablet")
|
|
11403
|
+
});
|
|
11404
|
+
const [panelOpen, setPanelOpen] = react.useState(false);
|
|
11405
|
+
if (!open && panelOpen) setPanelOpen(false);
|
|
11406
|
+
const [announcement, setAnnouncement] = react.useState("");
|
|
11407
|
+
const [, requestRender] = react.useReducer((count) => count + 1, 0);
|
|
11408
|
+
const previousOpenRef = react.useRef(open);
|
|
11409
|
+
const railRef = react.useRef(null);
|
|
11410
|
+
const tabRef = react.useRef(null);
|
|
11411
|
+
const focusIntentRef = react.useRef(null);
|
|
11412
|
+
const railId = `${id}-rail`;
|
|
11413
|
+
react.useLayoutEffect(() => {
|
|
11414
|
+
const intent = focusIntentRef.current;
|
|
11415
|
+
focusIntentRef.current = null;
|
|
11416
|
+
if (previousOpenRef.current === open) return;
|
|
11417
|
+
previousOpenRef.current = open;
|
|
11418
|
+
setAnnouncement(intent === open ? open ? labels.dockShown : labels.dockHidden : "");
|
|
11419
|
+
const entry = open ? getEntryElement(railRef.current) : tabRef.current;
|
|
11420
|
+
if (intent === open) {
|
|
11421
|
+
entry?.focus();
|
|
11422
|
+
return;
|
|
11423
|
+
}
|
|
11424
|
+
const active = document.activeElement;
|
|
11425
|
+
const stranded = open ? [tabRef.current] : [railRef.current, document.getElementById(`${id}-panel`)];
|
|
11426
|
+
if (active && stranded.some((element) => element?.contains(active))) entry?.focus();
|
|
11427
|
+
});
|
|
11428
|
+
function toggle(next) {
|
|
11429
|
+
focusIntentRef.current = next;
|
|
11430
|
+
setOpen(next);
|
|
11431
|
+
requestRender();
|
|
11432
|
+
}
|
|
11433
|
+
const context = react.useMemo(
|
|
11434
|
+
() => ({ labels, appName, renderLink, onNavigate }),
|
|
11435
|
+
[labels, appName, renderLink, onNavigate]
|
|
11436
|
+
);
|
|
11437
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AppHubContext, { value: context, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11438
|
+
"nav",
|
|
11439
|
+
{
|
|
11440
|
+
id,
|
|
11441
|
+
"aria-label": labels.navigation,
|
|
11442
|
+
"data-slot": "app-hub",
|
|
11443
|
+
"data-layout": family,
|
|
11444
|
+
"data-state": open ? "open" : "closed",
|
|
11445
|
+
"data-position": position,
|
|
11446
|
+
className: cn(
|
|
11447
|
+
// `overflow-x-clip` keeps the slid-out form from creating scrollable overflow
|
|
11448
|
+
// (a scrollIntoView would otherwise shift the host); `pl-8` leaves room for the shadow.
|
|
11449
|
+
"pointer-events-none inset-y-0 right-0 z-40 grid items-center justify-items-end overflow-x-clip pl-8 *:col-start-1 *:row-start-1",
|
|
11450
|
+
position === "fixed" ? "fixed" : "absolute",
|
|
11451
|
+
className
|
|
11452
|
+
),
|
|
11453
|
+
children: [
|
|
11454
|
+
family === "sheet" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
11455
|
+
AppHubSheet,
|
|
11456
|
+
{
|
|
11457
|
+
apps,
|
|
11458
|
+
currentAppId,
|
|
11459
|
+
status: catalogStatus,
|
|
11460
|
+
onRetry,
|
|
11461
|
+
directoryHref,
|
|
11462
|
+
searchThreshold,
|
|
11463
|
+
pending: sumPending(apps)
|
|
11464
|
+
}
|
|
11465
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
11466
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11467
|
+
AppHubRail,
|
|
11468
|
+
{
|
|
11469
|
+
id: railId,
|
|
11470
|
+
apps: apps.filter((app) => app.inRail && !app.locked),
|
|
11471
|
+
currentAppId,
|
|
11472
|
+
open,
|
|
11473
|
+
onHide: () => toggle(false),
|
|
11474
|
+
railRef,
|
|
11475
|
+
panel: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11476
|
+
AppHubPanel,
|
|
11477
|
+
{
|
|
11478
|
+
id: `${id}-panel`,
|
|
11479
|
+
open: panelOpen,
|
|
11480
|
+
onOpenChange: setPanelOpen,
|
|
11481
|
+
onCloseAutoFocus: (event) => {
|
|
11482
|
+
if (open) return;
|
|
11483
|
+
event.preventDefault();
|
|
11484
|
+
const active = document.activeElement;
|
|
11485
|
+
if (!active || active === document.body)
|
|
11486
|
+
tabRef.current?.focus();
|
|
11487
|
+
},
|
|
11488
|
+
apps,
|
|
11489
|
+
currentAppId,
|
|
11490
|
+
status: catalogStatus,
|
|
11491
|
+
onRetry,
|
|
11492
|
+
directoryHref,
|
|
11493
|
+
searchThreshold
|
|
11494
|
+
}
|
|
11495
|
+
)
|
|
11496
|
+
}
|
|
11497
|
+
),
|
|
11498
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11499
|
+
AppHubTab,
|
|
11500
|
+
{
|
|
11501
|
+
railId,
|
|
11502
|
+
open,
|
|
11503
|
+
pending: sumPending(apps),
|
|
11504
|
+
onShow: () => toggle(true),
|
|
11505
|
+
tabRef
|
|
11506
|
+
}
|
|
11507
|
+
)
|
|
11508
|
+
] }),
|
|
11509
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11510
|
+
"div",
|
|
11511
|
+
{
|
|
11512
|
+
role: "status",
|
|
11513
|
+
"aria-live": "polite",
|
|
11514
|
+
"aria-atomic": "true",
|
|
11515
|
+
"data-slot": "app-hub-live",
|
|
11516
|
+
className: "sr-only",
|
|
11517
|
+
children: announcement
|
|
11518
|
+
}
|
|
11519
|
+
)
|
|
11520
|
+
]
|
|
11521
|
+
}
|
|
11522
|
+
) });
|
|
11523
|
+
}
|
|
11524
|
+
function getLiveEntry(root) {
|
|
11525
|
+
const live = [...root?.querySelectorAll("[data-slot]") ?? []].find(
|
|
11526
|
+
(region) => !region.closest("[inert]") && getEntryElement(region) !== null
|
|
11527
|
+
);
|
|
11528
|
+
return getEntryElement(live ?? root);
|
|
11529
|
+
}
|
|
11530
|
+
function AppHubSkipLink({
|
|
11531
|
+
targetId = DEFAULT_APP_HUB_ID,
|
|
11532
|
+
children = "Skip to applications",
|
|
11533
|
+
className,
|
|
11534
|
+
onClick,
|
|
11535
|
+
...props
|
|
11536
|
+
}) {
|
|
11537
|
+
function handleClick(event) {
|
|
11538
|
+
onClick?.(event);
|
|
11539
|
+
if (event.defaultPrevented) return;
|
|
11540
|
+
const entry = getLiveEntry(document.getElementById(targetId));
|
|
11541
|
+
if (!entry) return;
|
|
11542
|
+
event.preventDefault();
|
|
11543
|
+
entry.focus();
|
|
11544
|
+
}
|
|
11545
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
11546
|
+
"a",
|
|
11547
|
+
{
|
|
11548
|
+
...props,
|
|
11549
|
+
href: `#${targetId}`,
|
|
11550
|
+
"data-slot": "app-hub-skip-link",
|
|
11551
|
+
onClick: handleClick,
|
|
11552
|
+
className: cn(
|
|
11553
|
+
"bg-main-blue-primary text-main-white sr-only rounded-md px-4 py-2 text-sm font-semibold",
|
|
11554
|
+
"focus:not-sr-only focus:fixed focus:top-2 focus:left-2 focus:z-50",
|
|
11555
|
+
"focus-visible:outline-main-orange-primary outline-hidden focus-visible:outline-2 focus-visible:outline-offset-2",
|
|
11556
|
+
className
|
|
11557
|
+
),
|
|
11558
|
+
children
|
|
11559
|
+
}
|
|
11560
|
+
);
|
|
11561
|
+
}
|
|
10232
11562
|
var DrawerContext = react.createContext({ isOpen: false, modal: true });
|
|
10233
11563
|
function Drawer({ children, open, onOpenChange, modal = true, ...props }) {
|
|
10234
11564
|
const [internalOpen, setInternalOpen] = react.useState(props.defaultOpen ?? false);
|
|
@@ -10689,6 +12019,8 @@ exports.AlertDialogPortal = AlertDialogPortal;
|
|
|
10689
12019
|
exports.AlertDialogTitle = AlertDialogTitle;
|
|
10690
12020
|
exports.AlertDialogTrigger = AlertDialogTrigger;
|
|
10691
12021
|
exports.AlertTitle = AlertTitle;
|
|
12022
|
+
exports.AppHub = AppHub;
|
|
12023
|
+
exports.AppHubSkipLink = AppHubSkipLink;
|
|
10692
12024
|
exports.AppShell = AppShell;
|
|
10693
12025
|
exports.Avatar = Avatar;
|
|
10694
12026
|
exports.AvatarBadge = AvatarBadge;
|