react-os-shell 3.24.0 → 3.28.1
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 +15 -1
- package/dist/{Browser-MU2LBUTA.js → Browser-AR4QP23G.js} +5 -6
- package/dist/Browser-AR4QP23G.js.map +1 -0
- package/dist/{Calculator-BFRUXV7E.js → Calculator-7MRLC77Q.js} +4 -5
- package/dist/Calculator-7MRLC77Q.js.map +1 -0
- package/dist/ConfirmDialog-2BV43KSW.js +4 -0
- package/dist/{ConfirmDialog-BEALMXZM.js.map → ConfirmDialog-2BV43KSW.js.map} +1 -1
- package/dist/{CurrencyConverter-543D5YHO.js → CurrencyConverter-6UTL2ZBY.js} +4 -5
- package/dist/CurrencyConverter-6UTL2ZBY.js.map +1 -0
- package/dist/{Documents-UGITESQI.js → Documents-FQKIQ4GH.js} +5 -6
- package/dist/Documents-FQKIQ4GH.js.map +1 -0
- package/dist/{Files-6E3RNGNQ.js → Files-NTUFLWY3.js} +5 -6
- package/dist/Files-NTUFLWY3.js.map +1 -0
- package/dist/{Notepad-LFLER4N2.js → Notepad-MQQSDSLT.js} +5 -6
- package/dist/Notepad-MQQSDSLT.js.map +1 -0
- package/dist/{PomodoroTimer-V4FCRP35.js → PomodoroTimer-YI4D7OLV.js} +5 -6
- package/dist/PomodoroTimer-YI4D7OLV.js.map +1 -0
- package/dist/{Preview-6SVV4EVG.js → Preview-2GUM6NO7.js} +5 -6
- package/dist/Preview-2GUM6NO7.js.map +1 -0
- package/dist/{Spreadsheet-OVFTWCJ6.js → Spreadsheet-6JWSE5NC.js} +5 -6
- package/dist/Spreadsheet-6JWSE5NC.js.map +1 -0
- package/dist/{Stock-UVBHR5NW.js → Stock-KQA6QWZ2.js} +4 -5
- package/dist/Stock-KQA6QWZ2.js.map +1 -0
- package/dist/{Weather-3GHOQR2B.js → Weather-45REOKUY.js} +4 -5
- package/dist/Weather-45REOKUY.js.map +1 -0
- package/dist/{WorldClock-B5ZW37KG.js → WorldClock-EJNEFDWZ.js} +4 -5
- package/dist/WorldClock-EJNEFDWZ.js.map +1 -0
- package/dist/apps/index.js +15 -16
- package/dist/apps/index.js.map +1 -1
- package/dist/chunk-CZW7CTI6.js +7 -0
- package/dist/{chunk-TGEZDU6N.js.map → chunk-CZW7CTI6.js.map} +1 -1
- package/dist/{chunk-JDGURXTZ.js → chunk-EWRKU7EF.js} +3 -3
- package/dist/{chunk-JDGURXTZ.js.map → chunk-EWRKU7EF.js.map} +1 -1
- package/dist/{chunk-L3RPWMS4.js → chunk-GHGD4GKR.js} +4 -4
- package/dist/{chunk-L3RPWMS4.js.map → chunk-GHGD4GKR.js.map} +1 -1
- package/dist/{chunk-2YTZ6COH.js → chunk-IU7MSBRI.js} +2964 -2589
- package/dist/chunk-IU7MSBRI.js.map +1 -0
- package/dist/{chunk-WNZH4GVY.js → chunk-WWT4XQJL.js} +3 -3
- package/dist/{chunk-WNZH4GVY.js.map → chunk-WWT4XQJL.js.map} +1 -1
- package/dist/index.d.ts +151 -5
- package/dist/index.js +711 -71
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/dist/Browser-MU2LBUTA.js.map +0 -1
- package/dist/Calculator-BFRUXV7E.js.map +0 -1
- package/dist/ConfirmDialog-BEALMXZM.js +0 -3
- package/dist/CurrencyConverter-543D5YHO.js.map +0 -1
- package/dist/Documents-UGITESQI.js.map +0 -1
- package/dist/Files-6E3RNGNQ.js.map +0 -1
- package/dist/Notepad-LFLER4N2.js.map +0 -1
- package/dist/PomodoroTimer-V4FCRP35.js.map +0 -1
- package/dist/Preview-6SVV4EVG.js.map +0 -1
- package/dist/Spreadsheet-OVFTWCJ6.js.map +0 -1
- package/dist/Stock-UVBHR5NW.js.map +0 -1
- package/dist/Weather-3GHOQR2B.js.map +0 -1
- package/dist/WorldClock-B5ZW37KG.js.map +0 -1
- package/dist/chunk-2YTZ6COH.js.map +0 -1
- package/dist/chunk-TGEZDU6N.js +0 -7
- package/dist/chunk-UBN4IUDE.js +0 -229
- package/dist/chunk-UBN4IUDE.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { subscribePomo, getPomoSnapshot } from './chunk-
|
|
2
|
-
export { setShellTodoProvider } from './chunk-
|
|
1
|
+
import { subscribePomo, getPomoSnapshot } from './chunk-WWT4XQJL.js';
|
|
2
|
+
export { setShellTodoProvider } from './chunk-WWT4XQJL.js';
|
|
3
3
|
export { ImageAnnotator_default as ImageAnnotator } from './chunk-QU5L5ZYM.js';
|
|
4
4
|
import { PREVIEW_OPENED_EVENT, openPreviewFile } from './chunk-DINNWYVB.js';
|
|
5
5
|
export { Breadcrumbs } from './chunk-DINNWYVB.js';
|
|
@@ -15,14 +15,13 @@ export { ShellAuthProvider, setShellAuthBridge, useShellAuth } from './chunk-ADJ
|
|
|
15
15
|
import { EditableGrid } from './chunk-GP4Y3VCB.js';
|
|
16
16
|
export { EditableGrid } from './chunk-GP4Y3VCB.js';
|
|
17
17
|
import './chunk-4SQU5YV6.js';
|
|
18
|
-
import { APP_VERSION, VERSION } from './chunk-
|
|
19
|
-
export { VERSION } from './chunk-
|
|
20
|
-
import { useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, WINDOW_REGISTRY, isPageEntry, Modal, useShellPrefs,
|
|
21
|
-
export { CancelButton, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ShellPrefsProvider, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, commitExposeHighlight, exitExposeMode, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, registerModalEscapeInterceptor, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useLocalStoragePrefs, useModalActive, useShellPrefs, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-
|
|
22
|
-
export { ConfirmProvider, confirm, confirmDestructive, prompt } from './chunk-UBN4IUDE.js';
|
|
18
|
+
import { APP_VERSION, VERSION } from './chunk-CZW7CTI6.js';
|
|
19
|
+
export { VERSION } from './chunk-CZW7CTI6.js';
|
|
20
|
+
import { registerModalEscapeInterceptor, useIsMobile, useWindowManager, PopupMenu, PopupMenuLabel, PopupMenuDivider, PopupMenuItem, WINDOW_REGISTRY, isPageEntry, Modal, useShellPrefs, SIDEBAR_STRIP_W, forgetMaximizedWindowBoxes, ModalActions, useModalActive, client_default, LoadingSpinner, isShellApiClientConfigured, CancelButton, setWindowPosition, ThumbCard, activateModal } from './chunk-IU7MSBRI.js';
|
|
21
|
+
export { CancelButton, ConfirmProvider, CopyButton, DocFavStar, Modal, ModalActions, PopupMenu, PopupMenuDivider, PopupMenuItem, PopupMenuLabel, ShellPrefsProvider, WindowCrashedFallback, WindowErrorBoundary, WindowManagerProvider, WindowTitle, commitExposeHighlight, confirm, confirmDestructive, exitExposeMode, getActiveWindowRoute, getExposeHighlight, getWindowPosition, isEntityEntry, isPageEntry, prompt, registerModalEscapeInterceptor, setExposeHighlight, setShellApiClient, setShellWindowRegistry, setWindowDefaultPosition, setWindowPosition, subscribeExposeHighlight, toggleExposeMode, useLocalStoragePrefs, useModalActive, useShellPrefs, useWidgetSettings, useWindowManager, useWindowMenuItem, useWindowTitle } from './chunk-IU7MSBRI.js';
|
|
23
22
|
import { glassStyle, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons } from './chunk-GW3RA6IS.js';
|
|
24
23
|
export { GLASS_DIVIDER, GLASS_INPUT_BG, glassStyle, setShellNavIcons } from './chunk-GW3RA6IS.js';
|
|
25
|
-
import { createContext, lazy, forwardRef, useCallback, useState, useRef,
|
|
24
|
+
import { createContext, lazy, forwardRef, useCallback, useState, useRef, useId, useEffect, useLayoutEffect, useMemo, useContext, isValidElement, cloneElement, Suspense, Fragment as Fragment$1, Children, useSyncExternalStore } from 'react';
|
|
26
25
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
27
26
|
import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
|
|
28
27
|
import { createPortal } from 'react-dom';
|
|
@@ -4371,7 +4370,7 @@ function Layout({
|
|
|
4371
4370
|
const { prefs, save: savePrefs } = useShellPrefs();
|
|
4372
4371
|
const layoutMode = prefs.layout_mode === "sidebar" ? "sidebar" : "classic";
|
|
4373
4372
|
const sidebarMode = layoutMode === "sidebar";
|
|
4374
|
-
const sidebarWidth = sidebarMode ?
|
|
4373
|
+
const sidebarWidth = sidebarMode ? SIDEBAR_STRIP_W : 0;
|
|
4375
4374
|
const taskbarPositionRaw = prefs.taskbar_position || "bottom";
|
|
4376
4375
|
const taskbarPosition = sidebarMode ? "bottom" : taskbarPositionRaw;
|
|
4377
4376
|
const taskbarSize = prefs.taskbar_size || "medium";
|
|
@@ -5082,7 +5081,7 @@ function Customization({ omit, section } = {}) {
|
|
|
5082
5081
|
inSection("layout") && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5083
5082
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
5084
5083
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-3", children: "Layout Mode" }),
|
|
5085
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mb-3", children: "Sidebar mode is designed for small screens \u2014 windows always run maximized and the start menu lives in a persistent left sidebar (sections expand inline instead of opening flyouts)." }),
|
|
5084
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-gray-500 mb-3", children: "Sidebar mode is designed for small screens \u2014 windows always run maximized and the start menu lives in a persistent left sidebar (sections expand inline instead of opening flyouts). Classic is the windowed mode: choosing it puts every open window back to its normal size." }),
|
|
5086
5085
|
/* @__PURE__ */ jsx("div", { className: "flex gap-2", children: [
|
|
5087
5086
|
{ key: "classic", label: "Classic" },
|
|
5088
5087
|
{ key: "sidebar", label: "Sidebar" }
|
|
@@ -5091,7 +5090,11 @@ function Customization({ omit, section } = {}) {
|
|
|
5091
5090
|
{
|
|
5092
5091
|
onClick: () => {
|
|
5093
5092
|
savePref("layout_mode", m.key);
|
|
5094
|
-
if (m.key === "
|
|
5093
|
+
if (m.key === "classic") {
|
|
5094
|
+
if (prefs.default_window_size === "maximized") savePref("default_window_size", "large");
|
|
5095
|
+
forgetMaximizedWindowBoxes();
|
|
5096
|
+
window.dispatchEvent(new CustomEvent("react-os-shell:restore-windowed"));
|
|
5097
|
+
}
|
|
5095
5098
|
},
|
|
5096
5099
|
className: `px-3 py-1.5 text-xs font-medium rounded-lg border transition-colors ${(prefs.layout_mode || "classic") === m.key ? "bg-blue-600 text-white border-blue-600" : "bg-white text-gray-700 border-gray-300 hover:bg-gray-50"}`,
|
|
5097
5100
|
children: m.label
|
|
@@ -5979,12 +5982,76 @@ function ListFooter({
|
|
|
5979
5982
|
isFetchingMore ? " \xB7 Loading more..." : ""
|
|
5980
5983
|
] });
|
|
5981
5984
|
}
|
|
5985
|
+
var BASE = "inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-60";
|
|
5986
|
+
var VARIANTS2 = {
|
|
5987
|
+
primary: "bg-blue-600 text-white shadow-sm hover:bg-blue-700 focus:ring-blue-400/40",
|
|
5988
|
+
secondary: "border border-gray-300 bg-white text-gray-700 shadow-sm hover:bg-gray-50 focus:ring-blue-400/30",
|
|
5989
|
+
ghost: "text-gray-700 hover:bg-gray-100 focus:ring-blue-400/30",
|
|
5990
|
+
danger: "bg-red-600 text-white shadow-sm hover:bg-red-700 focus:ring-red-400/40"
|
|
5991
|
+
};
|
|
5992
|
+
var SIZES = {
|
|
5993
|
+
sm: "gap-1 px-2.5 py-1 text-xs",
|
|
5994
|
+
md: "gap-1.5 px-3 py-1.5 text-sm"
|
|
5995
|
+
};
|
|
5996
|
+
function Spinner() {
|
|
5997
|
+
return /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
5998
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
5999
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
6000
|
+
] });
|
|
6001
|
+
}
|
|
6002
|
+
var Button = forwardRef(function Button2({
|
|
6003
|
+
variant = "primary",
|
|
6004
|
+
size = "md",
|
|
6005
|
+
loading = false,
|
|
6006
|
+
leftIcon,
|
|
6007
|
+
rightIcon,
|
|
6008
|
+
block = false,
|
|
6009
|
+
disabled,
|
|
6010
|
+
type = "button",
|
|
6011
|
+
children,
|
|
6012
|
+
className = "",
|
|
6013
|
+
...rest
|
|
6014
|
+
}, ref) {
|
|
6015
|
+
return /* @__PURE__ */ jsxs(
|
|
6016
|
+
"button",
|
|
6017
|
+
{
|
|
6018
|
+
ref,
|
|
6019
|
+
type,
|
|
6020
|
+
disabled: disabled || loading,
|
|
6021
|
+
"aria-busy": loading || void 0,
|
|
6022
|
+
className: [BASE, VARIANTS2[variant], SIZES[size], block ? "w-full" : "", className].filter(Boolean).join(" "),
|
|
6023
|
+
...rest,
|
|
6024
|
+
children: [
|
|
6025
|
+
loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
|
|
6026
|
+
children,
|
|
6027
|
+
!loading && rightIcon
|
|
6028
|
+
]
|
|
6029
|
+
}
|
|
6030
|
+
);
|
|
6031
|
+
});
|
|
6032
|
+
var Button_default = Button;
|
|
6033
|
+
function ListLoadError({
|
|
6034
|
+
title = "Couldn't load this list",
|
|
6035
|
+
message = "Something went wrong fetching these records. Check your connection and try again.",
|
|
6036
|
+
onRetry,
|
|
6037
|
+
variant = "dashed"
|
|
6038
|
+
}) {
|
|
6039
|
+
const frame = variant === "card" ? "rounded-md border border-gray-200 bg-white px-6 py-12" : variant === "none" ? "px-6 py-12" : "rounded-lg border-2 border-dashed border-red-200 px-6 py-12";
|
|
6040
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex flex-col items-center justify-center text-center ${frame}`, role: "alert", children: [
|
|
6041
|
+
/* @__PURE__ */ jsx("svg", { className: "h-10 w-10 text-red-300 mb-3", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 1, "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M12 9v3.75m0 3.75h.008M10.34 3.94l-8.4 14.55A1.5 1.5 0 003.24 21h17.52a1.5 1.5 0 001.3-2.51l-8.4-14.55a1.5 1.5 0 00-2.6 0z" }) }),
|
|
6042
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900", children: title }),
|
|
6043
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-2", children: message }),
|
|
6044
|
+
onRetry && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Button_default, { variant: "secondary", size: "sm", onClick: onRetry, children: "Try again" }) })
|
|
6045
|
+
] });
|
|
6046
|
+
}
|
|
5982
6047
|
function EntityList(props) {
|
|
5983
6048
|
const {
|
|
5984
6049
|
items,
|
|
5985
6050
|
isLoading,
|
|
5986
6051
|
emptyState,
|
|
5987
6052
|
totalCount,
|
|
6053
|
+
isError,
|
|
6054
|
+
onRetry,
|
|
5988
6055
|
tableId,
|
|
5989
6056
|
columns,
|
|
5990
6057
|
renderCell,
|
|
@@ -6070,6 +6137,7 @@ function EntityList(props) {
|
|
|
6070
6137
|
}
|
|
6071
6138
|
};
|
|
6072
6139
|
if (isLoading) return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
6140
|
+
if (isError && items.length === 0) return /* @__PURE__ */ jsx(ListLoadError, { onRetry });
|
|
6073
6141
|
if (items.length === 0) return /* @__PURE__ */ jsx(Fragment, { children: emptyState });
|
|
6074
6142
|
const allSelected = items.length > 0 && selected.size === items.length;
|
|
6075
6143
|
const fullColumns = [
|
|
@@ -6427,6 +6495,10 @@ function useInfiniteScroll({
|
|
|
6427
6495
|
items: allItems,
|
|
6428
6496
|
totalCount,
|
|
6429
6497
|
isLoading: query.isLoading,
|
|
6498
|
+
// Surface the query's error state so a failed fetch renders as an error
|
|
6499
|
+
// (with retry) rather than a misleading empty list. `refetch` is the retry.
|
|
6500
|
+
isError: query.isError,
|
|
6501
|
+
error: query.error,
|
|
6430
6502
|
isFetchingNextPage,
|
|
6431
6503
|
hasNextPage: !!hasNextPage,
|
|
6432
6504
|
sentinelRef,
|
|
@@ -6543,54 +6615,6 @@ function Pagination({
|
|
|
6543
6615
|
showEdges && /* @__PURE__ */ jsx("button", { type: "button", "aria-label": "Last page", disabled: page === pageCount, onClick: () => go(pageCount), className: `${BTN} text-gray-600 hover:bg-gray-100`, children: "\xBB" })
|
|
6544
6616
|
] });
|
|
6545
6617
|
}
|
|
6546
|
-
var BASE = "inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 disabled:cursor-not-allowed disabled:opacity-60";
|
|
6547
|
-
var VARIANTS2 = {
|
|
6548
|
-
primary: "bg-blue-600 text-white shadow-sm hover:bg-blue-700 focus:ring-blue-400/40",
|
|
6549
|
-
secondary: "border border-gray-300 bg-white text-gray-700 shadow-sm hover:bg-gray-50 focus:ring-blue-400/30",
|
|
6550
|
-
ghost: "text-gray-700 hover:bg-gray-100 focus:ring-blue-400/30",
|
|
6551
|
-
danger: "bg-red-600 text-white shadow-sm hover:bg-red-700 focus:ring-red-400/40"
|
|
6552
|
-
};
|
|
6553
|
-
var SIZES = {
|
|
6554
|
-
sm: "gap-1 px-2.5 py-1 text-xs",
|
|
6555
|
-
md: "gap-1.5 px-3 py-1.5 text-sm"
|
|
6556
|
-
};
|
|
6557
|
-
function Spinner() {
|
|
6558
|
-
return /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
6559
|
-
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
6560
|
-
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
6561
|
-
] });
|
|
6562
|
-
}
|
|
6563
|
-
var Button = forwardRef(function Button2({
|
|
6564
|
-
variant = "primary",
|
|
6565
|
-
size = "md",
|
|
6566
|
-
loading = false,
|
|
6567
|
-
leftIcon,
|
|
6568
|
-
rightIcon,
|
|
6569
|
-
block = false,
|
|
6570
|
-
disabled,
|
|
6571
|
-
type = "button",
|
|
6572
|
-
children,
|
|
6573
|
-
className = "",
|
|
6574
|
-
...rest
|
|
6575
|
-
}, ref) {
|
|
6576
|
-
return /* @__PURE__ */ jsxs(
|
|
6577
|
-
"button",
|
|
6578
|
-
{
|
|
6579
|
-
ref,
|
|
6580
|
-
type,
|
|
6581
|
-
disabled: disabled || loading,
|
|
6582
|
-
"aria-busy": loading || void 0,
|
|
6583
|
-
className: [BASE, VARIANTS2[variant], SIZES[size], block ? "w-full" : "", className].filter(Boolean).join(" "),
|
|
6584
|
-
...rest,
|
|
6585
|
-
children: [
|
|
6586
|
-
loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
|
|
6587
|
-
children,
|
|
6588
|
-
!loading && rightIcon
|
|
6589
|
-
]
|
|
6590
|
-
}
|
|
6591
|
-
);
|
|
6592
|
-
});
|
|
6593
|
-
var Button_default = Button;
|
|
6594
6618
|
var Input = forwardRef(function Input2({ invalid, leftIcon, rightAdornment, className = "", ...rest }, ref) {
|
|
6595
6619
|
const pad = `${leftIcon ? "pl-9" : ""} ${rightAdornment ? "pr-9" : ""}`.trim();
|
|
6596
6620
|
const field = /* @__PURE__ */ jsx(
|
|
@@ -6630,7 +6654,44 @@ var Textarea = forwardRef(function Textarea2({ invalid, autoGrow, className = ""
|
|
|
6630
6654
|
);
|
|
6631
6655
|
});
|
|
6632
6656
|
var Textarea_default = Textarea;
|
|
6633
|
-
|
|
6657
|
+
|
|
6658
|
+
// src/forms/selectNav.ts
|
|
6659
|
+
function firstEnabledIndex(options) {
|
|
6660
|
+
for (let i = 0; i < options.length; i++) {
|
|
6661
|
+
if (!options[i].disabled) return i;
|
|
6662
|
+
}
|
|
6663
|
+
return -1;
|
|
6664
|
+
}
|
|
6665
|
+
function lastEnabledIndex(options) {
|
|
6666
|
+
for (let i = options.length - 1; i >= 0; i--) {
|
|
6667
|
+
if (!options[i].disabled) return i;
|
|
6668
|
+
}
|
|
6669
|
+
return -1;
|
|
6670
|
+
}
|
|
6671
|
+
function nextEnabledIndex(options, from, dir) {
|
|
6672
|
+
let i = from + dir;
|
|
6673
|
+
while (i >= 0 && i < options.length) {
|
|
6674
|
+
if (!options[i].disabled) return i;
|
|
6675
|
+
i += dir;
|
|
6676
|
+
}
|
|
6677
|
+
if (from >= 0 && from < options.length && !options[from].disabled) return from;
|
|
6678
|
+
return dir > 0 ? firstEnabledIndex(options) : lastEnabledIndex(options);
|
|
6679
|
+
}
|
|
6680
|
+
function matchTypeahead(options, buffer, fromIndex) {
|
|
6681
|
+
const q = buffer.toLowerCase();
|
|
6682
|
+
const n = options.length;
|
|
6683
|
+
if (!q || n === 0) return -1;
|
|
6684
|
+
for (let step = 1; step <= n; step++) {
|
|
6685
|
+
const i = ((fromIndex + step) % n + n) % n;
|
|
6686
|
+
const o = options[i];
|
|
6687
|
+
if (!o.disabled && o.label.toLowerCase().startsWith(q)) return i;
|
|
6688
|
+
}
|
|
6689
|
+
return -1;
|
|
6690
|
+
}
|
|
6691
|
+
var MENU_GAP2 = 4;
|
|
6692
|
+
var VIEWPORT_MARGIN2 = 8;
|
|
6693
|
+
var MENU_MAX_HEIGHT2 = 240;
|
|
6694
|
+
var NativeSelect = forwardRef(function NativeSelect2({ value, onChange, options, placeholder, invalid, className = "", ...rest }, ref) {
|
|
6634
6695
|
return /* @__PURE__ */ jsxs(
|
|
6635
6696
|
"select",
|
|
6636
6697
|
{
|
|
@@ -6646,6 +6707,260 @@ var Select = forwardRef(function Select2({ value, onChange, options, placeholder
|
|
|
6646
6707
|
}
|
|
6647
6708
|
);
|
|
6648
6709
|
});
|
|
6710
|
+
function useAnchoredPosition(triggerRef, open) {
|
|
6711
|
+
const [pos, setPos] = useState(null);
|
|
6712
|
+
useLayoutEffect(() => {
|
|
6713
|
+
if (!open) {
|
|
6714
|
+
setPos(null);
|
|
6715
|
+
return;
|
|
6716
|
+
}
|
|
6717
|
+
let lastLeft = NaN, lastTop = NaN, lastBottom = NaN;
|
|
6718
|
+
const compute = () => {
|
|
6719
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
6720
|
+
if (!rect) return;
|
|
6721
|
+
lastLeft = rect.left;
|
|
6722
|
+
lastTop = rect.top;
|
|
6723
|
+
lastBottom = rect.bottom;
|
|
6724
|
+
const spaceBelow = window.innerHeight - rect.bottom - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
6725
|
+
const spaceAbove = rect.top - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
6726
|
+
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT2, 160) && spaceAbove > spaceBelow;
|
|
6727
|
+
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT2, placeAbove ? spaceAbove : spaceBelow));
|
|
6728
|
+
const left = Math.max(VIEWPORT_MARGIN2, Math.min(rect.left, window.innerWidth - rect.width - VIEWPORT_MARGIN2));
|
|
6729
|
+
const next = { left, minWidth: rect.width, maxHeight };
|
|
6730
|
+
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP2;
|
|
6731
|
+
else next.top = rect.bottom + MENU_GAP2;
|
|
6732
|
+
setPos(next);
|
|
6733
|
+
};
|
|
6734
|
+
compute();
|
|
6735
|
+
let raf = requestAnimationFrame(function tick() {
|
|
6736
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
6737
|
+
if (rect && (rect.left !== lastLeft || rect.top !== lastTop || rect.bottom !== lastBottom)) compute();
|
|
6738
|
+
raf = requestAnimationFrame(tick);
|
|
6739
|
+
});
|
|
6740
|
+
window.addEventListener("scroll", compute, true);
|
|
6741
|
+
window.addEventListener("resize", compute);
|
|
6742
|
+
return () => {
|
|
6743
|
+
cancelAnimationFrame(raf);
|
|
6744
|
+
window.removeEventListener("scroll", compute, true);
|
|
6745
|
+
window.removeEventListener("resize", compute);
|
|
6746
|
+
};
|
|
6747
|
+
}, [open, triggerRef]);
|
|
6748
|
+
return pos;
|
|
6749
|
+
}
|
|
6750
|
+
var ListboxSelect = forwardRef(function ListboxSelect2({ value, onChange, options, placeholder, invalid, className = "", id, disabled, ...rest }, ref) {
|
|
6751
|
+
const [open, setOpen] = useState(false);
|
|
6752
|
+
const [active, setActive] = useState(-1);
|
|
6753
|
+
const wrapRef = useRef(null);
|
|
6754
|
+
const triggerRef = useRef(null);
|
|
6755
|
+
const listRef = useRef(null);
|
|
6756
|
+
const openRef = useRef(open);
|
|
6757
|
+
openRef.current = open;
|
|
6758
|
+
const typeahead = useRef({ buffer: "", timer: null });
|
|
6759
|
+
const baseId = useId();
|
|
6760
|
+
const listboxId = `${baseId}-listbox`;
|
|
6761
|
+
const optionId = (i) => `${baseId}-opt-${i}`;
|
|
6762
|
+
const menuPos = useAnchoredPosition(triggerRef, open);
|
|
6763
|
+
const selectedIndex = options.findIndex((o) => o.value === value);
|
|
6764
|
+
const selectedLabel = selectedIndex >= 0 ? options[selectedIndex].label : void 0;
|
|
6765
|
+
const close = useCallback((refocus = true) => {
|
|
6766
|
+
setOpen(false);
|
|
6767
|
+
setActive(-1);
|
|
6768
|
+
if (refocus) triggerRef.current?.focus();
|
|
6769
|
+
}, []);
|
|
6770
|
+
const openList = useCallback(() => {
|
|
6771
|
+
if (disabled) return;
|
|
6772
|
+
setActive(selectedIndex >= 0 ? selectedIndex : firstEnabledIndex(options));
|
|
6773
|
+
setOpen(true);
|
|
6774
|
+
}, [disabled, options, selectedIndex]);
|
|
6775
|
+
const commit = useCallback((i) => {
|
|
6776
|
+
const o = options[i];
|
|
6777
|
+
if (!o || o.disabled) return;
|
|
6778
|
+
onChange(o.value);
|
|
6779
|
+
close();
|
|
6780
|
+
}, [options, onChange, close]);
|
|
6781
|
+
useEffect(() => {
|
|
6782
|
+
if (!open) return;
|
|
6783
|
+
const unregister = registerModalEscapeInterceptor((e) => {
|
|
6784
|
+
if (e.key !== "Escape" || !openRef.current) return false;
|
|
6785
|
+
close();
|
|
6786
|
+
return true;
|
|
6787
|
+
});
|
|
6788
|
+
return unregister;
|
|
6789
|
+
}, [open, close]);
|
|
6790
|
+
useEffect(() => {
|
|
6791
|
+
if (!open) return;
|
|
6792
|
+
const handler = (e) => {
|
|
6793
|
+
const t = e.target;
|
|
6794
|
+
if (wrapRef.current?.contains(t) || listRef.current?.contains(t)) return;
|
|
6795
|
+
close(false);
|
|
6796
|
+
};
|
|
6797
|
+
document.addEventListener("pointerdown", handler);
|
|
6798
|
+
return () => document.removeEventListener("pointerdown", handler);
|
|
6799
|
+
}, [open, close]);
|
|
6800
|
+
useEffect(() => {
|
|
6801
|
+
if (!open || active < 0) return;
|
|
6802
|
+
listRef.current?.querySelector(`#${CSS.escape(optionId(active))}`)?.scrollIntoView({ block: "nearest" });
|
|
6803
|
+
});
|
|
6804
|
+
const runTypeahead = useCallback((char) => {
|
|
6805
|
+
const ta = typeahead.current;
|
|
6806
|
+
if (ta.timer) clearTimeout(ta.timer);
|
|
6807
|
+
ta.buffer += char;
|
|
6808
|
+
ta.timer = setTimeout(() => {
|
|
6809
|
+
ta.buffer = "";
|
|
6810
|
+
ta.timer = null;
|
|
6811
|
+
}, 500);
|
|
6812
|
+
const from = open ? active : selectedIndex;
|
|
6813
|
+
const hit = matchTypeahead(options, ta.buffer, from);
|
|
6814
|
+
if (hit < 0) return;
|
|
6815
|
+
if (open) setActive(hit);
|
|
6816
|
+
else commit(hit);
|
|
6817
|
+
}, [open, active, selectedIndex, options, commit]);
|
|
6818
|
+
const onKeyDown = (e) => {
|
|
6819
|
+
if (disabled) return;
|
|
6820
|
+
switch (e.key) {
|
|
6821
|
+
case "ArrowDown":
|
|
6822
|
+
e.preventDefault();
|
|
6823
|
+
if (!open) openList();
|
|
6824
|
+
else setActive((a) => nextEnabledIndex(options, a, 1));
|
|
6825
|
+
return;
|
|
6826
|
+
case "ArrowUp":
|
|
6827
|
+
e.preventDefault();
|
|
6828
|
+
if (!open) openList();
|
|
6829
|
+
else setActive((a) => nextEnabledIndex(options, a, -1));
|
|
6830
|
+
return;
|
|
6831
|
+
case "Home":
|
|
6832
|
+
if (open) {
|
|
6833
|
+
e.preventDefault();
|
|
6834
|
+
setActive(firstEnabledIndex(options));
|
|
6835
|
+
}
|
|
6836
|
+
return;
|
|
6837
|
+
case "End":
|
|
6838
|
+
if (open) {
|
|
6839
|
+
e.preventDefault();
|
|
6840
|
+
setActive(lastEnabledIndex(options));
|
|
6841
|
+
}
|
|
6842
|
+
return;
|
|
6843
|
+
case "Enter":
|
|
6844
|
+
if (open) {
|
|
6845
|
+
e.preventDefault();
|
|
6846
|
+
commit(active);
|
|
6847
|
+
}
|
|
6848
|
+
return;
|
|
6849
|
+
case " ":
|
|
6850
|
+
e.preventDefault();
|
|
6851
|
+
if (!open) openList();
|
|
6852
|
+
else commit(active);
|
|
6853
|
+
return;
|
|
6854
|
+
case "Escape":
|
|
6855
|
+
if (open) {
|
|
6856
|
+
e.preventDefault();
|
|
6857
|
+
e.stopPropagation();
|
|
6858
|
+
close();
|
|
6859
|
+
}
|
|
6860
|
+
return;
|
|
6861
|
+
case "Tab":
|
|
6862
|
+
if (open) close(false);
|
|
6863
|
+
return;
|
|
6864
|
+
default:
|
|
6865
|
+
if (e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
6866
|
+
e.preventDefault();
|
|
6867
|
+
runTypeahead(e.key);
|
|
6868
|
+
}
|
|
6869
|
+
}
|
|
6870
|
+
};
|
|
6871
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative", children: [
|
|
6872
|
+
/* @__PURE__ */ jsx(
|
|
6873
|
+
"button",
|
|
6874
|
+
{
|
|
6875
|
+
ref: triggerRef,
|
|
6876
|
+
id,
|
|
6877
|
+
type: "button",
|
|
6878
|
+
role: "combobox",
|
|
6879
|
+
"aria-haspopup": "listbox",
|
|
6880
|
+
"aria-expanded": open,
|
|
6881
|
+
"aria-controls": open ? listboxId : void 0,
|
|
6882
|
+
"aria-activedescendant": open && active >= 0 ? optionId(active) : void 0,
|
|
6883
|
+
"aria-invalid": invalid || void 0,
|
|
6884
|
+
disabled,
|
|
6885
|
+
onClick: () => open ? close() : openList(),
|
|
6886
|
+
onKeyDown,
|
|
6887
|
+
className: inputClasses({ invalid, className: `pr-8 text-left ${className}`.trim() }),
|
|
6888
|
+
children: /* @__PURE__ */ jsx("span", { className: `block truncate ${selectedLabel === void 0 ? "text-gray-400" : ""}`, children: selectedLabel ?? placeholder ?? "\xA0" })
|
|
6889
|
+
}
|
|
6890
|
+
),
|
|
6891
|
+
/* @__PURE__ */ jsx(
|
|
6892
|
+
"svg",
|
|
6893
|
+
{
|
|
6894
|
+
"aria-hidden": "true",
|
|
6895
|
+
className: "pointer-events-none absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400",
|
|
6896
|
+
fill: "none",
|
|
6897
|
+
viewBox: "0 0 24 24",
|
|
6898
|
+
stroke: "currentColor",
|
|
6899
|
+
strokeWidth: 2,
|
|
6900
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 9l3.75-3.75L15.75 9M8.25 15l3.75 3.75L15.75 15" })
|
|
6901
|
+
}
|
|
6902
|
+
),
|
|
6903
|
+
/* @__PURE__ */ jsxs(
|
|
6904
|
+
"select",
|
|
6905
|
+
{
|
|
6906
|
+
ref,
|
|
6907
|
+
value,
|
|
6908
|
+
onChange: (e) => onChange(e.target.value),
|
|
6909
|
+
disabled,
|
|
6910
|
+
"aria-hidden": "true",
|
|
6911
|
+
tabIndex: -1,
|
|
6912
|
+
className: "sr-only",
|
|
6913
|
+
...rest,
|
|
6914
|
+
children: [
|
|
6915
|
+
placeholder !== void 0 && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
|
|
6916
|
+
options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
|
|
6917
|
+
]
|
|
6918
|
+
}
|
|
6919
|
+
),
|
|
6920
|
+
open && createPortal(
|
|
6921
|
+
/* @__PURE__ */ jsx(
|
|
6922
|
+
"div",
|
|
6923
|
+
{
|
|
6924
|
+
ref: listRef,
|
|
6925
|
+
id: listboxId,
|
|
6926
|
+
role: "listbox",
|
|
6927
|
+
className: "fixed z-[400] overflow-y-auto rounded-2xl py-1",
|
|
6928
|
+
style: {
|
|
6929
|
+
left: menuPos?.left,
|
|
6930
|
+
top: menuPos?.top,
|
|
6931
|
+
bottom: menuPos?.bottom,
|
|
6932
|
+
minWidth: menuPos?.minWidth,
|
|
6933
|
+
maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2,
|
|
6934
|
+
visibility: menuPos ? void 0 : "hidden",
|
|
6935
|
+
...glassStyle()
|
|
6936
|
+
},
|
|
6937
|
+
children: options.map((o, i) => /* @__PURE__ */ jsx(
|
|
6938
|
+
"div",
|
|
6939
|
+
{
|
|
6940
|
+
id: optionId(i),
|
|
6941
|
+
role: "option",
|
|
6942
|
+
"aria-selected": value === o.value,
|
|
6943
|
+
"aria-disabled": o.disabled || void 0,
|
|
6944
|
+
onPointerEnter: () => {
|
|
6945
|
+
if (!o.disabled) setActive(i);
|
|
6946
|
+
},
|
|
6947
|
+
onClick: () => commit(i),
|
|
6948
|
+
className: `mx-1 cursor-pointer truncate rounded-lg px-3 py-1.5 text-sm
|
|
6949
|
+
${o.disabled ? "cursor-not-allowed text-gray-400" : i === active ? "bg-blue-50 text-blue-700" : value === o.value ? "font-medium text-blue-600" : "text-gray-700"}`,
|
|
6950
|
+
children: o.label
|
|
6951
|
+
},
|
|
6952
|
+
o.value
|
|
6953
|
+
))
|
|
6954
|
+
}
|
|
6955
|
+
),
|
|
6956
|
+
document.body
|
|
6957
|
+
)
|
|
6958
|
+
] });
|
|
6959
|
+
});
|
|
6960
|
+
var Select = forwardRef(function Select2(props, ref) {
|
|
6961
|
+
const isMobile = useIsMobile();
|
|
6962
|
+
return isMobile ? /* @__PURE__ */ jsx(NativeSelect, { ref, ...props }) : /* @__PURE__ */ jsx(ListboxSelect, { ref, ...props });
|
|
6963
|
+
});
|
|
6649
6964
|
var Select_default = Select;
|
|
6650
6965
|
var BOX = "h-4 w-4 shrink-0 rounded border-gray-300 accent-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-400/30 disabled:cursor-not-allowed disabled:opacity-60";
|
|
6651
6966
|
var Checkbox = forwardRef(function Checkbox2({ checked, onChange, label, description, disabled, className = "", ...rest }, ref) {
|
|
@@ -7490,16 +7805,12 @@ function FilterBar({ filters, values, onChange, onClear, children }) {
|
|
|
7490
7805
|
onChange: (v) => onChange(f.field, v)
|
|
7491
7806
|
},
|
|
7492
7807
|
f.field
|
|
7493
|
-
) : /* @__PURE__ */
|
|
7494
|
-
|
|
7808
|
+
) : /* @__PURE__ */ jsx(
|
|
7809
|
+
PlainFilter,
|
|
7495
7810
|
{
|
|
7811
|
+
filter: f,
|
|
7496
7812
|
value: values[f.field] || "",
|
|
7497
|
-
onChange: (
|
|
7498
|
-
className: `border rounded-lg px-2.5 py-1.5 text-sm ${values[f.field] ? "border-blue-400 bg-blue-50 text-blue-700" : "border-gray-300 text-gray-600"}`,
|
|
7499
|
-
children: [
|
|
7500
|
-
/* @__PURE__ */ jsx("option", { value: "", children: f.label }),
|
|
7501
|
-
f.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
7502
|
-
]
|
|
7813
|
+
onChange: (v) => onChange(f.field, v)
|
|
7503
7814
|
},
|
|
7504
7815
|
f.field
|
|
7505
7816
|
);
|
|
@@ -7511,6 +7822,155 @@ function FilterBar({ filters, values, onChange, onClear, children }) {
|
|
|
7511
7822
|
] })
|
|
7512
7823
|
] });
|
|
7513
7824
|
}
|
|
7825
|
+
function PlainFilter({ filter, value, onChange }) {
|
|
7826
|
+
const [open, setOpen] = useState(false);
|
|
7827
|
+
const [active, setActive] = useState(-1);
|
|
7828
|
+
const ref = useRef(null);
|
|
7829
|
+
const triggerRef = useRef(null);
|
|
7830
|
+
const listRef = useRef(null);
|
|
7831
|
+
const openRef = useRef(open);
|
|
7832
|
+
openRef.current = open;
|
|
7833
|
+
const typeahead = useRef({ buffer: "", timer: null });
|
|
7834
|
+
const baseId = useId();
|
|
7835
|
+
const listboxId = `${baseId}-listbox`;
|
|
7836
|
+
const optionId = (i) => `${baseId}-opt-${i}`;
|
|
7837
|
+
const items = [{ value: "", label: filter.label }, ...filter.options];
|
|
7838
|
+
const selectedIndex = value ? items.findIndex((o) => o.value === value) : 0;
|
|
7839
|
+
const selectedLabel = value ? filter.options.find((o) => o.value === value)?.label : null;
|
|
7840
|
+
const close = useCallback((refocus = true) => {
|
|
7841
|
+
setOpen(false);
|
|
7842
|
+
setActive(-1);
|
|
7843
|
+
if (refocus) triggerRef.current?.focus();
|
|
7844
|
+
}, []);
|
|
7845
|
+
const openList = useCallback(() => {
|
|
7846
|
+
setActive(selectedIndex >= 0 ? selectedIndex : firstEnabledIndex(items));
|
|
7847
|
+
setOpen(true);
|
|
7848
|
+
}, [selectedIndex, items]);
|
|
7849
|
+
const commit = useCallback((i) => {
|
|
7850
|
+
const o = items[i];
|
|
7851
|
+
if (!o) return;
|
|
7852
|
+
onChange(o.value);
|
|
7853
|
+
close();
|
|
7854
|
+
}, [items, onChange, close]);
|
|
7855
|
+
useClickOutside(ref, useCallback(() => {
|
|
7856
|
+
if (open) close(false);
|
|
7857
|
+
}, [open, close]));
|
|
7858
|
+
useEffect(() => {
|
|
7859
|
+
if (!open) return;
|
|
7860
|
+
return registerModalEscapeInterceptor((e) => {
|
|
7861
|
+
if (e.key !== "Escape" || !openRef.current) return false;
|
|
7862
|
+
close();
|
|
7863
|
+
return true;
|
|
7864
|
+
});
|
|
7865
|
+
}, [open, close]);
|
|
7866
|
+
useEffect(() => {
|
|
7867
|
+
if (!open || active < 0) return;
|
|
7868
|
+
listRef.current?.querySelector(`#${CSS.escape(optionId(active))}`)?.scrollIntoView({ block: "nearest" });
|
|
7869
|
+
});
|
|
7870
|
+
const runTypeahead = (char) => {
|
|
7871
|
+
const ta = typeahead.current;
|
|
7872
|
+
if (ta.timer) clearTimeout(ta.timer);
|
|
7873
|
+
ta.buffer += char;
|
|
7874
|
+
ta.timer = setTimeout(() => {
|
|
7875
|
+
ta.buffer = "";
|
|
7876
|
+
ta.timer = null;
|
|
7877
|
+
}, 500);
|
|
7878
|
+
const hit = matchTypeahead(items, ta.buffer, open ? active : selectedIndex);
|
|
7879
|
+
if (hit < 0) return;
|
|
7880
|
+
if (open) setActive(hit);
|
|
7881
|
+
else commit(hit);
|
|
7882
|
+
};
|
|
7883
|
+
const onKeyDown = (e) => {
|
|
7884
|
+
switch (e.key) {
|
|
7885
|
+
case "ArrowDown":
|
|
7886
|
+
e.preventDefault();
|
|
7887
|
+
if (!open) openList();
|
|
7888
|
+
else setActive((a) => nextEnabledIndex(items, a, 1));
|
|
7889
|
+
return;
|
|
7890
|
+
case "ArrowUp":
|
|
7891
|
+
e.preventDefault();
|
|
7892
|
+
if (!open) openList();
|
|
7893
|
+
else setActive((a) => nextEnabledIndex(items, a, -1));
|
|
7894
|
+
return;
|
|
7895
|
+
case "Home":
|
|
7896
|
+
if (open) {
|
|
7897
|
+
e.preventDefault();
|
|
7898
|
+
setActive(firstEnabledIndex(items));
|
|
7899
|
+
}
|
|
7900
|
+
return;
|
|
7901
|
+
case "End":
|
|
7902
|
+
if (open) {
|
|
7903
|
+
e.preventDefault();
|
|
7904
|
+
setActive(lastEnabledIndex(items));
|
|
7905
|
+
}
|
|
7906
|
+
return;
|
|
7907
|
+
case "Enter":
|
|
7908
|
+
if (open) {
|
|
7909
|
+
e.preventDefault();
|
|
7910
|
+
commit(active);
|
|
7911
|
+
}
|
|
7912
|
+
return;
|
|
7913
|
+
case " ":
|
|
7914
|
+
e.preventDefault();
|
|
7915
|
+
if (!open) openList();
|
|
7916
|
+
else commit(active);
|
|
7917
|
+
return;
|
|
7918
|
+
case "Escape":
|
|
7919
|
+
if (open) {
|
|
7920
|
+
e.preventDefault();
|
|
7921
|
+
e.stopPropagation();
|
|
7922
|
+
close();
|
|
7923
|
+
}
|
|
7924
|
+
return;
|
|
7925
|
+
case "Tab":
|
|
7926
|
+
if (open) close(false);
|
|
7927
|
+
return;
|
|
7928
|
+
default:
|
|
7929
|
+
if (e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
7930
|
+
e.preventDefault();
|
|
7931
|
+
runTypeahead(e.key);
|
|
7932
|
+
}
|
|
7933
|
+
}
|
|
7934
|
+
};
|
|
7935
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "relative", children: [
|
|
7936
|
+
/* @__PURE__ */ jsxs(
|
|
7937
|
+
"button",
|
|
7938
|
+
{
|
|
7939
|
+
ref: triggerRef,
|
|
7940
|
+
type: "button",
|
|
7941
|
+
role: "combobox",
|
|
7942
|
+
"aria-haspopup": "listbox",
|
|
7943
|
+
"aria-expanded": open,
|
|
7944
|
+
"aria-controls": open ? listboxId : void 0,
|
|
7945
|
+
"aria-activedescendant": open && active >= 0 ? optionId(active) : void 0,
|
|
7946
|
+
onClick: () => open ? close() : openList(),
|
|
7947
|
+
onKeyDown,
|
|
7948
|
+
className: `flex items-center gap-1.5 border rounded-lg px-2.5 py-1.5 text-sm transition-colors ${value ? "border-blue-400 bg-blue-50 text-blue-700" : "border-gray-300 text-gray-600 hover:border-gray-400"}`,
|
|
7949
|
+
children: [
|
|
7950
|
+
/* @__PURE__ */ jsx("span", { className: "truncate max-w-[140px]", children: selectedLabel || filter.label }),
|
|
7951
|
+
value ? /* @__PURE__ */ jsx("button", { type: "button", onClick: (e) => {
|
|
7952
|
+
e.stopPropagation();
|
|
7953
|
+
onChange("");
|
|
7954
|
+
}, className: "text-blue-400 hover:text-blue-600", children: /* @__PURE__ */ jsx(XMarkIcon, { className: "h-3.5 w-3.5" }) }) : /* @__PURE__ */ jsx("svg", { className: `h-3.5 w-3.5 text-gray-400 transition-transform ${open ? "rotate-180" : ""}`, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M19.5 8.25l-7.5 7.5-7.5-7.5" }) })
|
|
7955
|
+
]
|
|
7956
|
+
}
|
|
7957
|
+
),
|
|
7958
|
+
open && /* @__PURE__ */ jsx("div", { ref: listRef, id: listboxId, role: "listbox", className: "absolute top-full left-0 mt-1 w-56 rounded-2xl z-[400] max-h-52 overflow-y-auto py-1", style: glassStyle(), children: items.map((o, i) => /* @__PURE__ */ jsx(
|
|
7959
|
+
"div",
|
|
7960
|
+
{
|
|
7961
|
+
id: optionId(i),
|
|
7962
|
+
role: "option",
|
|
7963
|
+
"aria-selected": i === selectedIndex,
|
|
7964
|
+
onPointerEnter: () => setActive(i),
|
|
7965
|
+
onClick: () => commit(i),
|
|
7966
|
+
className: `mx-1 cursor-pointer truncate rounded-lg px-3 py-1.5 text-sm
|
|
7967
|
+
${i === active ? "bg-blue-50 text-blue-700" : i === selectedIndex ? "font-medium text-blue-600" : "text-gray-700"}`,
|
|
7968
|
+
children: o.label
|
|
7969
|
+
},
|
|
7970
|
+
o.value || "__all__"
|
|
7971
|
+
)) })
|
|
7972
|
+
] });
|
|
7973
|
+
}
|
|
7514
7974
|
function SearchableFilter({ filter, value, onChange }) {
|
|
7515
7975
|
const [open, setOpen] = useState(false);
|
|
7516
7976
|
const [search, setSearch] = useState("");
|
|
@@ -7601,10 +8061,84 @@ function useFilters() {
|
|
|
7601
8061
|
}
|
|
7602
8062
|
return { filterValues, setFilter, clearFilters, filterParams };
|
|
7603
8063
|
}
|
|
8064
|
+
|
|
8065
|
+
// src/shell/severity.ts
|
|
8066
|
+
var SEVERITY_TONES = ["success", "warning", "danger"];
|
|
8067
|
+
function isSeverityTone(value) {
|
|
8068
|
+
return typeof value === "string" && SEVERITY_TONES.includes(value);
|
|
8069
|
+
}
|
|
8070
|
+
function severityOf(value, warn, crit) {
|
|
8071
|
+
if (value == null || !Number.isFinite(value)) return null;
|
|
8072
|
+
const warnAt = boundOf(warn);
|
|
8073
|
+
const critAt = boundOf(crit);
|
|
8074
|
+
if (warnAt == null && critAt == null) return null;
|
|
8075
|
+
if (critAt != null && value >= critAt) return "danger";
|
|
8076
|
+
if (warnAt != null && value >= warnAt) return "warning";
|
|
8077
|
+
return "success";
|
|
8078
|
+
}
|
|
8079
|
+
function boundOf(value) {
|
|
8080
|
+
return value != null && Number.isFinite(value) ? value : null;
|
|
8081
|
+
}
|
|
8082
|
+
var SEVERITY_FILL = {
|
|
8083
|
+
success: "bg-green-500",
|
|
8084
|
+
warning: "bg-amber-500",
|
|
8085
|
+
danger: "bg-red-500"
|
|
8086
|
+
};
|
|
8087
|
+
var SEVERITY_INK = {
|
|
8088
|
+
success: "text-gray-900",
|
|
8089
|
+
warning: "text-amber-600",
|
|
8090
|
+
danger: "text-red-600"
|
|
8091
|
+
};
|
|
8092
|
+
var SEVERITY_WORD = {
|
|
8093
|
+
success: "ok",
|
|
8094
|
+
warning: "warning",
|
|
8095
|
+
danger: "critical"
|
|
8096
|
+
};
|
|
8097
|
+
var SEVERITY_UNKNOWN_FILL = "bg-gray-300 border border-red-500";
|
|
8098
|
+
var SEVERITY_UNKNOWN_INK = "text-gray-900";
|
|
8099
|
+
var TONE_STYLES = {
|
|
8100
|
+
success: { tone: "success", fill: SEVERITY_FILL.success, ink: SEVERITY_INK.success, word: SEVERITY_WORD.success },
|
|
8101
|
+
warning: { tone: "warning", fill: SEVERITY_FILL.warning, ink: SEVERITY_INK.warning, word: SEVERITY_WORD.warning },
|
|
8102
|
+
danger: { tone: "danger", fill: SEVERITY_FILL.danger, ink: SEVERITY_INK.danger, word: SEVERITY_WORD.danger }
|
|
8103
|
+
};
|
|
8104
|
+
function styleForTone(tone) {
|
|
8105
|
+
return tone == null ? null : TONE_STYLES[tone];
|
|
8106
|
+
}
|
|
8107
|
+
function describeToken(value) {
|
|
8108
|
+
const raw = typeof value === "string" ? JSON.stringify(value) : typeof value === "number" || typeof value === "boolean" || typeof value === "bigint" ? String(value) : Object.prototype.toString.call(value);
|
|
8109
|
+
return raw.length > 32 ? `${raw.slice(0, 31)}\u2026` : raw;
|
|
8110
|
+
}
|
|
8111
|
+
var reported = /* @__PURE__ */ new Set();
|
|
8112
|
+
function reportUnknownSeverity(component, described) {
|
|
8113
|
+
const key = `${component}:${described}`;
|
|
8114
|
+
if (reported.has(key)) return;
|
|
8115
|
+
reported.add(key);
|
|
8116
|
+
console.error(
|
|
8117
|
+
`[react-os-shell] ${component}: severity ${described} is not one of ${SEVERITY_TONES.join(" | ")}. Rendering an "unknown severity" marker \u2014 a health marker must never silently disappear. If this came from a backend rollup, map it to the shell's vocabulary at the fetch boundary (see isSeverityTone).`
|
|
8118
|
+
);
|
|
8119
|
+
}
|
|
8120
|
+
function resolveSeverity(severity, component) {
|
|
8121
|
+
if (severity == null) return null;
|
|
8122
|
+
if (isSeverityTone(severity)) return TONE_STYLES[severity];
|
|
8123
|
+
const described = describeToken(severity);
|
|
8124
|
+
reportUnknownSeverity(component, described);
|
|
8125
|
+
return {
|
|
8126
|
+
tone: null,
|
|
8127
|
+
fill: SEVERITY_UNKNOWN_FILL,
|
|
8128
|
+
ink: SEVERITY_UNKNOWN_INK,
|
|
8129
|
+
word: `unrecognised severity ${described}`
|
|
8130
|
+
};
|
|
8131
|
+
}
|
|
8132
|
+
function warnOnce(key, message) {
|
|
8133
|
+
if (reported.has(key)) return;
|
|
8134
|
+
reported.add(key);
|
|
8135
|
+
console.error(message);
|
|
8136
|
+
}
|
|
7604
8137
|
function SidebarGroupLabel({ children }) {
|
|
7605
8138
|
return /* @__PURE__ */ jsx("p", { className: "px-2.5 pb-1 pt-1 text-[11px] font-semibold uppercase tracking-wide text-gray-400", children });
|
|
7606
8139
|
}
|
|
7607
|
-
function SidebarNavItem({ label, count, active, onClick }) {
|
|
8140
|
+
function SidebarNavItem({ label, count, active, onClick, severity }) {
|
|
8141
|
+
const marker = resolveSeverity(severity, "SidebarNavItem");
|
|
7608
8142
|
return /* @__PURE__ */ jsxs(
|
|
7609
8143
|
"button",
|
|
7610
8144
|
{
|
|
@@ -7612,12 +8146,118 @@ function SidebarNavItem({ label, count, active, onClick }) {
|
|
|
7612
8146
|
onClick,
|
|
7613
8147
|
className: `flex w-full items-center justify-between gap-2 rounded-lg px-2.5 py-1.5 text-sm text-left ${active ? "bg-blue-50 font-medium text-blue-700" : "text-gray-700 hover:bg-gray-100"}`,
|
|
7614
8148
|
children: [
|
|
7615
|
-
|
|
8149
|
+
marker && // Decorative in the a11y tree — the word itself follows the label, so
|
|
8150
|
+
// the item reads "Warehouses, warning, 12" in that order instead of
|
|
8151
|
+
// leading with a tone before anyone knows what it belongs to.
|
|
8152
|
+
/* @__PURE__ */ jsx(
|
|
8153
|
+
"span",
|
|
8154
|
+
{
|
|
8155
|
+
"aria-hidden": "true",
|
|
8156
|
+
title: marker.word,
|
|
8157
|
+
className: `shrink-0 h-1.5 w-1.5 rounded-full ${marker.fill}`
|
|
8158
|
+
}
|
|
8159
|
+
),
|
|
8160
|
+
/* @__PURE__ */ jsx("span", { className: marker ? "truncate mr-auto" : "truncate", children: label }),
|
|
8161
|
+
marker && /* @__PURE__ */ jsx("span", { className: "sr-only", children: marker.word }),
|
|
7616
8162
|
count != null && count > 0 && /* @__PURE__ */ jsx("span", { className: `shrink-0 inline-flex items-center justify-center min-w-[1.25rem] px-1.5 h-5 rounded-full text-[11px] font-medium ${active ? "bg-blue-100 text-blue-700" : "bg-gray-100 text-gray-600"}`, children: count })
|
|
7617
8163
|
]
|
|
7618
8164
|
}
|
|
7619
8165
|
);
|
|
7620
8166
|
}
|
|
8167
|
+
function Tick({ at, title, className }) {
|
|
8168
|
+
return /* @__PURE__ */ jsx(
|
|
8169
|
+
"div",
|
|
8170
|
+
{
|
|
8171
|
+
title,
|
|
8172
|
+
className: `absolute -top-[3px] h-3 w-0.5 rounded-[1px] ${className}`,
|
|
8173
|
+
style: { left: `${at}%` }
|
|
8174
|
+
}
|
|
8175
|
+
);
|
|
8176
|
+
}
|
|
8177
|
+
var clampPct = (n) => Math.min(100, Math.max(0, n));
|
|
8178
|
+
function MetricBar({
|
|
8179
|
+
label,
|
|
8180
|
+
value,
|
|
8181
|
+
max = 100,
|
|
8182
|
+
warn,
|
|
8183
|
+
crit,
|
|
8184
|
+
severity,
|
|
8185
|
+
detail,
|
|
8186
|
+
formatValue,
|
|
8187
|
+
emptyLabel = "no data",
|
|
8188
|
+
size = "sm",
|
|
8189
|
+
ariaLabel,
|
|
8190
|
+
className = ""
|
|
8191
|
+
}) {
|
|
8192
|
+
const reading = value != null && Number.isFinite(value) ? value : null;
|
|
8193
|
+
const scale = Number.isFinite(max) && max > 0 ? max : null;
|
|
8194
|
+
if (scale == null) {
|
|
8195
|
+
warnOnce(
|
|
8196
|
+
`MetricBar:max:${String(max)}`,
|
|
8197
|
+
`[react-os-shell] MetricBar: max=${String(max)} is not a positive finite number, so there is no scale to draw a proportional bar against. Printing the value without a bar. Pass the real capacity, or leave the reading out entirely (value={null}) when it is unknown \u2014 do not pass 0.`
|
|
8198
|
+
);
|
|
8199
|
+
}
|
|
8200
|
+
const supplied = resolveSeverity(severity, "MetricBar");
|
|
8201
|
+
const paint = reading != null ? supplied ?? styleForTone(severityOf(reading, warn, crit)) : null;
|
|
8202
|
+
const warnAt = boundOf(warn);
|
|
8203
|
+
const critAt = boundOf(crit);
|
|
8204
|
+
const width = reading != null && scale != null ? clampPct(reading / scale * 100) : 0;
|
|
8205
|
+
const format = formatValue ?? ((v) => scale === 100 ? `${v.toFixed(1)}%` : String(v));
|
|
8206
|
+
const printed = reading != null ? format(reading) : "\u2014";
|
|
8207
|
+
const showTicks = reading != null && scale != null && (warnAt != null || critAt != null);
|
|
8208
|
+
const meterLabel = ariaLabel ?? (typeof label === "string" ? label : void 0);
|
|
8209
|
+
const barHeight = size === "md" ? "h-2" : "h-1.5";
|
|
8210
|
+
const isMeter = reading != null && scale != null;
|
|
8211
|
+
const bar = /* @__PURE__ */ jsxs(
|
|
8212
|
+
"div",
|
|
8213
|
+
{
|
|
8214
|
+
...isMeter ? {
|
|
8215
|
+
role: "meter",
|
|
8216
|
+
"aria-label": meterLabel,
|
|
8217
|
+
"aria-valuemin": 0,
|
|
8218
|
+
"aria-valuemax": scale,
|
|
8219
|
+
// Kept inside the declared range: the bar clamps, and a valuenow
|
|
8220
|
+
// past its own valuemax is an invalid widget. `aria-valuetext`
|
|
8221
|
+
// still carries the unclamped truth, and takes precedence in the
|
|
8222
|
+
// announcement.
|
|
8223
|
+
"aria-valuenow": Math.min(scale, Math.max(0, reading)),
|
|
8224
|
+
"aria-valuetext": printed
|
|
8225
|
+
} : { "aria-hidden": true },
|
|
8226
|
+
className: isMeter && paint ? `relative mt-2 ${barHeight} rounded-full bg-gray-200` : `relative mt-2 ${barHeight} rounded-full border border-dashed border-gray-300 bg-transparent`,
|
|
8227
|
+
children: [
|
|
8228
|
+
isMeter && // Grey when unjudged: the magnitude is real, the verdict is not ours.
|
|
8229
|
+
/* @__PURE__ */ jsx(
|
|
8230
|
+
"div",
|
|
8231
|
+
{
|
|
8232
|
+
className: `absolute inset-y-0 left-0 rounded-full ${paint ? paint.fill : "bg-gray-400"}`,
|
|
8233
|
+
style: { width: `${width}%` }
|
|
8234
|
+
}
|
|
8235
|
+
),
|
|
8236
|
+
showTicks && scale != null && warnAt != null && /* @__PURE__ */ jsx(Tick, { at: clampPct(warnAt / scale * 100), title: `warning \u2265 ${warnAt}`, className: "bg-gray-400 opacity-75" }),
|
|
8237
|
+
showTicks && scale != null && critAt != null && /* @__PURE__ */ jsx(Tick, { at: clampPct(critAt / scale * 100), title: `critical \u2265 ${critAt}`, className: "bg-gray-500" })
|
|
8238
|
+
]
|
|
8239
|
+
}
|
|
8240
|
+
);
|
|
8241
|
+
const valueInk = paint ? paint.ink : reading != null ? "text-gray-900" : "text-gray-400";
|
|
8242
|
+
if (size === "md") {
|
|
8243
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
8244
|
+
label != null && /* @__PURE__ */ jsx("div", { className: "text-[10px] font-medium uppercase tracking-wide text-gray-500", children: label }),
|
|
8245
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-baseline gap-2", children: [
|
|
8246
|
+
/* @__PURE__ */ jsx("span", { className: `text-2xl font-semibold leading-[30px] tabular-nums ${valueInk}`, children: printed }),
|
|
8247
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 truncate text-[11px] tabular-nums text-gray-400", children: reading != null ? detail : emptyLabel })
|
|
8248
|
+
] }),
|
|
8249
|
+
bar
|
|
8250
|
+
] });
|
|
8251
|
+
}
|
|
8252
|
+
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
8253
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-2", children: [
|
|
8254
|
+
label != null && /* @__PURE__ */ jsx("span", { className: "w-14 shrink-0 truncate text-[10px] font-medium uppercase tracking-wide text-gray-500", children: label }),
|
|
8255
|
+
/* @__PURE__ */ jsx("span", { className: `text-sm font-semibold tabular-nums ${valueInk}`, children: printed }),
|
|
8256
|
+
/* @__PURE__ */ jsx("span", { className: "ml-auto min-w-0 truncate text-[10px] tabular-nums text-gray-400", children: reading != null ? detail : emptyLabel })
|
|
8257
|
+
] }),
|
|
8258
|
+
bar
|
|
8259
|
+
] });
|
|
8260
|
+
}
|
|
7621
8261
|
|
|
7622
8262
|
// src/utils/mergeBulkItems.ts
|
|
7623
8263
|
function findDuplicateKeys(rows, keyRowKey) {
|
|
@@ -9700,6 +10340,6 @@ function useEditHotkey(callback) {
|
|
|
9700
10340
|
}, [callback, isActive]);
|
|
9701
10341
|
}
|
|
9702
10342
|
|
|
9703
|
-
export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, BehaviorPanel, BulkImportGrid, Button_default as Button, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, Card, ChangePasswordForm, ChatTemplate, Checkbox_default as Checkbox, CheckoutTemplate, ColoredBadge, ContainerFillChart, Customization, DEV_BANNER_TEXT, DashboardTemplate, DataTablePage, Desktop, DesktopHostProvider, DevIndicator, DonutChart, ENTER, EmailTemplate, EmptyState, EntityList, ErrorPage, FilterBar, FormField, FormLayoutPage, GalleryTemplate, GlobalSearch, HelpCenter, INPUT_BASE, Input_default as Input, Kanban, Label, Layout, ListFooter, LoadingSpinner2 as LoadingSpinner, MOD, Markdown, MediaUploadField, MediaUploadGrid, MilestoneTimeline, NotificationBell, PageHeader, Pagination, PdfActionButton, Radio_default as Radio, ResizableTable, SHIFT, SearchableSelect, Select_default as Select, ServerStatusIndicator, ShellEntityFetcherProvider, ShortcutHelp, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, SoundsPanel, Sparkline, StartMenu, StatCard, StatusBadge, StatusBadgeProvider, SystemPreferences, Tabs, Textarea_default as Textarea, Tooltip, TopNav, WidgetManager, applyDevTitle, createWindowRegistry, findDuplicateKeys, formatDate, inputClasses, isDevEnv, isMac, mediaFileName, mergeBulkItems, useClickOutside, useColumnConfig, useDesktopHost, useEditHotkey, useFilters, useInfiniteScroll, useNewHotkey, useShellEntityFetcher, useSort, useTableNav };
|
|
10343
|
+
export { ALT, ALT_SHIFT_D, ALT_SHIFT_E, ALT_SHIFT_N, Accordion, AuthScreen, Avatar, AvatarGroup, Banner, BarChart, BehaviorPanel, BulkImportGrid, Button_default as Button, CMD_A, CMD_DOT, CMD_ENTER, CMD_K, CMD_S, Card, ChangePasswordForm, ChatTemplate, Checkbox_default as Checkbox, CheckoutTemplate, ColoredBadge, ContainerFillChart, Customization, DEV_BANNER_TEXT, DashboardTemplate, DataTablePage, Desktop, DesktopHostProvider, DevIndicator, DonutChart, ENTER, EmailTemplate, EmptyState, EntityList, ErrorPage, FilterBar, FormField, FormLayoutPage, GalleryTemplate, GlobalSearch, HelpCenter, INPUT_BASE, Input_default as Input, Kanban, Label, Layout, ListFooter, ListLoadError, LoadingSpinner2 as LoadingSpinner, MOD, Markdown, MediaUploadField, MediaUploadGrid, MetricBar, MilestoneTimeline, NativeSelect, NotificationBell, PageHeader, Pagination, PdfActionButton, Radio_default as Radio, ResizableTable, SHIFT, SearchableSelect, Select_default as Select, ServerStatusIndicator, ShellEntityFetcherProvider, ShortcutHelp, SidebarActionButton, SidebarGroupLabel, SidebarNavItem, SoundsPanel, Sparkline, StartMenu, StatCard, StatusBadge, StatusBadgeProvider, SystemPreferences, Tabs, Textarea_default as Textarea, Tooltip, TopNav, WidgetManager, applyDevTitle, createWindowRegistry, findDuplicateKeys, formatDate, inputClasses, isDevEnv, isMac, isSeverityTone, mediaFileName, mergeBulkItems, severityOf, useClickOutside, useColumnConfig, useDesktopHost, useEditHotkey, useFilters, useInfiniteScroll, useNewHotkey, useShellEntityFetcher, useSort, useTableNav };
|
|
9704
10344
|
//# sourceMappingURL=index.js.map
|
|
9705
10345
|
//# sourceMappingURL=index.js.map
|