react-os-shell 3.26.0 → 3.28.3
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/{Browser-OYJVFNED.js → Browser-OE4RRSNX.js} +5 -5
- package/dist/{Browser-OYJVFNED.js.map → Browser-OE4RRSNX.js.map} +1 -1
- package/dist/{Calculator-DMOIIGKO.js → Calculator-BJGIBI4Y.js} +4 -4
- package/dist/{Calculator-DMOIIGKO.js.map → Calculator-BJGIBI4Y.js.map} +1 -1
- package/dist/ConfirmDialog-LPE2X6OJ.js +4 -0
- package/dist/{ConfirmDialog-3RUHJG5R.js.map → ConfirmDialog-LPE2X6OJ.js.map} +1 -1
- package/dist/{CurrencyConverter-ROSY6A3Q.js → CurrencyConverter-CHTBKF6J.js} +4 -4
- package/dist/{CurrencyConverter-ROSY6A3Q.js.map → CurrencyConverter-CHTBKF6J.js.map} +1 -1
- package/dist/{Documents-VLKG4D22.js → Documents-D6Q75QR7.js} +5 -5
- package/dist/{Documents-VLKG4D22.js.map → Documents-D6Q75QR7.js.map} +1 -1
- package/dist/{Files-WRMJX4QG.js → Files-ROREKNZQ.js} +5 -5
- package/dist/{Files-WRMJX4QG.js.map → Files-ROREKNZQ.js.map} +1 -1
- package/dist/{Notepad-JVB7OIPO.js → Notepad-5P66KO2D.js} +5 -5
- package/dist/{Notepad-JVB7OIPO.js.map → Notepad-5P66KO2D.js.map} +1 -1
- package/dist/{PomodoroTimer-RVNX4CYS.js → PomodoroTimer-NLIPU5UR.js} +5 -5
- package/dist/{PomodoroTimer-RVNX4CYS.js.map → PomodoroTimer-NLIPU5UR.js.map} +1 -1
- package/dist/{Preview-DUADZWDA.js → Preview-7F27UNJW.js} +5 -5
- package/dist/{Preview-DUADZWDA.js.map → Preview-7F27UNJW.js.map} +1 -1
- package/dist/{Spreadsheet-EIWL7RIF.js → Spreadsheet-NKJBGBWK.js} +5 -5
- package/dist/{Spreadsheet-EIWL7RIF.js.map → Spreadsheet-NKJBGBWK.js.map} +1 -1
- package/dist/{Stock-7BIHXBPQ.js → Stock-Q5TKAAYK.js} +4 -4
- package/dist/{Stock-7BIHXBPQ.js.map → Stock-Q5TKAAYK.js.map} +1 -1
- package/dist/{Weather-7KUHPWTZ.js → Weather-ZZBMC3TS.js} +4 -4
- package/dist/{Weather-7KUHPWTZ.js.map → Weather-ZZBMC3TS.js.map} +1 -1
- package/dist/{WorldClock-I24ASGUI.js → WorldClock-ILLIOFRX.js} +4 -4
- package/dist/{WorldClock-I24ASGUI.js.map → WorldClock-ILLIOFRX.js.map} +1 -1
- package/dist/apps/index.js +15 -15
- package/dist/{chunk-E6ZOCXEA.js → chunk-6LMWM4ZE.js} +86 -24
- package/dist/chunk-6LMWM4ZE.js.map +1 -0
- package/dist/{chunk-NQ2QVUVX.js → chunk-7GNI7HRH.js} +3 -3
- package/dist/{chunk-NQ2QVUVX.js.map → chunk-7GNI7HRH.js.map} +1 -1
- package/dist/{chunk-MU7UZXAS.js → chunk-AKPD4Z34.js} +3 -3
- package/dist/{chunk-MU7UZXAS.js.map → chunk-AKPD4Z34.js.map} +1 -1
- package/dist/chunk-KFJA5CYZ.js +7 -0
- package/dist/{chunk-4BOGLRCL.js.map → chunk-KFJA5CYZ.js.map} +1 -1
- package/dist/{chunk-FPDVIPLM.js → chunk-WCV2646Z.js} +4 -4
- package/dist/{chunk-FPDVIPLM.js.map → chunk-WCV2646Z.js.map} +1 -1
- package/dist/index.d.ts +47 -4
- package/dist/index.js +537 -72
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/ConfirmDialog-3RUHJG5R.js +0 -4
- package/dist/chunk-4BOGLRCL.js +0 -7
- package/dist/chunk-E6ZOCXEA.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-AKPD4Z34.js';
|
|
2
|
+
export { setShellTodoProvider } from './chunk-AKPD4Z34.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,13 +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, 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-
|
|
18
|
+
import { APP_VERSION, VERSION } from './chunk-KFJA5CYZ.js';
|
|
19
|
+
export { VERSION } from './chunk-KFJA5CYZ.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-6LMWM4ZE.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-6LMWM4ZE.js';
|
|
22
22
|
import { glassStyle, startMenuCategories, navSections, isSection, GLASS_INPUT_BG, navIcons, sectionIcons } from './chunk-GW3RA6IS.js';
|
|
23
23
|
export { GLASS_DIVIDER, GLASS_INPUT_BG, glassStyle, setShellNavIcons } from './chunk-GW3RA6IS.js';
|
|
24
|
-
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';
|
|
25
25
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
26
26
|
import { Dialog, DialogBackdrop, DialogPanel } from '@headlessui/react';
|
|
27
27
|
import { createPortal } from 'react-dom';
|
|
@@ -951,6 +951,10 @@ function timeAgo(dateStr) {
|
|
|
951
951
|
if (days < 7) return `${days}d ago`;
|
|
952
952
|
return formatDate(dateStr);
|
|
953
953
|
}
|
|
954
|
+
function readingTimeMs(notif) {
|
|
955
|
+
const chars = (notif.title?.length ?? 0) + (notif.message?.length ?? 0);
|
|
956
|
+
return Math.min(12e3, Math.max(5e3, Math.round(chars / 15) * 1e3));
|
|
957
|
+
}
|
|
954
958
|
function NotificationBell({
|
|
955
959
|
useUnreadCount,
|
|
956
960
|
list,
|
|
@@ -992,7 +996,7 @@ function NotificationBell({
|
|
|
992
996
|
}
|
|
993
997
|
setInlineNotif(null);
|
|
994
998
|
}, []);
|
|
995
|
-
const showInlineNotif = useCallback((notif, durationMs =
|
|
999
|
+
const showInlineNotif = useCallback((notif, durationMs = readingTimeMs(notif)) => {
|
|
996
1000
|
setInlineNotif(notif);
|
|
997
1001
|
playNotification();
|
|
998
1002
|
if (inlineTimerRef.current) clearTimeout(inlineTimerRef.current);
|
|
@@ -1134,10 +1138,10 @@ function NotificationBell({
|
|
|
1134
1138
|
style: { animation: "notif-in 300ms cubic-bezier(0.4,0,0.2,1)" },
|
|
1135
1139
|
children: [
|
|
1136
1140
|
/* @__PURE__ */ jsx("div", { className: "h-9 w-9 shrink-0 rounded-lg bg-blue-500/15 flex items-center justify-center", children: /* @__PURE__ */ jsx("svg", { className: "h-5 w-5 text-blue-500", fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", strokeWidth: 2, children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0" }) }) }),
|
|
1137
|
-
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
|
|
1141
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 max-h-[60vh] overflow-y-auto", children: [
|
|
1138
1142
|
/* @__PURE__ */ jsx("div", { className: "text-[11px] font-semibold uppercase tracking-wide text-blue-600 mb-0.5", children: "Notification" }),
|
|
1139
|
-
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-800 leading-snug
|
|
1140
|
-
inlineNotif.message && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 leading-snug
|
|
1143
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-medium text-gray-800 leading-snug break-words", children: inlineNotif.title }),
|
|
1144
|
+
inlineNotif.message && /* @__PURE__ */ jsx("div", { className: "text-xs text-gray-500 leading-snug break-words mt-0.5", children: inlineNotif.message })
|
|
1141
1145
|
] }),
|
|
1142
1146
|
/* @__PURE__ */ jsx(
|
|
1143
1147
|
"button",
|
|
@@ -4370,7 +4374,7 @@ function Layout({
|
|
|
4370
4374
|
const { prefs, save: savePrefs } = useShellPrefs();
|
|
4371
4375
|
const layoutMode = prefs.layout_mode === "sidebar" ? "sidebar" : "classic";
|
|
4372
4376
|
const sidebarMode = layoutMode === "sidebar";
|
|
4373
|
-
const sidebarWidth = sidebarMode ?
|
|
4377
|
+
const sidebarWidth = sidebarMode ? SIDEBAR_STRIP_W : 0;
|
|
4374
4378
|
const taskbarPositionRaw = prefs.taskbar_position || "bottom";
|
|
4375
4379
|
const taskbarPosition = sidebarMode ? "bottom" : taskbarPositionRaw;
|
|
4376
4380
|
const taskbarSize = prefs.taskbar_size || "medium";
|
|
@@ -5081,7 +5085,7 @@ function Customization({ omit, section } = {}) {
|
|
|
5081
5085
|
inSection("layout") && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5082
5086
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
5083
5087
|
/* @__PURE__ */ jsx("h3", { className: "text-sm font-semibold text-gray-900 mb-3", children: "Layout Mode" }),
|
|
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)." }),
|
|
5088
|
+
/* @__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." }),
|
|
5085
5089
|
/* @__PURE__ */ jsx("div", { className: "flex gap-2", children: [
|
|
5086
5090
|
{ key: "classic", label: "Classic" },
|
|
5087
5091
|
{ key: "sidebar", label: "Sidebar" }
|
|
@@ -5090,7 +5094,11 @@ function Customization({ omit, section } = {}) {
|
|
|
5090
5094
|
{
|
|
5091
5095
|
onClick: () => {
|
|
5092
5096
|
savePref("layout_mode", m.key);
|
|
5093
|
-
if (m.key === "
|
|
5097
|
+
if (m.key === "classic") {
|
|
5098
|
+
if (prefs.default_window_size === "maximized") savePref("default_window_size", "large");
|
|
5099
|
+
forgetMaximizedWindowBoxes();
|
|
5100
|
+
window.dispatchEvent(new CustomEvent("react-os-shell:restore-windowed"));
|
|
5101
|
+
}
|
|
5094
5102
|
},
|
|
5095
5103
|
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"}`,
|
|
5096
5104
|
children: m.label
|
|
@@ -5978,12 +5986,76 @@ function ListFooter({
|
|
|
5978
5986
|
isFetchingMore ? " \xB7 Loading more..." : ""
|
|
5979
5987
|
] });
|
|
5980
5988
|
}
|
|
5989
|
+
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";
|
|
5990
|
+
var VARIANTS2 = {
|
|
5991
|
+
primary: "bg-blue-600 text-white shadow-sm hover:bg-blue-700 focus:ring-blue-400/40",
|
|
5992
|
+
secondary: "border border-gray-300 bg-white text-gray-700 shadow-sm hover:bg-gray-50 focus:ring-blue-400/30",
|
|
5993
|
+
ghost: "text-gray-700 hover:bg-gray-100 focus:ring-blue-400/30",
|
|
5994
|
+
danger: "bg-red-600 text-white shadow-sm hover:bg-red-700 focus:ring-red-400/40"
|
|
5995
|
+
};
|
|
5996
|
+
var SIZES = {
|
|
5997
|
+
sm: "gap-1 px-2.5 py-1 text-xs",
|
|
5998
|
+
md: "gap-1.5 px-3 py-1.5 text-sm"
|
|
5999
|
+
};
|
|
6000
|
+
function Spinner() {
|
|
6001
|
+
return /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
6002
|
+
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
6003
|
+
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
6004
|
+
] });
|
|
6005
|
+
}
|
|
6006
|
+
var Button = forwardRef(function Button2({
|
|
6007
|
+
variant = "primary",
|
|
6008
|
+
size = "md",
|
|
6009
|
+
loading = false,
|
|
6010
|
+
leftIcon,
|
|
6011
|
+
rightIcon,
|
|
6012
|
+
block = false,
|
|
6013
|
+
disabled,
|
|
6014
|
+
type = "button",
|
|
6015
|
+
children,
|
|
6016
|
+
className = "",
|
|
6017
|
+
...rest
|
|
6018
|
+
}, ref) {
|
|
6019
|
+
return /* @__PURE__ */ jsxs(
|
|
6020
|
+
"button",
|
|
6021
|
+
{
|
|
6022
|
+
ref,
|
|
6023
|
+
type,
|
|
6024
|
+
disabled: disabled || loading,
|
|
6025
|
+
"aria-busy": loading || void 0,
|
|
6026
|
+
className: [BASE, VARIANTS2[variant], SIZES[size], block ? "w-full" : "", className].filter(Boolean).join(" "),
|
|
6027
|
+
...rest,
|
|
6028
|
+
children: [
|
|
6029
|
+
loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
|
|
6030
|
+
children,
|
|
6031
|
+
!loading && rightIcon
|
|
6032
|
+
]
|
|
6033
|
+
}
|
|
6034
|
+
);
|
|
6035
|
+
});
|
|
6036
|
+
var Button_default = Button;
|
|
6037
|
+
function ListLoadError({
|
|
6038
|
+
title = "Couldn't load this list",
|
|
6039
|
+
message = "Something went wrong fetching these records. Check your connection and try again.",
|
|
6040
|
+
onRetry,
|
|
6041
|
+
variant = "dashed"
|
|
6042
|
+
}) {
|
|
6043
|
+
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";
|
|
6044
|
+
return /* @__PURE__ */ jsxs("div", { className: `flex flex-col items-center justify-center text-center ${frame}`, role: "alert", children: [
|
|
6045
|
+
/* @__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" }) }),
|
|
6046
|
+
/* @__PURE__ */ jsx("h3", { className: "text-sm font-medium text-gray-900", children: title }),
|
|
6047
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-gray-500 mt-2", children: message }),
|
|
6048
|
+
onRetry && /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(Button_default, { variant: "secondary", size: "sm", onClick: onRetry, children: "Try again" }) })
|
|
6049
|
+
] });
|
|
6050
|
+
}
|
|
5981
6051
|
function EntityList(props) {
|
|
5982
6052
|
const {
|
|
5983
6053
|
items,
|
|
5984
6054
|
isLoading,
|
|
5985
6055
|
emptyState,
|
|
5986
6056
|
totalCount,
|
|
6057
|
+
isError,
|
|
6058
|
+
onRetry,
|
|
5987
6059
|
tableId,
|
|
5988
6060
|
columns,
|
|
5989
6061
|
renderCell,
|
|
@@ -6069,6 +6141,7 @@ function EntityList(props) {
|
|
|
6069
6141
|
}
|
|
6070
6142
|
};
|
|
6071
6143
|
if (isLoading) return /* @__PURE__ */ jsx(LoadingSpinner, {});
|
|
6144
|
+
if (isError && items.length === 0) return /* @__PURE__ */ jsx(ListLoadError, { onRetry });
|
|
6072
6145
|
if (items.length === 0) return /* @__PURE__ */ jsx(Fragment, { children: emptyState });
|
|
6073
6146
|
const allSelected = items.length > 0 && selected.size === items.length;
|
|
6074
6147
|
const fullColumns = [
|
|
@@ -6426,6 +6499,10 @@ function useInfiniteScroll({
|
|
|
6426
6499
|
items: allItems,
|
|
6427
6500
|
totalCount,
|
|
6428
6501
|
isLoading: query.isLoading,
|
|
6502
|
+
// Surface the query's error state so a failed fetch renders as an error
|
|
6503
|
+
// (with retry) rather than a misleading empty list. `refetch` is the retry.
|
|
6504
|
+
isError: query.isError,
|
|
6505
|
+
error: query.error,
|
|
6429
6506
|
isFetchingNextPage,
|
|
6430
6507
|
hasNextPage: !!hasNextPage,
|
|
6431
6508
|
sentinelRef,
|
|
@@ -6542,54 +6619,6 @@ function Pagination({
|
|
|
6542
6619
|
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" })
|
|
6543
6620
|
] });
|
|
6544
6621
|
}
|
|
6545
|
-
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";
|
|
6546
|
-
var VARIANTS2 = {
|
|
6547
|
-
primary: "bg-blue-600 text-white shadow-sm hover:bg-blue-700 focus:ring-blue-400/40",
|
|
6548
|
-
secondary: "border border-gray-300 bg-white text-gray-700 shadow-sm hover:bg-gray-50 focus:ring-blue-400/30",
|
|
6549
|
-
ghost: "text-gray-700 hover:bg-gray-100 focus:ring-blue-400/30",
|
|
6550
|
-
danger: "bg-red-600 text-white shadow-sm hover:bg-red-700 focus:ring-red-400/40"
|
|
6551
|
-
};
|
|
6552
|
-
var SIZES = {
|
|
6553
|
-
sm: "gap-1 px-2.5 py-1 text-xs",
|
|
6554
|
-
md: "gap-1.5 px-3 py-1.5 text-sm"
|
|
6555
|
-
};
|
|
6556
|
-
function Spinner() {
|
|
6557
|
-
return /* @__PURE__ */ jsxs("svg", { className: "h-3.5 w-3.5 animate-spin", viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
6558
|
-
/* @__PURE__ */ jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }),
|
|
6559
|
-
/* @__PURE__ */ jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
6560
|
-
] });
|
|
6561
|
-
}
|
|
6562
|
-
var Button = forwardRef(function Button2({
|
|
6563
|
-
variant = "primary",
|
|
6564
|
-
size = "md",
|
|
6565
|
-
loading = false,
|
|
6566
|
-
leftIcon,
|
|
6567
|
-
rightIcon,
|
|
6568
|
-
block = false,
|
|
6569
|
-
disabled,
|
|
6570
|
-
type = "button",
|
|
6571
|
-
children,
|
|
6572
|
-
className = "",
|
|
6573
|
-
...rest
|
|
6574
|
-
}, ref) {
|
|
6575
|
-
return /* @__PURE__ */ jsxs(
|
|
6576
|
-
"button",
|
|
6577
|
-
{
|
|
6578
|
-
ref,
|
|
6579
|
-
type,
|
|
6580
|
-
disabled: disabled || loading,
|
|
6581
|
-
"aria-busy": loading || void 0,
|
|
6582
|
-
className: [BASE, VARIANTS2[variant], SIZES[size], block ? "w-full" : "", className].filter(Boolean).join(" "),
|
|
6583
|
-
...rest,
|
|
6584
|
-
children: [
|
|
6585
|
-
loading ? /* @__PURE__ */ jsx(Spinner, {}) : leftIcon,
|
|
6586
|
-
children,
|
|
6587
|
-
!loading && rightIcon
|
|
6588
|
-
]
|
|
6589
|
-
}
|
|
6590
|
-
);
|
|
6591
|
-
});
|
|
6592
|
-
var Button_default = Button;
|
|
6593
6622
|
var Input = forwardRef(function Input2({ invalid, leftIcon, rightAdornment, className = "", ...rest }, ref) {
|
|
6594
6623
|
const pad = `${leftIcon ? "pl-9" : ""} ${rightAdornment ? "pr-9" : ""}`.trim();
|
|
6595
6624
|
const field = /* @__PURE__ */ jsx(
|
|
@@ -6629,7 +6658,44 @@ var Textarea = forwardRef(function Textarea2({ invalid, autoGrow, className = ""
|
|
|
6629
6658
|
);
|
|
6630
6659
|
});
|
|
6631
6660
|
var Textarea_default = Textarea;
|
|
6632
|
-
|
|
6661
|
+
|
|
6662
|
+
// src/forms/selectNav.ts
|
|
6663
|
+
function firstEnabledIndex(options) {
|
|
6664
|
+
for (let i = 0; i < options.length; i++) {
|
|
6665
|
+
if (!options[i].disabled) return i;
|
|
6666
|
+
}
|
|
6667
|
+
return -1;
|
|
6668
|
+
}
|
|
6669
|
+
function lastEnabledIndex(options) {
|
|
6670
|
+
for (let i = options.length - 1; i >= 0; i--) {
|
|
6671
|
+
if (!options[i].disabled) return i;
|
|
6672
|
+
}
|
|
6673
|
+
return -1;
|
|
6674
|
+
}
|
|
6675
|
+
function nextEnabledIndex(options, from, dir) {
|
|
6676
|
+
let i = from + dir;
|
|
6677
|
+
while (i >= 0 && i < options.length) {
|
|
6678
|
+
if (!options[i].disabled) return i;
|
|
6679
|
+
i += dir;
|
|
6680
|
+
}
|
|
6681
|
+
if (from >= 0 && from < options.length && !options[from].disabled) return from;
|
|
6682
|
+
return dir > 0 ? firstEnabledIndex(options) : lastEnabledIndex(options);
|
|
6683
|
+
}
|
|
6684
|
+
function matchTypeahead(options, buffer, fromIndex) {
|
|
6685
|
+
const q = buffer.toLowerCase();
|
|
6686
|
+
const n = options.length;
|
|
6687
|
+
if (!q || n === 0) return -1;
|
|
6688
|
+
for (let step = 1; step <= n; step++) {
|
|
6689
|
+
const i = ((fromIndex + step) % n + n) % n;
|
|
6690
|
+
const o = options[i];
|
|
6691
|
+
if (!o.disabled && o.label.toLowerCase().startsWith(q)) return i;
|
|
6692
|
+
}
|
|
6693
|
+
return -1;
|
|
6694
|
+
}
|
|
6695
|
+
var MENU_GAP2 = 4;
|
|
6696
|
+
var VIEWPORT_MARGIN2 = 8;
|
|
6697
|
+
var MENU_MAX_HEIGHT2 = 240;
|
|
6698
|
+
var NativeSelect = forwardRef(function NativeSelect2({ value, onChange, options, placeholder, invalid, className = "", ...rest }, ref) {
|
|
6633
6699
|
return /* @__PURE__ */ jsxs(
|
|
6634
6700
|
"select",
|
|
6635
6701
|
{
|
|
@@ -6645,6 +6711,260 @@ var Select = forwardRef(function Select2({ value, onChange, options, placeholder
|
|
|
6645
6711
|
}
|
|
6646
6712
|
);
|
|
6647
6713
|
});
|
|
6714
|
+
function useAnchoredPosition(triggerRef, open) {
|
|
6715
|
+
const [pos, setPos] = useState(null);
|
|
6716
|
+
useLayoutEffect(() => {
|
|
6717
|
+
if (!open) {
|
|
6718
|
+
setPos(null);
|
|
6719
|
+
return;
|
|
6720
|
+
}
|
|
6721
|
+
let lastLeft = NaN, lastTop = NaN, lastBottom = NaN;
|
|
6722
|
+
const compute = () => {
|
|
6723
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
6724
|
+
if (!rect) return;
|
|
6725
|
+
lastLeft = rect.left;
|
|
6726
|
+
lastTop = rect.top;
|
|
6727
|
+
lastBottom = rect.bottom;
|
|
6728
|
+
const spaceBelow = window.innerHeight - rect.bottom - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
6729
|
+
const spaceAbove = rect.top - MENU_GAP2 - VIEWPORT_MARGIN2;
|
|
6730
|
+
const placeAbove = spaceBelow < Math.min(MENU_MAX_HEIGHT2, 160) && spaceAbove > spaceBelow;
|
|
6731
|
+
const maxHeight = Math.max(96, Math.min(MENU_MAX_HEIGHT2, placeAbove ? spaceAbove : spaceBelow));
|
|
6732
|
+
const left = Math.max(VIEWPORT_MARGIN2, Math.min(rect.left, window.innerWidth - rect.width - VIEWPORT_MARGIN2));
|
|
6733
|
+
const next = { left, minWidth: rect.width, maxHeight };
|
|
6734
|
+
if (placeAbove) next.bottom = window.innerHeight - rect.top + MENU_GAP2;
|
|
6735
|
+
else next.top = rect.bottom + MENU_GAP2;
|
|
6736
|
+
setPos(next);
|
|
6737
|
+
};
|
|
6738
|
+
compute();
|
|
6739
|
+
let raf = requestAnimationFrame(function tick() {
|
|
6740
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
6741
|
+
if (rect && (rect.left !== lastLeft || rect.top !== lastTop || rect.bottom !== lastBottom)) compute();
|
|
6742
|
+
raf = requestAnimationFrame(tick);
|
|
6743
|
+
});
|
|
6744
|
+
window.addEventListener("scroll", compute, true);
|
|
6745
|
+
window.addEventListener("resize", compute);
|
|
6746
|
+
return () => {
|
|
6747
|
+
cancelAnimationFrame(raf);
|
|
6748
|
+
window.removeEventListener("scroll", compute, true);
|
|
6749
|
+
window.removeEventListener("resize", compute);
|
|
6750
|
+
};
|
|
6751
|
+
}, [open, triggerRef]);
|
|
6752
|
+
return pos;
|
|
6753
|
+
}
|
|
6754
|
+
var ListboxSelect = forwardRef(function ListboxSelect2({ value, onChange, options, placeholder, invalid, className = "", id, disabled, ...rest }, ref) {
|
|
6755
|
+
const [open, setOpen] = useState(false);
|
|
6756
|
+
const [active, setActive] = useState(-1);
|
|
6757
|
+
const wrapRef = useRef(null);
|
|
6758
|
+
const triggerRef = useRef(null);
|
|
6759
|
+
const listRef = useRef(null);
|
|
6760
|
+
const openRef = useRef(open);
|
|
6761
|
+
openRef.current = open;
|
|
6762
|
+
const typeahead = useRef({ buffer: "", timer: null });
|
|
6763
|
+
const baseId = useId();
|
|
6764
|
+
const listboxId = `${baseId}-listbox`;
|
|
6765
|
+
const optionId = (i) => `${baseId}-opt-${i}`;
|
|
6766
|
+
const menuPos = useAnchoredPosition(triggerRef, open);
|
|
6767
|
+
const selectedIndex = options.findIndex((o) => o.value === value);
|
|
6768
|
+
const selectedLabel = selectedIndex >= 0 ? options[selectedIndex].label : void 0;
|
|
6769
|
+
const close = useCallback((refocus = true) => {
|
|
6770
|
+
setOpen(false);
|
|
6771
|
+
setActive(-1);
|
|
6772
|
+
if (refocus) triggerRef.current?.focus();
|
|
6773
|
+
}, []);
|
|
6774
|
+
const openList = useCallback(() => {
|
|
6775
|
+
if (disabled) return;
|
|
6776
|
+
setActive(selectedIndex >= 0 ? selectedIndex : firstEnabledIndex(options));
|
|
6777
|
+
setOpen(true);
|
|
6778
|
+
}, [disabled, options, selectedIndex]);
|
|
6779
|
+
const commit = useCallback((i) => {
|
|
6780
|
+
const o = options[i];
|
|
6781
|
+
if (!o || o.disabled) return;
|
|
6782
|
+
onChange(o.value);
|
|
6783
|
+
close();
|
|
6784
|
+
}, [options, onChange, close]);
|
|
6785
|
+
useEffect(() => {
|
|
6786
|
+
if (!open) return;
|
|
6787
|
+
const unregister = registerModalEscapeInterceptor((e) => {
|
|
6788
|
+
if (e.key !== "Escape" || !openRef.current) return false;
|
|
6789
|
+
close();
|
|
6790
|
+
return true;
|
|
6791
|
+
});
|
|
6792
|
+
return unregister;
|
|
6793
|
+
}, [open, close]);
|
|
6794
|
+
useEffect(() => {
|
|
6795
|
+
if (!open) return;
|
|
6796
|
+
const handler = (e) => {
|
|
6797
|
+
const t = e.target;
|
|
6798
|
+
if (wrapRef.current?.contains(t) || listRef.current?.contains(t)) return;
|
|
6799
|
+
close(false);
|
|
6800
|
+
};
|
|
6801
|
+
document.addEventListener("pointerdown", handler);
|
|
6802
|
+
return () => document.removeEventListener("pointerdown", handler);
|
|
6803
|
+
}, [open, close]);
|
|
6804
|
+
useEffect(() => {
|
|
6805
|
+
if (!open || active < 0) return;
|
|
6806
|
+
listRef.current?.querySelector(`#${CSS.escape(optionId(active))}`)?.scrollIntoView({ block: "nearest" });
|
|
6807
|
+
});
|
|
6808
|
+
const runTypeahead = useCallback((char) => {
|
|
6809
|
+
const ta = typeahead.current;
|
|
6810
|
+
if (ta.timer) clearTimeout(ta.timer);
|
|
6811
|
+
ta.buffer += char;
|
|
6812
|
+
ta.timer = setTimeout(() => {
|
|
6813
|
+
ta.buffer = "";
|
|
6814
|
+
ta.timer = null;
|
|
6815
|
+
}, 500);
|
|
6816
|
+
const from = open ? active : selectedIndex;
|
|
6817
|
+
const hit = matchTypeahead(options, ta.buffer, from);
|
|
6818
|
+
if (hit < 0) return;
|
|
6819
|
+
if (open) setActive(hit);
|
|
6820
|
+
else commit(hit);
|
|
6821
|
+
}, [open, active, selectedIndex, options, commit]);
|
|
6822
|
+
const onKeyDown = (e) => {
|
|
6823
|
+
if (disabled) return;
|
|
6824
|
+
switch (e.key) {
|
|
6825
|
+
case "ArrowDown":
|
|
6826
|
+
e.preventDefault();
|
|
6827
|
+
if (!open) openList();
|
|
6828
|
+
else setActive((a) => nextEnabledIndex(options, a, 1));
|
|
6829
|
+
return;
|
|
6830
|
+
case "ArrowUp":
|
|
6831
|
+
e.preventDefault();
|
|
6832
|
+
if (!open) openList();
|
|
6833
|
+
else setActive((a) => nextEnabledIndex(options, a, -1));
|
|
6834
|
+
return;
|
|
6835
|
+
case "Home":
|
|
6836
|
+
if (open) {
|
|
6837
|
+
e.preventDefault();
|
|
6838
|
+
setActive(firstEnabledIndex(options));
|
|
6839
|
+
}
|
|
6840
|
+
return;
|
|
6841
|
+
case "End":
|
|
6842
|
+
if (open) {
|
|
6843
|
+
e.preventDefault();
|
|
6844
|
+
setActive(lastEnabledIndex(options));
|
|
6845
|
+
}
|
|
6846
|
+
return;
|
|
6847
|
+
case "Enter":
|
|
6848
|
+
if (open) {
|
|
6849
|
+
e.preventDefault();
|
|
6850
|
+
commit(active);
|
|
6851
|
+
}
|
|
6852
|
+
return;
|
|
6853
|
+
case " ":
|
|
6854
|
+
e.preventDefault();
|
|
6855
|
+
if (!open) openList();
|
|
6856
|
+
else commit(active);
|
|
6857
|
+
return;
|
|
6858
|
+
case "Escape":
|
|
6859
|
+
if (open) {
|
|
6860
|
+
e.preventDefault();
|
|
6861
|
+
e.stopPropagation();
|
|
6862
|
+
close();
|
|
6863
|
+
}
|
|
6864
|
+
return;
|
|
6865
|
+
case "Tab":
|
|
6866
|
+
if (open) close(false);
|
|
6867
|
+
return;
|
|
6868
|
+
default:
|
|
6869
|
+
if (e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
6870
|
+
e.preventDefault();
|
|
6871
|
+
runTypeahead(e.key);
|
|
6872
|
+
}
|
|
6873
|
+
}
|
|
6874
|
+
};
|
|
6875
|
+
return /* @__PURE__ */ jsxs("div", { ref: wrapRef, className: "relative", children: [
|
|
6876
|
+
/* @__PURE__ */ jsx(
|
|
6877
|
+
"button",
|
|
6878
|
+
{
|
|
6879
|
+
ref: triggerRef,
|
|
6880
|
+
id,
|
|
6881
|
+
type: "button",
|
|
6882
|
+
role: "combobox",
|
|
6883
|
+
"aria-haspopup": "listbox",
|
|
6884
|
+
"aria-expanded": open,
|
|
6885
|
+
"aria-controls": open ? listboxId : void 0,
|
|
6886
|
+
"aria-activedescendant": open && active >= 0 ? optionId(active) : void 0,
|
|
6887
|
+
"aria-invalid": invalid || void 0,
|
|
6888
|
+
disabled,
|
|
6889
|
+
onClick: () => open ? close() : openList(),
|
|
6890
|
+
onKeyDown,
|
|
6891
|
+
className: inputClasses({ invalid, className: `pr-8 text-left ${className}`.trim() }),
|
|
6892
|
+
children: /* @__PURE__ */ jsx("span", { className: `block truncate ${selectedLabel === void 0 ? "text-gray-400" : ""}`, children: selectedLabel ?? placeholder ?? "\xA0" })
|
|
6893
|
+
}
|
|
6894
|
+
),
|
|
6895
|
+
/* @__PURE__ */ jsx(
|
|
6896
|
+
"svg",
|
|
6897
|
+
{
|
|
6898
|
+
"aria-hidden": "true",
|
|
6899
|
+
className: "pointer-events-none absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400",
|
|
6900
|
+
fill: "none",
|
|
6901
|
+
viewBox: "0 0 24 24",
|
|
6902
|
+
stroke: "currentColor",
|
|
6903
|
+
strokeWidth: 2,
|
|
6904
|
+
children: /* @__PURE__ */ jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M8.25 9l3.75-3.75L15.75 9M8.25 15l3.75 3.75L15.75 15" })
|
|
6905
|
+
}
|
|
6906
|
+
),
|
|
6907
|
+
/* @__PURE__ */ jsxs(
|
|
6908
|
+
"select",
|
|
6909
|
+
{
|
|
6910
|
+
ref,
|
|
6911
|
+
value,
|
|
6912
|
+
onChange: (e) => onChange(e.target.value),
|
|
6913
|
+
disabled,
|
|
6914
|
+
"aria-hidden": "true",
|
|
6915
|
+
tabIndex: -1,
|
|
6916
|
+
className: "sr-only",
|
|
6917
|
+
...rest,
|
|
6918
|
+
children: [
|
|
6919
|
+
placeholder !== void 0 && /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: placeholder }),
|
|
6920
|
+
options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, disabled: o.disabled, children: o.label }, o.value))
|
|
6921
|
+
]
|
|
6922
|
+
}
|
|
6923
|
+
),
|
|
6924
|
+
open && createPortal(
|
|
6925
|
+
/* @__PURE__ */ jsx(
|
|
6926
|
+
"div",
|
|
6927
|
+
{
|
|
6928
|
+
ref: listRef,
|
|
6929
|
+
id: listboxId,
|
|
6930
|
+
role: "listbox",
|
|
6931
|
+
className: "fixed z-[400] overflow-y-auto rounded-2xl py-1",
|
|
6932
|
+
style: {
|
|
6933
|
+
left: menuPos?.left,
|
|
6934
|
+
top: menuPos?.top,
|
|
6935
|
+
bottom: menuPos?.bottom,
|
|
6936
|
+
minWidth: menuPos?.minWidth,
|
|
6937
|
+
maxHeight: menuPos?.maxHeight ?? MENU_MAX_HEIGHT2,
|
|
6938
|
+
visibility: menuPos ? void 0 : "hidden",
|
|
6939
|
+
...glassStyle()
|
|
6940
|
+
},
|
|
6941
|
+
children: options.map((o, i) => /* @__PURE__ */ jsx(
|
|
6942
|
+
"div",
|
|
6943
|
+
{
|
|
6944
|
+
id: optionId(i),
|
|
6945
|
+
role: "option",
|
|
6946
|
+
"aria-selected": value === o.value,
|
|
6947
|
+
"aria-disabled": o.disabled || void 0,
|
|
6948
|
+
onPointerEnter: () => {
|
|
6949
|
+
if (!o.disabled) setActive(i);
|
|
6950
|
+
},
|
|
6951
|
+
onClick: () => commit(i),
|
|
6952
|
+
className: `mx-1 cursor-pointer truncate rounded-lg px-3 py-1.5 text-sm
|
|
6953
|
+
${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"}`,
|
|
6954
|
+
children: o.label
|
|
6955
|
+
},
|
|
6956
|
+
o.value
|
|
6957
|
+
))
|
|
6958
|
+
}
|
|
6959
|
+
),
|
|
6960
|
+
document.body
|
|
6961
|
+
)
|
|
6962
|
+
] });
|
|
6963
|
+
});
|
|
6964
|
+
var Select = forwardRef(function Select2(props, ref) {
|
|
6965
|
+
const isMobile = useIsMobile();
|
|
6966
|
+
return isMobile ? /* @__PURE__ */ jsx(NativeSelect, { ref, ...props }) : /* @__PURE__ */ jsx(ListboxSelect, { ref, ...props });
|
|
6967
|
+
});
|
|
6648
6968
|
var Select_default = Select;
|
|
6649
6969
|
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";
|
|
6650
6970
|
var Checkbox = forwardRef(function Checkbox2({ checked, onChange, label, description, disabled, className = "", ...rest }, ref) {
|
|
@@ -7489,16 +7809,12 @@ function FilterBar({ filters, values, onChange, onClear, children }) {
|
|
|
7489
7809
|
onChange: (v) => onChange(f.field, v)
|
|
7490
7810
|
},
|
|
7491
7811
|
f.field
|
|
7492
|
-
) : /* @__PURE__ */
|
|
7493
|
-
|
|
7812
|
+
) : /* @__PURE__ */ jsx(
|
|
7813
|
+
PlainFilter,
|
|
7494
7814
|
{
|
|
7815
|
+
filter: f,
|
|
7495
7816
|
value: values[f.field] || "",
|
|
7496
|
-
onChange: (
|
|
7497
|
-
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"}`,
|
|
7498
|
-
children: [
|
|
7499
|
-
/* @__PURE__ */ jsx("option", { value: "", children: f.label }),
|
|
7500
|
-
f.options.map((o) => /* @__PURE__ */ jsx("option", { value: o.value, children: o.label }, o.value))
|
|
7501
|
-
]
|
|
7817
|
+
onChange: (v) => onChange(f.field, v)
|
|
7502
7818
|
},
|
|
7503
7819
|
f.field
|
|
7504
7820
|
);
|
|
@@ -7510,6 +7826,155 @@ function FilterBar({ filters, values, onChange, onClear, children }) {
|
|
|
7510
7826
|
] })
|
|
7511
7827
|
] });
|
|
7512
7828
|
}
|
|
7829
|
+
function PlainFilter({ filter, value, onChange }) {
|
|
7830
|
+
const [open, setOpen] = useState(false);
|
|
7831
|
+
const [active, setActive] = useState(-1);
|
|
7832
|
+
const ref = useRef(null);
|
|
7833
|
+
const triggerRef = useRef(null);
|
|
7834
|
+
const listRef = useRef(null);
|
|
7835
|
+
const openRef = useRef(open);
|
|
7836
|
+
openRef.current = open;
|
|
7837
|
+
const typeahead = useRef({ buffer: "", timer: null });
|
|
7838
|
+
const baseId = useId();
|
|
7839
|
+
const listboxId = `${baseId}-listbox`;
|
|
7840
|
+
const optionId = (i) => `${baseId}-opt-${i}`;
|
|
7841
|
+
const items = [{ value: "", label: filter.label }, ...filter.options];
|
|
7842
|
+
const selectedIndex = value ? items.findIndex((o) => o.value === value) : 0;
|
|
7843
|
+
const selectedLabel = value ? filter.options.find((o) => o.value === value)?.label : null;
|
|
7844
|
+
const close = useCallback((refocus = true) => {
|
|
7845
|
+
setOpen(false);
|
|
7846
|
+
setActive(-1);
|
|
7847
|
+
if (refocus) triggerRef.current?.focus();
|
|
7848
|
+
}, []);
|
|
7849
|
+
const openList = useCallback(() => {
|
|
7850
|
+
setActive(selectedIndex >= 0 ? selectedIndex : firstEnabledIndex(items));
|
|
7851
|
+
setOpen(true);
|
|
7852
|
+
}, [selectedIndex, items]);
|
|
7853
|
+
const commit = useCallback((i) => {
|
|
7854
|
+
const o = items[i];
|
|
7855
|
+
if (!o) return;
|
|
7856
|
+
onChange(o.value);
|
|
7857
|
+
close();
|
|
7858
|
+
}, [items, onChange, close]);
|
|
7859
|
+
useClickOutside(ref, useCallback(() => {
|
|
7860
|
+
if (open) close(false);
|
|
7861
|
+
}, [open, close]));
|
|
7862
|
+
useEffect(() => {
|
|
7863
|
+
if (!open) return;
|
|
7864
|
+
return registerModalEscapeInterceptor((e) => {
|
|
7865
|
+
if (e.key !== "Escape" || !openRef.current) return false;
|
|
7866
|
+
close();
|
|
7867
|
+
return true;
|
|
7868
|
+
});
|
|
7869
|
+
}, [open, close]);
|
|
7870
|
+
useEffect(() => {
|
|
7871
|
+
if (!open || active < 0) return;
|
|
7872
|
+
listRef.current?.querySelector(`#${CSS.escape(optionId(active))}`)?.scrollIntoView({ block: "nearest" });
|
|
7873
|
+
});
|
|
7874
|
+
const runTypeahead = (char) => {
|
|
7875
|
+
const ta = typeahead.current;
|
|
7876
|
+
if (ta.timer) clearTimeout(ta.timer);
|
|
7877
|
+
ta.buffer += char;
|
|
7878
|
+
ta.timer = setTimeout(() => {
|
|
7879
|
+
ta.buffer = "";
|
|
7880
|
+
ta.timer = null;
|
|
7881
|
+
}, 500);
|
|
7882
|
+
const hit = matchTypeahead(items, ta.buffer, open ? active : selectedIndex);
|
|
7883
|
+
if (hit < 0) return;
|
|
7884
|
+
if (open) setActive(hit);
|
|
7885
|
+
else commit(hit);
|
|
7886
|
+
};
|
|
7887
|
+
const onKeyDown = (e) => {
|
|
7888
|
+
switch (e.key) {
|
|
7889
|
+
case "ArrowDown":
|
|
7890
|
+
e.preventDefault();
|
|
7891
|
+
if (!open) openList();
|
|
7892
|
+
else setActive((a) => nextEnabledIndex(items, a, 1));
|
|
7893
|
+
return;
|
|
7894
|
+
case "ArrowUp":
|
|
7895
|
+
e.preventDefault();
|
|
7896
|
+
if (!open) openList();
|
|
7897
|
+
else setActive((a) => nextEnabledIndex(items, a, -1));
|
|
7898
|
+
return;
|
|
7899
|
+
case "Home":
|
|
7900
|
+
if (open) {
|
|
7901
|
+
e.preventDefault();
|
|
7902
|
+
setActive(firstEnabledIndex(items));
|
|
7903
|
+
}
|
|
7904
|
+
return;
|
|
7905
|
+
case "End":
|
|
7906
|
+
if (open) {
|
|
7907
|
+
e.preventDefault();
|
|
7908
|
+
setActive(lastEnabledIndex(items));
|
|
7909
|
+
}
|
|
7910
|
+
return;
|
|
7911
|
+
case "Enter":
|
|
7912
|
+
if (open) {
|
|
7913
|
+
e.preventDefault();
|
|
7914
|
+
commit(active);
|
|
7915
|
+
}
|
|
7916
|
+
return;
|
|
7917
|
+
case " ":
|
|
7918
|
+
e.preventDefault();
|
|
7919
|
+
if (!open) openList();
|
|
7920
|
+
else commit(active);
|
|
7921
|
+
return;
|
|
7922
|
+
case "Escape":
|
|
7923
|
+
if (open) {
|
|
7924
|
+
e.preventDefault();
|
|
7925
|
+
e.stopPropagation();
|
|
7926
|
+
close();
|
|
7927
|
+
}
|
|
7928
|
+
return;
|
|
7929
|
+
case "Tab":
|
|
7930
|
+
if (open) close(false);
|
|
7931
|
+
return;
|
|
7932
|
+
default:
|
|
7933
|
+
if (e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
7934
|
+
e.preventDefault();
|
|
7935
|
+
runTypeahead(e.key);
|
|
7936
|
+
}
|
|
7937
|
+
}
|
|
7938
|
+
};
|
|
7939
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: "relative", children: [
|
|
7940
|
+
/* @__PURE__ */ jsxs(
|
|
7941
|
+
"button",
|
|
7942
|
+
{
|
|
7943
|
+
ref: triggerRef,
|
|
7944
|
+
type: "button",
|
|
7945
|
+
role: "combobox",
|
|
7946
|
+
"aria-haspopup": "listbox",
|
|
7947
|
+
"aria-expanded": open,
|
|
7948
|
+
"aria-controls": open ? listboxId : void 0,
|
|
7949
|
+
"aria-activedescendant": open && active >= 0 ? optionId(active) : void 0,
|
|
7950
|
+
onClick: () => open ? close() : openList(),
|
|
7951
|
+
onKeyDown,
|
|
7952
|
+
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"}`,
|
|
7953
|
+
children: [
|
|
7954
|
+
/* @__PURE__ */ jsx("span", { className: "truncate max-w-[140px]", children: selectedLabel || filter.label }),
|
|
7955
|
+
value ? /* @__PURE__ */ jsx("button", { type: "button", onClick: (e) => {
|
|
7956
|
+
e.stopPropagation();
|
|
7957
|
+
onChange("");
|
|
7958
|
+
}, 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" }) })
|
|
7959
|
+
]
|
|
7960
|
+
}
|
|
7961
|
+
),
|
|
7962
|
+
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(
|
|
7963
|
+
"div",
|
|
7964
|
+
{
|
|
7965
|
+
id: optionId(i),
|
|
7966
|
+
role: "option",
|
|
7967
|
+
"aria-selected": i === selectedIndex,
|
|
7968
|
+
onPointerEnter: () => setActive(i),
|
|
7969
|
+
onClick: () => commit(i),
|
|
7970
|
+
className: `mx-1 cursor-pointer truncate rounded-lg px-3 py-1.5 text-sm
|
|
7971
|
+
${i === active ? "bg-blue-50 text-blue-700" : i === selectedIndex ? "font-medium text-blue-600" : "text-gray-700"}`,
|
|
7972
|
+
children: o.label
|
|
7973
|
+
},
|
|
7974
|
+
o.value || "__all__"
|
|
7975
|
+
)) })
|
|
7976
|
+
] });
|
|
7977
|
+
}
|
|
7513
7978
|
function SearchableFilter({ filter, value, onChange }) {
|
|
7514
7979
|
const [open, setOpen] = useState(false);
|
|
7515
7980
|
const [search, setSearch] = useState("");
|
|
@@ -9879,6 +10344,6 @@ function useEditHotkey(callback) {
|
|
|
9879
10344
|
}, [callback, isActive]);
|
|
9880
10345
|
}
|
|
9881
10346
|
|
|
9882
|
-
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, MetricBar, 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, isSeverityTone, mediaFileName, mergeBulkItems, severityOf, useClickOutside, useColumnConfig, useDesktopHost, useEditHotkey, useFilters, useInfiniteScroll, useNewHotkey, useShellEntityFetcher, useSort, useTableNav };
|
|
10347
|
+
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 };
|
|
9883
10348
|
//# sourceMappingURL=index.js.map
|
|
9884
10349
|
//# sourceMappingURL=index.js.map
|