@yca-software/yca-react-core 0.0.21 → 0.0.23

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.
@@ -139,6 +139,8 @@ async function performAccessTokenRefresh(params) {
139
139
  throw { error: new Error("failed to refresh access token"), status: lastStatus };
140
140
  }
141
141
  var refreshInFlight = null;
142
+ var refreshCooldownUntilMs = 0;
143
+ var REFRESH_COOLDOWN_MS = 3e4;
142
144
  async function executeConfiguredRefresh(config) {
143
145
  const refresh = config.refresh;
144
146
  if (!refresh) {
@@ -147,8 +149,23 @@ async function executeConfiguredRefresh(config) {
147
149
  if (refreshInFlight) {
148
150
  return refreshInFlight;
149
151
  }
152
+ const now = Date.now();
153
+ if (refreshCooldownUntilMs > now) {
154
+ throw { error: new Error("refresh cooling down"), status: 429 };
155
+ }
150
156
  refresh.onStart?.();
151
- refreshInFlight = performAccessTokenRefresh({
157
+ const refreshAttempt = refresh.executor ? Promise.resolve().then(() => refresh.executor()).then(({ accessToken, expiresAt }) => {
158
+ if (!accessToken || !expiresAt || !Number.isFinite(Date.parse(expiresAt)) || Date.parse(expiresAt) <= Date.now()) {
159
+ throw { error: new Error("invalid native refresh response"), status: 0 };
160
+ }
161
+ refresh.setAccessToken(accessToken);
162
+ return accessToken;
163
+ }).catch((err) => {
164
+ if (typeof err?.status === "number" && isFatalRefreshFailureStatus(err.status) && shouldClearSessionOnRefreshFailure()) {
165
+ refresh.onFailure();
166
+ }
167
+ throw err;
168
+ }) : performAccessTokenRefresh({
152
169
  baseURL: config.baseURL,
153
170
  getRefreshToken: config.getRefreshToken,
154
171
  request: refresh.request,
@@ -156,6 +173,16 @@ async function executeConfiguredRefresh(config) {
156
173
  setAccessToken: refresh.setAccessToken,
157
174
  onFailure: refresh.onFailure,
158
175
  acceptLanguage: config.getAcceptLanguage?.()
176
+ });
177
+ refreshInFlight = refreshAttempt.then((token) => {
178
+ refreshCooldownUntilMs = 0;
179
+ return token;
180
+ }).catch((err) => {
181
+ const status = typeof err?.status === "number" ? err.status : 0;
182
+ if (isTransientRefreshStatus(status)) {
183
+ refreshCooldownUntilMs = Date.now() + REFRESH_COOLDOWN_MS;
184
+ }
185
+ throw err;
159
186
  }).finally(() => {
160
187
  refreshInFlight = null;
161
188
  refresh.onEnd?.();
@@ -168,7 +195,7 @@ function shouldRetryWithRefresh(status, endpoint, isRetry, refreshToken, refresh
168
195
  if (status !== 401 || !refresh || !endpoint || isRetry) {
169
196
  return false;
170
197
  }
171
- const canRefresh = !!refreshToken || refresh.cookieCredentialsEnabled();
198
+ const canRefresh = !!refresh.executor || !!refreshToken || refresh.cookieCredentialsEnabled();
172
199
  if (!canRefresh) {
173
200
  return false;
174
201
  }
@@ -258,6 +285,7 @@ function createApiProvider(useOptions) {
258
285
  endpoint: options.refreshEndpoint,
259
286
  excludedRetryPrefixes: options.refreshExcludedPrefixes
260
287
  }),
288
+ executor: options.refreshExecutor,
261
289
  cookieCredentialsEnabled: options.cookieCredentialsEnabled,
262
290
  setAccessToken: options.setAccessToken,
263
291
  onFailure: options.onRefreshFailure,
@@ -330,5 +358,5 @@ function useAccessTokenKeepAlive(options) {
330
358
  }
331
359
 
332
360
  export { ApiClientProvider, DEFAULT_REFRESH_ENDPOINT, DEFAULT_REFRESH_EXCLUDED_PREFIXES, accessTokenNeedsRefresh, buildRequestUrl, createApiProvider, createDefaultRefreshRequest, createResponseHandler, executeConfiguredRefresh, getRequestHeaders, getRequestOptions, isFatalRefreshFailureStatus, msUntilAccessRefresh, performAccessTokenRefresh, shouldClearSessionOnRefreshFailure, useAPI, useAccessTokenKeepAlive, useApiClientConfig };
333
- //# sourceMappingURL=chunk-NL5V3XXV.js.map
334
- //# sourceMappingURL=chunk-NL5V3XXV.js.map
361
+ //# sourceMappingURL=chunk-V6EYEN2F.js.map
362
+ //# sourceMappingURL=chunk-V6EYEN2F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/api/request.ts","../src/api/responseHandler.ts","../src/api/ApiClientContext.tsx","../src/api/createApiProvider.tsx","../src/api/useAccessTokenKeepAlive.ts"],"names":["useMemo","jsx"],"mappings":"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","file":"chunk-V6EYEN2F.js","sourcesContent":["import type {\n ApiClientConfig,\n RefreshBodyContext,\n RefreshRequestConfig,\n RequestConfig,\n} from './types';\n\nexport const DEFAULT_REFRESH_ENDPOINT = 'auth/refresh';\nexport const DEFAULT_REFRESH_EXCLUDED_PREFIXES = ['auth/'];\n\nexport interface DefaultRefreshRequestOptions {\n endpoint?: string;\n excludedRetryPrefixes?: string[];\n}\n\nexport function createDefaultRefreshRequest({\n endpoint = DEFAULT_REFRESH_ENDPOINT,\n excludedRetryPrefixes = DEFAULT_REFRESH_EXCLUDED_PREFIXES,\n}: DefaultRefreshRequestOptions = {}): RefreshRequestConfig {\n return {\n endpoint,\n method: 'POST',\n buildBody: ({ refreshToken }: RefreshBodyContext) => (refreshToken ? { refreshToken } : {}),\n parseAccessToken: (data: unknown) => {\n if (data && typeof data === 'object' && 'accessToken' in data) {\n const token = (data as { accessToken: unknown }).accessToken;\n return typeof token === 'string' ? token : null;\n }\n return null;\n },\n excludedRetryPrefixes,\n };\n}\n\nexport function buildRequestUrl(baseURL: string, endpoint: string): string {\n const base = baseURL.replace(/\\/$/, '');\n const path = endpoint.replace(/^\\//, '');\n return `${base}/${path}`;\n}\n\nexport function getRequestHeaders(\n accessToken: string | null,\n options?: { multipart?: boolean; acceptLanguage?: string },\n): HeadersInit {\n const headers: HeadersInit = {};\n if (!options?.multipart) {\n headers['Content-Type'] = 'application/json';\n }\n if (accessToken) {\n headers.Authorization = `Bearer ${accessToken}`;\n }\n if (options?.acceptLanguage) {\n headers['Accept-Language'] = options.acceptLanguage;\n }\n return headers;\n}\n\nexport function getRequestOptions(\n config: RequestConfig,\n token: string | null,\n acceptLanguage?: string,\n): RequestInit {\n const init: RequestInit = {\n method: config.method,\n headers: getRequestHeaders(token, {\n multipart: config.multipart,\n acceptLanguage,\n }),\n body: config.multipart\n ? (config.body as BodyInit)\n : config.body != null\n ? JSON.stringify(config.body)\n : undefined,\n };\n if (config.credentials) {\n init.credentials = config.credentials;\n }\n return init;\n}\n\n/** Auth errors where the refresh cookie/token is actually unusable. */\nexport function isFatalRefreshFailureStatus(status: number): boolean {\n return status === 400 || status === 401 || status === 403 || status === 404;\n}\n\n/** Background/frozen tabs must not clear the session — cookies may be omitted from the fetch. */\nexport function shouldClearSessionOnRefreshFailure(): boolean {\n return typeof document === 'undefined' || document.visibilityState !== 'hidden';\n}\n\nfunction isTransientRefreshStatus(status: number): boolean {\n return status === 0 || status === 429 || status === 502 || status === 503 || status === 504;\n}\n\nconst REFRESH_TRANSIENT_ATTEMPTS = 3;\nconst REFRESH_TRANSIENT_DELAY_MS = 50;\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nexport async function performAccessTokenRefresh(params: {\n baseURL: string;\n getRefreshToken: () => string | null;\n request: RefreshRequestConfig;\n useCookieCredentials: boolean;\n setAccessToken: (token: string) => void;\n onFailure: () => void;\n acceptLanguage?: string;\n}): Promise<string> {\n const refreshToken = params.useCookieCredentials ? null : params.getRefreshToken();\n if (!params.useCookieCredentials && !refreshToken) {\n // Missing JS token is not proof the session is dead (hydration may still\n // install an HttpOnly marker). Do not log the user out.\n throw { error: new Error('missing refresh token'), status: 401 };\n }\n\n const bodyContext: RefreshBodyContext = {\n refreshToken,\n useCookieCredentials: params.useCookieCredentials,\n };\n\n const requestConfig: RequestConfig = {\n endpoint: params.request.endpoint,\n method: params.request.method,\n body: params.request.buildBody(bodyContext),\n credentials: params.useCookieCredentials ? 'include' : params.request.credentials,\n };\n\n let lastStatus = 0;\n for (let attempt = 1; attempt <= REFRESH_TRANSIENT_ATTEMPTS; attempt += 1) {\n let response: Response;\n try {\n response = await fetch(\n buildRequestUrl(params.baseURL, requestConfig.endpoint),\n getRequestOptions(requestConfig, null, params.acceptLanguage),\n );\n } catch {\n lastStatus = 0;\n if (attempt < REFRESH_TRANSIENT_ATTEMPTS) {\n await wait(REFRESH_TRANSIENT_DELAY_MS * attempt);\n continue;\n }\n throw { error: new Error('refresh network error'), status: 0 };\n }\n\n const responseText = await response.text();\n\n let data: unknown = null;\n if (responseText) {\n try {\n data = JSON.parse(responseText);\n } catch {\n lastStatus = 0;\n if (attempt < REFRESH_TRANSIENT_ATTEMPTS) {\n await wait(REFRESH_TRANSIENT_DELAY_MS * attempt);\n continue;\n }\n throw { error: new Error('invalid refresh response'), status: 0 };\n }\n }\n\n const accessToken = params.request.parseAccessToken(data);\n if (response.ok && accessToken) {\n params.setAccessToken(accessToken);\n return accessToken;\n }\n\n lastStatus = response.status || 0;\n if (isTransientRefreshStatus(lastStatus) && attempt < REFRESH_TRANSIENT_ATTEMPTS) {\n await wait(REFRESH_TRANSIENT_DELAY_MS * attempt);\n continue;\n }\n\n if (isFatalRefreshFailureStatus(lastStatus) && shouldClearSessionOnRefreshFailure()) {\n params.onFailure();\n }\n throw {\n error: new Error('failed to refresh access token'),\n status: lastStatus,\n };\n }\n\n throw { error: new Error('failed to refresh access token'), status: lastStatus };\n}\n\n/** One in-flight refresh per page — parallel 401 retries share the same promise. */\nlet refreshInFlight: Promise<string> | null = null;\n/** After 429/5xx, pause new refresh attempts so the SPA cannot hammer the API. */\nlet refreshCooldownUntilMs = 0;\nconst REFRESH_COOLDOWN_MS = 30_000;\n\nexport async function executeConfiguredRefresh(config: ApiClientConfig): Promise<string> {\n const refresh = config.refresh;\n if (!refresh) {\n throw new Error('refresh is not configured');\n }\n\n if (refreshInFlight) {\n return refreshInFlight;\n }\n\n const now = Date.now();\n if (refreshCooldownUntilMs > now) {\n throw { error: new Error('refresh cooling down'), status: 429 };\n }\n\n refresh.onStart?.();\n const refreshAttempt = refresh.executor\n ? Promise.resolve()\n .then(() => refresh.executor!())\n .then(({ accessToken, expiresAt }) => {\n if (\n !accessToken ||\n !expiresAt ||\n !Number.isFinite(Date.parse(expiresAt)) ||\n Date.parse(expiresAt) <= Date.now()\n ) {\n throw { error: new Error('invalid native refresh response'), status: 0 };\n }\n refresh.setAccessToken(accessToken);\n return accessToken;\n })\n .catch((err: { status?: number }) => {\n if (\n typeof err?.status === 'number' &&\n isFatalRefreshFailureStatus(err.status) &&\n shouldClearSessionOnRefreshFailure()\n ) {\n refresh.onFailure();\n }\n throw err;\n })\n : performAccessTokenRefresh({\n baseURL: config.baseURL,\n getRefreshToken: config.getRefreshToken,\n request: refresh.request,\n useCookieCredentials: refresh.cookieCredentialsEnabled(),\n setAccessToken: refresh.setAccessToken,\n onFailure: refresh.onFailure,\n acceptLanguage: config.getAcceptLanguage?.(),\n });\n refreshInFlight = refreshAttempt\n .then((token) => {\n refreshCooldownUntilMs = 0;\n return token;\n })\n .catch((err: { status?: number }) => {\n const status = typeof err?.status === 'number' ? err.status : 0;\n if (isTransientRefreshStatus(status)) {\n refreshCooldownUntilMs = Date.now() + REFRESH_COOLDOWN_MS;\n }\n throw err;\n })\n .finally(() => {\n refreshInFlight = null;\n refresh.onEnd?.();\n });\n\n return refreshInFlight;\n}\n","import { buildRequestUrl, executeConfiguredRefresh, getRequestOptions } from './request';\nimport type { ApiClientConfig, ApiErrorBody, RequestConfig, RequestError } from './types';\n\nfunction shouldRetryWithRefresh(\n status: number,\n endpoint: string | undefined,\n isRetry: boolean | undefined,\n refreshToken: string | null | undefined,\n refresh: ApiClientConfig['refresh'],\n): boolean {\n if (status !== 401 || !refresh || !endpoint || isRetry) {\n return false;\n }\n const canRefresh = !!refresh.executor || !!refreshToken || refresh.cookieCredentialsEnabled();\n if (!canRefresh) {\n return false;\n }\n const normalized = endpoint.replace(/^\\//, '');\n return !refresh.request.excludedRetryPrefixes.some((prefix) =>\n normalized.startsWith(prefix.replace(/^\\//, '')),\n );\n}\n\nexport function createResponseHandler(config: ApiClientConfig) {\n const { baseURL, getRefreshToken, refresh } = config;\n\n async function handleResponse(\n response: Response,\n options?: { config?: RequestConfig; isRetry?: boolean },\n ): Promise<unknown> {\n const responseText = await response.text();\n let data: unknown;\n if (responseText) {\n try {\n data = JSON.parse(responseText);\n } catch {\n data = responseText;\n }\n }\n\n if (!response.ok) {\n const refreshToken = getRefreshToken();\n if (\n shouldRetryWithRefresh(\n response.status,\n options?.config?.endpoint,\n options?.isRetry,\n refreshToken,\n refresh,\n ) &&\n options?.config\n ) {\n const newToken = await executeConfiguredRefresh(config);\n const retryResponse = await fetch(\n buildRequestUrl(baseURL, options.config.endpoint),\n getRequestOptions(options.config, newToken, config.getAcceptLanguage?.()),\n );\n return handleResponse(retryResponse, { ...options, isRetry: true });\n }\n\n throw {\n error: data as ApiErrorBody,\n status: response.status,\n retry: response.status >= 500,\n } satisfies RequestError;\n }\n\n return data;\n }\n\n return handleResponse;\n}\n","import { createContext, type ReactNode, useCallback, useContext, useMemo } from 'react';\nimport { buildRequestUrl, getRequestOptions } from './request';\nimport { createResponseHandler } from './responseHandler';\nimport type { ApiClientConfig, ApiClientProviderConfig, FetchFn, RequestConfig } from './types';\n\nconst ApiClientContext = createContext<ApiClientConfig | null>(null);\n\nexport function ApiClientProvider({\n baseURL,\n config,\n children,\n}: {\n baseURL: string;\n config: ApiClientProviderConfig;\n children: ReactNode;\n}) {\n const value = useMemo<ApiClientConfig>(() => ({ ...config, baseURL }), [baseURL, config]);\n\n return <ApiClientContext.Provider value={value}>{children}</ApiClientContext.Provider>;\n}\n\nexport function useApiClientConfig(): ApiClientConfig {\n const ctx = useContext(ApiClientContext);\n if (!ctx) {\n throw new Error('useApiClientConfig must be used within ApiClientProvider');\n }\n return ctx;\n}\n\nexport function useAPI(): FetchFn {\n const config = useApiClientConfig();\n const responseHandler = useMemo(() => createResponseHandler(config), [config]);\n\n return useCallback(\n (requestConfig: RequestConfig) => {\n const accessToken = config.getAccessToken();\n return fetch(\n buildRequestUrl(config.baseURL, requestConfig.endpoint),\n getRequestOptions(requestConfig, accessToken, config.getAcceptLanguage?.()),\n ).then((response) => responseHandler(response, { config: requestConfig }));\n },\n [config, responseHandler],\n );\n}\n","import { type ReactNode, useMemo } from 'react';\n\nimport { ApiClientProvider } from './ApiClientContext';\nimport { createDefaultRefreshRequest } from './request';\nimport type { ApiClientProviderConfig } from './types';\n\nexport interface CreateApiProviderOptions {\n baseURL: string;\n getAccessToken: () => string | null;\n getRefreshToken: () => string | null;\n /** When true, refresh uses HttpOnly cookie credentials instead of body token. */\n cookieCredentialsEnabled: () => boolean;\n setAccessToken: (token: string) => void;\n onRefreshFailure: () => void;\n getAcceptLanguage?: () => string;\n onRefreshStart?: () => void;\n onRefreshEnd?: () => void;\n /** Optional native refresh boundary; browser apps retain the default HTTP cookie flow. */\n refreshExecutor?: () => Promise<{ accessToken: string; expiresAt: string }>;\n /** Refresh endpoint path relative to baseURL. Defaults to `auth/refresh`. */\n refreshEndpoint?: string;\n /** Paths that must not trigger automatic refresh retry on 401. Defaults to `['auth/']`. */\n refreshExcludedPrefixes?: string[];\n}\n\n/**\n * Factory for app `ApiProvider` components. Pass a hook that returns wiring options\n * (cookies, i18n, zustand). Memoize that return value with `useMemo` so the API\n * client context is not rebuilt on every parent render.\n */\nexport function createApiProvider(useOptions: () => CreateApiProviderOptions) {\n return function ApiProvider({ children }: { children: ReactNode }) {\n const options = useOptions();\n\n const apiConfig = useMemo<ApiClientProviderConfig>(\n () => ({\n getAccessToken: options.getAccessToken,\n getRefreshToken: options.getRefreshToken,\n getAcceptLanguage: options.getAcceptLanguage,\n refresh: {\n request: createDefaultRefreshRequest({\n endpoint: options.refreshEndpoint,\n excludedRetryPrefixes: options.refreshExcludedPrefixes,\n }),\n executor: options.refreshExecutor,\n cookieCredentialsEnabled: options.cookieCredentialsEnabled,\n setAccessToken: options.setAccessToken,\n onFailure: options.onRefreshFailure,\n onStart: options.onRefreshStart,\n onEnd: options.onRefreshEnd,\n },\n }),\n [options],\n );\n\n return (\n <ApiClientProvider baseURL={options.baseURL} config={apiConfig}>\n {children}\n </ApiClientProvider>\n );\n };\n}\n","import { jwtDecode } from 'jwt-decode';\nimport { useEffect } from 'react';\nimport { useApiClientConfig } from './ApiClientContext';\nimport { executeConfiguredRefresh } from './request';\n\n/** Typical access JWT TTL is 15m — refresh ahead of expiry. */\nconst REFRESH_SKEW_MS = 2 * 60 * 1000;\n/** Cap so we re-check often enough if the JWT has no exp. */\nconst KEEP_ALIVE_MAX_DELAY_MS = 4 * 60 * 1000;\n\nexport function accessTokenNeedsRefresh(\n token: string | null,\n nowMs: number = Date.now(),\n skewMs: number = REFRESH_SKEW_MS,\n): boolean {\n return msUntilAccessRefresh(token, nowMs, skewMs) === 0;\n}\n\n/** Milliseconds until the access JWT should be refreshed (0 = now). */\nexport function msUntilAccessRefresh(\n token: string | null,\n nowMs: number = Date.now(),\n skewMs: number = REFRESH_SKEW_MS,\n): number {\n if (!token) return 0;\n try {\n const { exp } = jwtDecode<{ exp?: number }>(token);\n if (typeof exp !== 'number') return 0;\n return Math.max(0, exp * 1000 - skewMs - nowMs);\n } catch {\n return 0;\n }\n}\n\nexport type UseAccessTokenKeepAliveOptions = {\n /** When false, no timers or listeners are registered. */\n enabled: boolean;\n /** Same accessor the API client uses (cookie and/or in-memory). */\n getAccessToken: () => string | null;\n};\n\n/**\n * Keeps the access token fresh while a session exists.\n * - Timeout scheduled from JWT exp (capped at 4 minutes)\n * - Also refreshes on visibility / focus / pageshow after expiry\n */\nexport function useAccessTokenKeepAlive(options: UseAccessTokenKeepAliveOptions): void {\n const apiConfig = useApiClientConfig();\n const { enabled, getAccessToken } = options;\n\n useEffect(() => {\n if (!enabled || !apiConfig.refresh) {\n return;\n }\n\n const refreshIfNeeded = () => {\n if (!accessTokenNeedsRefresh(getAccessToken())) {\n return;\n }\n void executeConfiguredRefresh(apiConfig).catch(() => {\n // Hard auth failures clear via onRefreshFailure only while the tab is visible.\n });\n };\n\n let timeoutId = 0;\n const schedule = () => {\n window.clearTimeout(timeoutId);\n const until = msUntilAccessRefresh(getAccessToken());\n const delay =\n until === 0 ? KEEP_ALIVE_MAX_DELAY_MS : Math.min(until, KEEP_ALIVE_MAX_DELAY_MS);\n timeoutId = window.setTimeout(() => {\n refreshIfNeeded();\n schedule();\n }, delay);\n };\n\n const onVisibility = () => {\n if (document.visibilityState === 'visible') {\n refreshIfNeeded();\n schedule();\n }\n };\n\n refreshIfNeeded();\n schedule();\n document.addEventListener('visibilitychange', onVisibility);\n window.addEventListener('focus', refreshIfNeeded);\n window.addEventListener('pageshow', refreshIfNeeded);\n\n return () => {\n document.removeEventListener('visibilitychange', onVisibility);\n window.removeEventListener('focus', refreshIfNeeded);\n window.removeEventListener('pageshow', refreshIfNeeded);\n window.clearTimeout(timeoutId);\n };\n }, [apiConfig, enabled, getAccessToken]);\n}\n"]}
@@ -1,8 +1,8 @@
1
- import { Table, TableHeader, TableRow, TableHead, Checkbox, TableBody, TableCell, Select, Alert, AlertDescription, DateRangePicker, Tooltip, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from './chunk-XCDKWHJJ.js';
1
+ import { SearchField, Table, TableHeader, TableRow, TableHead, Checkbox, TableBody, TableCell, Select, Alert, AlertDescription, DateRangePicker, Tooltip, DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from './chunk-QHNZTXPJ.js';
2
2
  import { Button, Card, CardHeader, CardTitle, CardDescription, Input, CardContent } from './chunk-3AYG73DK.js';
3
3
  import { dateRangePickerTranslations } from './chunk-UCJ76BEC.js';
4
4
  import { cn } from './chunk-GXWVFQCK.js';
5
- import { Loader2, ArrowLeft, X, Search, MoreVertical, Moon, Sun } from 'lucide-react';
5
+ import { Loader2, ArrowLeft, Search, MoreVertical, Moon, Sun } from 'lucide-react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
8
8
  import { Link } from 'react-router';
@@ -130,7 +130,6 @@ function AdminListPage({
130
130
  }) {
131
131
  const safeItems = items.filter((item) => item != null && typeof item === "object");
132
132
  const isSubmitMode = searchMode === "submit";
133
- const hasSearchText = search.trim().length > 0;
134
133
  const selectionEnabled = selectionMode === "multiple" && onSelectedKeysChange != null;
135
134
  const selected = selectedKeys ?? /* @__PURE__ */ new Set();
136
135
  const visibleKeys = safeItems.map((item) => getRowKey(item)).filter(Boolean);
@@ -138,13 +137,6 @@ function AdminListPage({
138
137
  const allVisibleSelected = visibleKeys.length > 0 && selectedVisibleCount === visibleKeys.length;
139
138
  const someVisibleSelected = selectedVisibleCount > 0 && !allVisibleSelected;
140
139
  const columnCount = columns.length + (selectionEnabled ? 1 : 0);
141
- const handleSearchInputKeyDown = (event) => {
142
- if (isSubmitMode && event.key === "Enter") {
143
- event.preventDefault();
144
- onSearchSubmit?.();
145
- }
146
- onSearchKeyDown?.(event);
147
- };
148
140
  const toggleKey = (key, checked) => {
149
141
  if (!onSelectedKeysChange) return;
150
142
  const next = new Set(selected);
@@ -182,59 +174,17 @@ function AdminListPage({
182
174
  !isSubmitMode ? /* @__PURE__ */ jsx(CardDescription, { children: searchPlaceholder }) : null
183
175
  ] }),
184
176
  selectionEnabled && selected.size > 0 && bulkActions ? /* @__PURE__ */ jsx("div", { className: "flex flex-wrap items-center gap-2", children: bulkActions }) : null,
185
- isSubmitMode ? /* @__PURE__ */ jsxs(
186
- "div",
177
+ isSubmitMode ? /* @__PURE__ */ jsx(
178
+ SearchField,
187
179
  {
188
- className: cn(
189
- "flex h-9 w-full min-w-0 max-w-full overflow-hidden rounded-md border border-input bg-background shadow-xs sm:max-w-sm",
190
- "transition-[border-color,box-shadow] focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/20"
191
- ),
192
- children: [
193
- /* @__PURE__ */ jsxs("div", { className: "relative flex min-w-0 flex-1 items-center", children: [
194
- /* @__PURE__ */ jsx(
195
- Input,
196
- {
197
- placeholder: searchPlaceholder,
198
- value: search,
199
- onChange: (e) => onSearchChange(e.target.value),
200
- onKeyDown: handleSearchInputKeyDown,
201
- className: cn(
202
- "h-9 rounded-none rounded-l-md border-0 bg-transparent px-3 shadow-none",
203
- "focus-visible:border-transparent focus-visible:ring-0",
204
- hasSearchText && "pr-9"
205
- ),
206
- "aria-label": searchPlaceholder
207
- }
208
- ),
209
- hasSearchText ? /* @__PURE__ */ jsx(
210
- Button,
211
- {
212
- type: "button",
213
- variant: "ghost",
214
- size: "icon-sm",
215
- onClick: onSearchClear,
216
- "aria-label": clearButtonLabel,
217
- className: "absolute right-1 top-1/2 -translate-y-1/2 text-muted-foreground hover:bg-muted/60 hover:text-foreground",
218
- children: /* @__PURE__ */ jsx(X, { className: "h-4 w-4", "aria-hidden": true })
219
- }
220
- ) : null
221
- ] }),
222
- /* @__PURE__ */ jsx(
223
- Button,
224
- {
225
- type: "button",
226
- variant: "default",
227
- onClick: onSearchSubmit,
228
- "aria-label": searchButtonLabel,
229
- className: cn(
230
- "h-full w-10 shrink-0 rounded-none rounded-r-md border-0 border-l border-primary-foreground/15 px-0 shadow-none",
231
- "hover:bg-primary/90 active:bg-primary/95",
232
- "shadow-[inset_0_1px_0_0_color-mix(in_oklch,var(--primary-foreground)_20%,transparent)]"
233
- ),
234
- children: /* @__PURE__ */ jsx(Search, { className: "h-4 w-4", "aria-hidden": true })
235
- }
236
- )
237
- ]
180
+ className: "max-w-full sm:max-w-sm",
181
+ value: search,
182
+ onValueChange: onSearchChange,
183
+ onSubmit: () => onSearchSubmit?.(),
184
+ onClear: onSearchClear,
185
+ placeholder: searchPlaceholder,
186
+ searchButtonLabel,
187
+ clearButtonLabel
238
188
  }
239
189
  ) : /* @__PURE__ */ jsxs("div", { className: "relative max-w-full sm:max-w-sm", children: [
240
190
  /* @__PURE__ */ jsx(
@@ -250,6 +200,7 @@ function AdminListPage({
250
200
  placeholder: searchPlaceholder,
251
201
  value: search,
252
202
  onChange: (e) => onSearchChange(e.target.value),
203
+ onKeyDown: onSearchKeyDown,
253
204
  className: "pl-9",
254
205
  "aria-label": searchPlaceholder
255
206
  }
@@ -573,6 +524,37 @@ function EntityRow({
573
524
  }
574
525
  );
575
526
  }
527
+ function LabeledSelect({
528
+ label,
529
+ value,
530
+ onValueChange,
531
+ options,
532
+ placeholder,
533
+ disabled,
534
+ className,
535
+ triggerClassName,
536
+ searchable,
537
+ translations
538
+ }) {
539
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
540
+ /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs font-medium text-muted-foreground", children: label }),
541
+ /* @__PURE__ */ jsx(
542
+ Select,
543
+ {
544
+ className: className ?? "w-[8.5rem]",
545
+ triggerClassName: triggerClassName ?? "h-9",
546
+ value,
547
+ onValueChange,
548
+ options,
549
+ placeholder,
550
+ disabled,
551
+ searchable,
552
+ translations,
553
+ "aria-label": label
554
+ }
555
+ )
556
+ ] });
557
+ }
576
558
  function RouteSuspense({ children, loadingLabel }) {
577
559
  return /* @__PURE__ */ jsx(Suspense, { fallback: /* @__PURE__ */ jsx(PageLoader, { variant: "route", loadingLabel }), children });
578
560
  }
@@ -639,6 +621,6 @@ function ThemeToggle({
639
621
  return /* @__PURE__ */ jsx(ThemeToggleWithContext, { ariaLabel });
640
622
  }
641
623
 
642
- export { AdminDetailPage, AdminListPage, AuditLogListFilters, DateRangeFilter, DetailFieldList, EntityRow, PageLoader, QueryState, RouteSuspense, ThemeProvider, ThemeToggle, createBoundQueryState, useDefaultThemeStore, useThemeStoreContext };
643
- //# sourceMappingURL=chunk-3GBM327E.js.map
644
- //# sourceMappingURL=chunk-3GBM327E.js.map
624
+ export { AdminDetailPage, AdminListPage, AuditLogListFilters, DateRangeFilter, DetailFieldList, EntityRow, LabeledSelect, PageLoader, QueryState, RouteSuspense, ThemeProvider, ThemeToggle, createBoundQueryState, useDefaultThemeStore, useThemeStoreContext };
625
+ //# sourceMappingURL=chunk-WZ64FPVI.js.map
626
+ //# sourceMappingURL=chunk-WZ64FPVI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/spa/page-loader/index.tsx","../src/components/spa/admin-detail-page/index.tsx","../src/components/spa/admin-list-page/index.tsx","../src/components/spa/audit-log-list-filters/index.tsx","../src/components/spa/query-state/index.tsx","../src/components/spa/create-bound-query-state/index.tsx","../src/components/spa/date-range-filter/index.tsx","../src/components/spa/detail-field-list/index.tsx","../src/components/spa/entity-row/index.tsx","../src/components/spa/labeled-select/index.tsx","../src/components/spa/route-suspense/index.tsx","../src/components/spa/theme-provider/index.tsx","../src/components/spa/theme-toggle/index.tsx"],"names":["jsx","jsxs","Loader2","Search","Fragment"],"mappings":"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","file":"chunk-WZ64FPVI.js","sourcesContent":["import { Loader2 } from 'lucide-react';\nimport { useTranslation } from 'react-i18next';\n\nimport { cn } from '../../../lib/utils';\n\nexport interface PageLoaderProps {\n className?: string;\n spinnerClassName?: string;\n /**\n * - `page`: full-screen route guard\n * - `route`: lazy route / admin detail suspense (`min-h-[40vh]`)\n * - `section`: in-page block (`py-12`)\n * - `inline`: compact centered spinner (auth cards, nested panels)\n */\n variant?: 'page' | 'route' | 'section' | 'inline';\n /** Accessible loading text; defaults to i18n `common.loading`. */\n loadingLabel?: string;\n}\n\nexport function PageLoader({\n className,\n spinnerClassName,\n variant = 'section',\n loadingLabel,\n}: PageLoaderProps) {\n const { t } = useTranslation('common');\n const label = loadingLabel ?? t('loading');\n const spinnerSize =\n variant === 'inline'\n ? 'h-6 w-6 animate-spin text-primary'\n : 'h-8 w-8 animate-spin text-primary';\n\n const content = (\n <>\n <Loader2 className={cn(spinnerSize, spinnerClassName)} aria-hidden />\n <span className=\"sr-only\">{label}</span>\n </>\n );\n\n if (variant === 'page') {\n return (\n <div\n className={cn('min-h-screen flex items-center justify-center bg-background', className)}\n role=\"status\"\n aria-live=\"polite\"\n >\n {content}\n </div>\n );\n }\n\n if (variant === 'route') {\n return (\n <div\n className={cn('flex min-h-[40vh] items-center justify-center', className)}\n role=\"status\"\n aria-live=\"polite\"\n >\n {content}\n </div>\n );\n }\n\n if (variant === 'inline') {\n return (\n <div\n className={cn('flex items-center justify-center', className)}\n role=\"status\"\n aria-live=\"polite\"\n >\n {content}\n </div>\n );\n }\n\n return (\n <div\n className={cn('flex items-center justify-center py-12', className)}\n role=\"status\"\n aria-live=\"polite\"\n >\n {content}\n </div>\n );\n}\n","import { ArrowLeft } from 'lucide-react';\nimport { Link } from 'react-router';\nimport type { AdminDetailErrorKind } from '../../../types/admin';\nimport { Button } from '../../ui';\nimport { PageLoader } from '../page-loader';\n\nexport type { AdminDetailErrorKind };\n\nexport interface AdminDetailPageProps {\n backHref: string;\n backLabel: string;\n isLoading: boolean;\n errorKind?: AdminDetailErrorKind;\n error?: unknown;\n notFoundMessage: string;\n forbiddenMessage: string;\n loadErrorMessage: string;\n /** App-bound API error formatter (e.g. formatApiError from SPA helpers). */\n formatError?: (error: unknown) => string;\n children: React.ReactNode;\n headerActions?: React.ReactNode;\n}\n\n/** Reusable admin detail page: back button, loading/error states, content. */\nexport function AdminDetailPage({\n backHref,\n backLabel,\n isLoading,\n errorKind,\n error,\n notFoundMessage,\n forbiddenMessage,\n loadErrorMessage,\n formatError,\n children,\n headerActions,\n}: AdminDetailPageProps) {\n if (isLoading) {\n return <PageLoader variant=\"route\" />;\n }\n\n if (errorKind) {\n const message =\n errorKind === 'forbidden'\n ? forbiddenMessage\n : errorKind === 'load'\n ? formatError?.(error) || loadErrorMessage\n : notFoundMessage;\n\n return (\n <div className=\"space-y-4 sm:space-y-6\">\n <p className=\"text-destructive\">{message}</p>\n <Link to={backHref}>\n <Button variant=\"outline\">{backLabel}</Button>\n </Link>\n </div>\n );\n }\n\n return (\n <div className=\"space-y-4 sm:space-y-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <Link to={backHref}>\n <Button variant=\"ghost\" size=\"sm\">\n <ArrowLeft className=\"mr-2 h-4 w-4\" aria-hidden />\n {backLabel}\n </Button>\n </Link>\n {headerActions}\n </div>\n {children}\n </div>\n );\n}\n","import { Loader2, Search } from 'lucide-react';\n\nimport type { AdminListSearchMode } from '../../../hooks/useAdminListPage';\nimport { cn } from '../../../lib/utils';\nimport {\n Card,\n CardContent,\n CardDescription,\n CardHeader,\n CardTitle,\n Checkbox,\n Input,\n SearchField,\n Table,\n TableBody,\n TableCell,\n TableHead,\n TableHeader,\n TableRow,\n} from '../../ui';\nimport { PageLoader } from '../page-loader';\n\nexport type { AdminListSearchMode };\n\nexport interface AdminListPageColumn<T> {\n key: string;\n header: string;\n render: (item: T) => React.ReactNode;\n /** Column class for alignment/width */\n className?: string;\n}\n\nexport type AdminListSelectionMode = 'none' | 'multiple';\n\nexport interface AdminListPageProps<T> {\n title: string;\n description: string;\n /** Optional actions (e.g. \"Create\" button) rendered next to the page title. */\n headerActions?: React.ReactNode;\n /** Card header title (e.g. \"All Users\") */\n cardTitle: string;\n searchPlaceholder: string;\n emptyMessage: string;\n columns: AdminListPageColumn<T>[];\n items: T[];\n isLoading: boolean;\n hasNextPage: boolean;\n isFetchingNextPage: boolean;\n loadMoreRef: React.RefObject<HTMLTableRowElement | null>;\n search: string;\n onSearchChange: (value: string) => void;\n onRowClick: (item: T) => void;\n getRowKey: (item: T) => string;\n /** Accessible label for the loading spinner (app i18n). */\n loadingAriaLabel?: string;\n /** `instant` updates query on debounced typing; `submit` requires Search/Clear actions. */\n searchMode?: AdminListSearchMode;\n /** Label for the Search button when `searchMode` is `submit`. */\n searchButtonLabel?: string;\n /** Label for the Clear button when `searchMode` is `submit`. */\n clearButtonLabel?: string;\n /** Called when the user clicks Search or presses Enter in submit mode. */\n onSearchSubmit?: () => void;\n /** Called when the user clicks Clear in submit mode. */\n onSearchClear?: () => void;\n /** Enter-key handler for submit mode (typically from `useAdminListPage().onSearchKeyDown`). */\n onSearchKeyDown?: React.KeyboardEventHandler<HTMLInputElement>;\n /** Optional row multi-select (default none). */\n selectionMode?: AdminListSelectionMode;\n selectedKeys?: Set<string>;\n onSelectedKeysChange?: (keys: Set<string>) => void;\n /** Rendered in the card header when selectionMode is multiple and keys are selected. */\n bulkActions?: React.ReactNode;\n /** Accessible label for the selection checkbox column. */\n selectionLabel?: string;\n}\n\n/**\n * Reusable admin list page: search + card + table + infinite scroll.\n */\nexport function AdminListPage<T>({\n title,\n description,\n headerActions,\n cardTitle,\n searchPlaceholder,\n emptyMessage,\n columns,\n items,\n isLoading,\n hasNextPage,\n isFetchingNextPage,\n loadMoreRef,\n search,\n onSearchChange,\n onRowClick,\n getRowKey,\n loadingAriaLabel = 'Loading...',\n searchMode = 'instant',\n searchButtonLabel = 'Search',\n clearButtonLabel = 'Clear',\n onSearchSubmit,\n onSearchClear,\n onSearchKeyDown,\n selectionMode = 'none',\n selectedKeys,\n onSelectedKeysChange,\n bulkActions,\n selectionLabel = 'Select',\n}: AdminListPageProps<T>) {\n const safeItems = items.filter((item): item is T => item != null && typeof item === 'object');\n const isSubmitMode = searchMode === 'submit';\n const selectionEnabled = selectionMode === 'multiple' && onSelectedKeysChange != null;\n const selected = selectedKeys ?? new Set<string>();\n const visibleKeys = safeItems.map((item) => getRowKey(item)).filter(Boolean);\n const selectedVisibleCount = visibleKeys.filter((key) => selected.has(key)).length;\n const allVisibleSelected = visibleKeys.length > 0 && selectedVisibleCount === visibleKeys.length;\n const someVisibleSelected = selectedVisibleCount > 0 && !allVisibleSelected;\n const columnCount = columns.length + (selectionEnabled ? 1 : 0);\n\n const toggleKey = (key: string, checked: boolean) => {\n if (!onSelectedKeysChange) return;\n const next = new Set(selected);\n if (checked) {\n next.add(key);\n } else {\n next.delete(key);\n }\n onSelectedKeysChange(next);\n };\n\n const toggleAllVisible = (checked: boolean) => {\n if (!onSelectedKeysChange) return;\n const next = new Set(selected);\n for (const key of visibleKeys) {\n if (checked) {\n next.add(key);\n } else {\n next.delete(key);\n }\n }\n onSelectedKeysChange(next);\n };\n\n return (\n <div className=\"space-y-4 sm:space-y-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-bold sm:text-3xl\">{title}</h1>\n <p className=\"mt-1 text-sm text-muted-foreground sm:text-base\">{description}</p>\n </div>\n {headerActions}\n </div>\n\n <Card>\n <CardHeader className=\"gap-4\">\n <div className=\"space-y-2\">\n <CardTitle>{cardTitle}</CardTitle>\n {!isSubmitMode ? <CardDescription>{searchPlaceholder}</CardDescription> : null}\n </div>\n {selectionEnabled && selected.size > 0 && bulkActions ? (\n <div className=\"flex flex-wrap items-center gap-2\">{bulkActions}</div>\n ) : null}\n {isSubmitMode ? (\n <SearchField\n className=\"max-w-full sm:max-w-sm\"\n value={search}\n onValueChange={onSearchChange}\n onSubmit={() => onSearchSubmit?.()}\n onClear={onSearchClear}\n placeholder={searchPlaceholder}\n searchButtonLabel={searchButtonLabel}\n clearButtonLabel={clearButtonLabel}\n />\n ) : (\n <div className=\"relative max-w-full sm:max-w-sm\">\n <Search\n className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground\"\n aria-hidden\n />\n <Input\n placeholder={searchPlaceholder}\n value={search}\n onChange={(e) => onSearchChange(e.target.value)}\n onKeyDown={onSearchKeyDown}\n className=\"pl-9\"\n aria-label={searchPlaceholder}\n />\n </div>\n )}\n </CardHeader>\n <CardContent>\n {isLoading ? (\n <PageLoader loadingLabel={loadingAriaLabel} />\n ) : safeItems.length === 0 ? (\n <p className=\"py-12 text-center text-muted-foreground\">{emptyMessage}</p>\n ) : (\n <div className=\"-mx-4 overflow-x-auto sm:mx-0\">\n <Table className=\"min-w-[400px]\">\n <TableHeader>\n <TableRow className=\"bg-muted/50 hover:bg-muted/50\">\n {selectionEnabled ? (\n <TableHead className=\"w-10\">\n <Checkbox\n checked={\n allVisibleSelected\n ? true\n : someVisibleSelected\n ? 'indeterminate'\n : false\n }\n onCheckedChange={(value) => toggleAllVisible(value === true)}\n aria-label={selectionLabel}\n onClick={(e) => e.stopPropagation()}\n />\n </TableHead>\n ) : null}\n {columns.map((col) => (\n <TableHead key={col.key} className={col.className}>\n {col.header}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {safeItems.map((item, index) => {\n const rowKey = getRowKey(item) || `row-${index}`;\n const isSelected = selected.has(rowKey);\n return (\n <TableRow\n key={rowKey}\n role=\"button\"\n tabIndex={0}\n data-state={isSelected ? 'selected' : undefined}\n onClick={() => onRowClick(item)}\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onRowClick(item);\n }\n }}\n className=\"cursor-pointer hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-inset\"\n >\n {selectionEnabled ? (\n <TableCell className=\"w-10\" onClick={(e) => e.stopPropagation()}>\n <Checkbox\n checked={isSelected}\n onCheckedChange={(value) => toggleKey(rowKey, value === true)}\n aria-label={`${selectionLabel} ${rowKey}`}\n />\n </TableCell>\n ) : null}\n {columns.map((col) => (\n <TableCell\n key={col.key}\n className={cn(col.className ?? 'text-muted-foreground')}\n >\n {col.render(item)}\n </TableCell>\n ))}\n </TableRow>\n );\n })}\n {hasNextPage && (\n <TableRow ref={loadMoreRef}>\n <TableCell\n colSpan={columnCount}\n className=\"text-center text-muted-foreground\"\n >\n {isFetchingNextPage ? (\n <Loader2 className=\"inline-block h-5 w-5 animate-spin\" aria-hidden />\n ) : null}\n </TableCell>\n </TableRow>\n )}\n </TableBody>\n </Table>\n </div>\n )}\n </CardContent>\n </Card>\n </div>\n );\n}\n","import { Search } from 'lucide-react';\n\nimport { Input } from '../../ui/input';\nimport { Select } from '../../ui/select';\n\nexport type AuditLogFilterOption = {\n value: string;\n label: string;\n};\n\nexport type AuditLogListFiltersProps = {\n search: string;\n onSearchChange: (value: string) => void;\n action: string;\n onActionChange: (value: string) => void;\n resourceType: string;\n onResourceTypeChange: (value: string) => void;\n actionOptions: AuditLogFilterOption[];\n resourceOptions: AuditLogFilterOption[];\n searchPlaceholder: string;\n actionFilterLabel: string;\n resourceFilterLabel: string;\n};\n\nexport function AuditLogListFilters({\n search,\n onSearchChange,\n action,\n onActionChange,\n resourceType,\n onResourceTypeChange,\n actionOptions,\n resourceOptions,\n searchPlaceholder,\n actionFilterLabel,\n resourceFilterLabel,\n}: AuditLogListFiltersProps) {\n return (\n <div className=\"flex flex-col gap-2 lg:flex-row lg:flex-wrap lg:items-center\">\n <div className=\"relative w-full lg:max-w-md\">\n <Search\n className=\"pointer-events-none absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-muted-foreground\"\n aria-hidden\n />\n <Input\n className=\"pl-9\"\n placeholder={searchPlaceholder}\n value={search}\n onChange={(event) => onSearchChange(event.target.value)}\n aria-label={searchPlaceholder}\n />\n </div>\n <Select\n className=\"w-full lg:w-44\"\n value={action}\n onValueChange={onActionChange}\n options={actionOptions}\n aria-label={actionFilterLabel}\n />\n <Select\n className=\"w-full lg:w-52\"\n value={resourceType}\n onValueChange={onResourceTypeChange}\n options={resourceOptions}\n aria-label={resourceFilterLabel}\n />\n </div>\n );\n}\n","import { Alert, AlertDescription, Button } from '../../ui';\nimport { PageLoader } from '../page-loader';\n\nexport interface QueryStateProps {\n isLoading: boolean;\n isError?: boolean;\n error?: unknown;\n onRetry?: () => void;\n loadingClassName?: string;\n children: React.ReactNode;\n /** App-bound API error formatter (e.g. formatApiError from SPA helpers). */\n formatError?: (error: unknown) => string;\n /** Fallback copy when formatError returns empty. */\n errorDescription?: string;\n retryLabel?: string;\n loadingLabel?: string;\n}\n\n/** Renders loading/error states for TanStack Query results, then children on success. */\nexport function QueryState({\n isLoading,\n isError,\n error,\n onRetry,\n loadingClassName,\n children,\n formatError,\n errorDescription = 'We could not load this data. Please try again.',\n retryLabel = 'Try again',\n loadingLabel = 'Loading...',\n}: QueryStateProps) {\n if (isLoading) {\n return (\n <PageLoader variant=\"section\" className={loadingClassName} loadingLabel={loadingLabel} />\n );\n }\n\n if (isError) {\n const message = formatError?.(error) || errorDescription;\n return (\n <Alert variant=\"destructive\" className=\"max-w-xl\">\n <AlertDescription className=\"space-y-3\">\n <p>{message}</p>\n {onRetry ? (\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={onRetry}>\n {retryLabel}\n </Button>\n ) : null}\n </AlertDescription>\n </Alert>\n );\n }\n\n return <>{children}</>;\n}\n","import { QueryState, type QueryStateProps } from '../query-state';\n\nexport type QueryStateBindings = Pick<\n QueryStateProps,\n 'formatError' | 'errorDescription' | 'retryLabel' | 'loadingLabel'\n>;\n\nexport type BoundQueryStateProps = Omit<QueryStateProps, keyof QueryStateBindings>;\n\n/** Factory for SPA-local i18n/error bindings around shared QueryState. */\nexport function createBoundQueryState(useBindings: () => QueryStateBindings) {\n function BoundQueryState(props: BoundQueryStateProps) {\n const bindings = useBindings();\n return <QueryState {...bindings} {...props} />;\n }\n\n BoundQueryState.displayName = 'BoundQueryState';\n return BoundQueryState;\n}\n","import type { DateRange } from 'react-day-picker';\n\nimport { dateRangePickerTranslations } from '../../../lib/dateRangePickerTranslations';\nimport { cn } from '../../../lib/utils';\nimport { DateRangePicker } from '../../ui/date-range-picker';\n\nexport interface DateRangeFilterProps {\n label: string;\n value: DateRange | undefined;\n onChange: (value: DateRange | undefined) => void;\n onApply: (value: DateRange | undefined) => void;\n minDate?: Date;\n maxDate?: Date;\n className?: string;\n hint?: string;\n /** Layout variant for toolbar vs panel contexts. */\n variant?: 'panel' | 'inline' | 'toolbar';\n /** i18n translate function (e.g. from useTranslationNamespace). */\n t: (key: string) => string;\n /** Namespace prefix for dateRange keys (default: `common`). */\n translationNs?: string;\n}\n\nexport function DateRangeFilter({\n label,\n value,\n onChange,\n onApply,\n minDate,\n maxDate,\n className,\n hint,\n variant = 'panel',\n t,\n translationNs = 'common',\n}: DateRangeFilterProps) {\n const inline = variant === 'inline';\n const toolbar = variant === 'toolbar';\n\n const picker = (\n <DateRangePicker\n className={cn(\n 'w-full min-w-0 border-border/80 bg-background',\n toolbar ? 'w-full min-w-0' : inline ? 'sm:max-w-[280px]' : 'sm:max-w-[320px]',\n )}\n value={value}\n onChange={onChange}\n minDate={minDate}\n maxDate={maxDate}\n translations={dateRangePickerTranslations(t, translationNs)}\n onApply={onApply}\n />\n );\n\n if (toolbar) {\n return (\n <div className={cn('flex min-w-0 w-full flex-col gap-1', className)}>\n <p className=\"text-xs font-medium text-muted-foreground\">{label}</p>\n {picker}\n </div>\n );\n }\n\n if (inline) {\n return (\n <div className={cn('flex w-full shrink-0 flex-col gap-1 sm:w-auto', className)}>\n <p className=\"text-xs font-medium text-muted-foreground\">{label}</p>\n {picker}\n {hint ? <p className=\"text-[0.65rem] text-muted-foreground\">{hint}</p> : null}\n </div>\n );\n }\n\n return (\n <div className={cn('rounded-lg border border-border/80 bg-muted/25 p-3 shadow-sm', className)}>\n <div className=\"flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between\">\n <div className=\"min-w-0 space-y-1\">\n <p className=\"text-xs font-medium uppercase tracking-wide text-muted-foreground\">\n {label}\n </p>\n {hint ? <p className=\"text-xs text-muted-foreground\">{hint}</p> : null}\n </div>\n {picker}\n </div>\n </div>\n );\n}\n\nexport { dateRangePickerTranslations };\n","import { cn } from '../../../lib/utils';\n\nexport interface DetailField {\n label: string;\n value: React.ReactNode;\n /** Span 2 columns on sm+ */\n span?: 1 | 2;\n}\n\nexport type DetailFieldVariant = 'plain' | 'bordered';\n\nexport interface DetailFieldListProps {\n fields: DetailField[];\n className?: string;\n /** When `bordered`, each label/value group is shown in a subtle framed cell. */\n fieldVariant?: DetailFieldVariant;\n}\n\n/** Definition list for detail views. Responsive two-column grid on sm+. */\nexport function DetailFieldList({\n fields,\n className,\n fieldVariant = 'plain',\n}: DetailFieldListProps) {\n return (\n <dl className={cn('grid gap-4 sm:grid-cols-2', className)}>\n {fields.map((field, i) => (\n <div\n key={`${field.label}-${i}`}\n className={cn(\n 'space-y-1',\n fieldVariant === 'bordered' && 'rounded-lg border bg-muted/20 px-3 py-2.5',\n field.span === 2 && 'sm:col-span-2',\n )}\n >\n <dt className=\"text-sm font-medium text-muted-foreground\">{field.label}</dt>\n <dd className=\"text-sm break-words\">{field.value}</dd>\n </div>\n ))}\n </dl>\n );\n}\n","import type { LucideIcon } from 'lucide-react';\nimport { MoreVertical } from 'lucide-react';\n\nimport { cn } from '../../../lib/utils';\nimport {\n Button,\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuTrigger,\n Tooltip,\n} from '../../ui';\n\nexport interface EntityRowAction {\n label: string;\n icon: LucideIcon;\n onClick: () => void;\n variant?: 'default' | 'destructive';\n}\n\nexport interface EntityRowProps {\n icon: LucideIcon;\n title: React.ReactNode;\n /** Tooltip for title (when title is truncated). Omit when title is a ReactNode. */\n titleTooltip?: string;\n description?: string;\n /** Secondary line below title (e.g. created date, email) */\n subtitle?: string;\n onClick?: () => void;\n actions?: EntityRowAction[];\n /** Muted styling for archived items */\n archived?: boolean;\n /** Extra content below main block (e.g. key prefix, metadata) */\n children?: React.ReactNode;\n className?: string;\n}\n\n/**\n * Reusable row for settings entity lists (roles, teams, members, API keys).\n * Consistent layout: icon + title + optional description/subtitle + actions dropdown.\n */\nexport function EntityRow({\n icon: Icon,\n title,\n titleTooltip = typeof title === 'string' ? title : undefined,\n description,\n subtitle,\n onClick,\n actions = [],\n archived = false,\n children,\n className,\n}: EntityRowProps) {\n const hasActions = actions.length > 0;\n const isClickable = !!onClick;\n\n return (\n <div\n role={isClickable ? 'button' : undefined}\n tabIndex={isClickable ? 0 : undefined}\n onClick={onClick}\n onKeyDown={\n isClickable\n ? (e) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n onClick?.();\n }\n }\n : undefined\n }\n className={cn(\n 'flex flex-col gap-2 rounded-lg border p-4 transition-colors',\n archived ? 'bg-muted/30' : 'hover:bg-muted/40',\n isClickable &&\n 'cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',\n className,\n )}\n >\n <div className=\"flex items-start justify-between gap-2\">\n <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n <div\n className={cn(\n 'flex h-10 w-10 shrink-0 items-center justify-center rounded-lg',\n archived ? 'bg-muted' : 'bg-primary/10',\n )}\n >\n <Icon\n className={cn('h-5 w-5', archived ? 'text-muted-foreground' : 'text-primary')}\n aria-hidden\n />\n </div>\n <div className=\"min-w-0 flex-1\">\n {titleTooltip ? (\n <Tooltip content={titleTooltip} side=\"top\" align=\"start\">\n <p className=\"truncate font-medium max-w-full sm:max-w-md\">{title}</p>\n </Tooltip>\n ) : (\n <p className=\"truncate font-medium max-w-full sm:max-w-md\">{title}</p>\n )}\n {subtitle && (\n <p className=\"mt-0.5 truncate text-xs text-muted-foreground max-w-full sm:max-w-md\">\n {subtitle}\n </p>\n )}\n </div>\n </div>\n {hasActions && (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"icon\"\n className=\"shrink-0 -mr-1\"\n onClick={(e) => e.stopPropagation()}\n aria-label=\"Open menu\"\n >\n <MoreVertical className=\"h-4 w-4\" aria-hidden />\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={4} onClick={(e) => e.stopPropagation()}>\n {actions.map((action) => {\n const ActionIcon = action.icon;\n return (\n <DropdownMenuItem\n key={action.label}\n onClick={action.onClick}\n className={\n action.variant === 'destructive'\n ? 'text-destructive focus:text-destructive'\n : undefined\n }\n >\n <ActionIcon className=\"mr-2 h-4 w-4\" aria-hidden />\n {action.label}\n </DropdownMenuItem>\n );\n })}\n </DropdownMenuContent>\n </DropdownMenu>\n )}\n </div>\n {description && (\n <Tooltip content={description} side=\"top\" align=\"start\">\n <p className=\"text-sm text-muted-foreground overflow-hidden line-clamp-2 [display:-webkit-box] [-webkit-line-clamp:2] [-webkit-box-orient:vertical]\">\n {description}\n </p>\n </Tooltip>\n )}\n {children}\n </div>\n );\n}\n","import type { SelectOption, SelectTranslations } from '../../ui/select';\nimport { Select } from '../../ui/select';\n\nexport type LabeledSelectProps = {\n label: string;\n value: string;\n onValueChange: (value: string) => void;\n options: SelectOption[];\n placeholder?: string;\n disabled?: boolean;\n className?: string;\n triggerClassName?: string;\n searchable?: boolean;\n translations?: SelectTranslations;\n};\n\n/** Toolbar filter select with a visible label + shared Select dropdown. */\nexport function LabeledSelect({\n label,\n value,\n onValueChange,\n options,\n placeholder,\n disabled,\n className,\n triggerClassName,\n searchable,\n translations,\n}: LabeledSelectProps) {\n return (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"shrink-0 text-xs font-medium text-muted-foreground\">{label}</span>\n <Select\n className={className ?? 'w-[8.5rem]'}\n triggerClassName={triggerClassName ?? 'h-9'}\n value={value}\n onValueChange={onValueChange}\n options={options}\n placeholder={placeholder}\n disabled={disabled}\n searchable={searchable}\n translations={translations}\n aria-label={label}\n />\n </div>\n );\n}\n","import { type ReactNode, Suspense } from 'react';\n\nimport { PageLoader } from '../page-loader';\n\nexport interface RouteSuspenseProps {\n children: ReactNode;\n loadingLabel?: string;\n}\n\n/** Suspense boundary for lazy route modules with shared loading UX. */\nexport function RouteSuspense({ children, loadingLabel }: RouteSuspenseProps) {\n return (\n <Suspense fallback={<PageLoader variant=\"route\" loadingLabel={loadingLabel} />}>\n {children}\n </Suspense>\n );\n}\n","import React, { useEffect, useState } from 'react';\n\n/**\n * Theme store interface for theme state management.\n */\nexport interface ThemeStore {\n /** Current theme mode */\n theme: 'light' | 'dark';\n /** Function to update theme */\n setTheme: (theme: 'light' | 'dark') => void;\n}\n\n/** Default in-memory theme store when no external store is provided. */\nexport function useDefaultThemeStore(): ThemeStore {\n const [theme, setTheme] = useState<'light' | 'dark'>('light');\n return { theme, setTheme };\n}\n\nconst ThemeStoreContext = React.createContext<ThemeStore | null>(null);\n\n/** Hook to read theme store from ThemeProvider context. */\nexport function useThemeStoreContext(): ThemeStore | null {\n return React.useContext(ThemeStoreContext);\n}\n\n/**\n * Props for the ThemeProvider component.\n */\nexport interface ThemeProviderProps {\n /** Child components */\n children: React.ReactNode;\n /** Hook function that returns the theme store (e.g., from Zustand) */\n useThemeStore?: () => ThemeStore;\n}\n\n/**\n * Theme provider component that applies theme classes to the document root.\n * Works with any state management solution via the `useThemeStore` prop.\n * When `useThemeStore` is not provided, uses an internal default store so hooks are always called unconditionally.\n *\n * @example\n * ```tsx\n * // With Zustand\n * const useThemeStore = () => {\n * const theme = useStore((state) => state.theme);\n * const setTheme = useStore((state) => state.setTheme);\n * return { theme, setTheme };\n * };\n *\n * <ThemeProvider useThemeStore={useThemeStore}>\n * <App />\n * </ThemeProvider>\n * ```\n */\nexport function ThemeProvider({ children, useThemeStore: useThemeStoreProp }: ThemeProviderProps) {\n const useResolvedStore = useThemeStoreProp ?? useDefaultThemeStore;\n const store = useResolvedStore();\n\n useEffect(() => {\n const root = window.document.documentElement;\n root.classList.remove('light', 'dark');\n root.classList.add(store.theme);\n }, [store.theme]);\n\n return <ThemeStoreContext.Provider value={store}>{children}</ThemeStoreContext.Provider>;\n}\n","import { Moon, Sun } from 'lucide-react';\nimport { Button } from '../../ui/button';\nimport type { ThemeStore } from '../theme-provider';\nimport { useDefaultThemeStore, useThemeStoreContext } from '../theme-provider';\n\n/**\n * Props for the ThemeToggle component.\n */\nexport interface ThemeToggleProps {\n /** Hook function that returns the theme store (e.g., from Zustand) */\n useThemeStore?: () => ThemeStore;\n /** Accessible label for the toggle button */\n ariaLabel?: string;\n}\n\nfunction ThemeToggleWithStore({\n useThemeStore,\n ariaLabel,\n}: {\n useThemeStore: () => ThemeStore;\n ariaLabel: string;\n}) {\n const { theme, setTheme } = useThemeStore();\n const toggleTheme = () => setTheme(theme === 'dark' ? 'light' : 'dark');\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={toggleTheme}\n aria-label={ariaLabel}\n className=\"cursor-pointer\"\n >\n {theme === 'dark' ? <Moon className=\"h-4 w-4\" /> : <Sun className=\"h-4 w-4\" />}\n </Button>\n );\n}\n\nfunction ThemeToggleWithContext({ ariaLabel }: { ariaLabel: string }) {\n const fromContext = useThemeStoreContext();\n const defaultStore = useDefaultThemeStore();\n const store = fromContext ?? defaultStore;\n const toggleTheme = () => store.setTheme(store.theme === 'dark' ? 'light' : 'dark');\n return (\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={toggleTheme}\n aria-label={ariaLabel}\n className=\"cursor-pointer\"\n >\n {store.theme === 'dark' ? <Moon className=\"h-4 w-4\" /> : <Sun className=\"h-4 w-4\" />}\n </Button>\n );\n}\n\n/**\n * Theme toggle button component.\n * Displays a sun icon in dark mode and moon icon in light mode.\n * Toggles between light and dark themes when clicked.\n * When useThemeStore is passed, uses that store; otherwise uses ThemeProvider context or internal default (no conditional hook calls).\n *\n * @example\n * ```tsx\n * const useThemeStore = () => {\n * const theme = useStore((state) => state.theme);\n * const setTheme = useStore((state) => state.setTheme);\n * return { theme, setTheme };\n * };\n *\n * <ThemeToggle useThemeStore={useThemeStore} ariaLabel=\"Toggle theme\" />\n * ```\n */\nexport function ThemeToggle({\n useThemeStore: useThemeStoreProp,\n ariaLabel = 'Toggle theme',\n}: ThemeToggleProps) {\n if (useThemeStoreProp) {\n return <ThemeToggleWithStore useThemeStore={useThemeStoreProp} ariaLabel={ariaLabel} />;\n }\n return <ThemeToggleWithContext ariaLabel={ariaLabel} />;\n}\n"]}
@@ -1,5 +1,5 @@
1
- export { DescriptionField, EmailField, ExpiresAtField, FirstNameField, LastNameField, NameField, PasswordField, PermissionsField, RoleSelectField } from '../../chunk-KO7KQ7DZ.js';
2
- import '../../chunk-XCDKWHJJ.js';
1
+ export { DescriptionField, EmailField, ExpiresAtField, FirstNameField, LastNameField, NameField, PasswordField, PermissionsField, RoleSelectField } from '../../chunk-HJZNKZHZ.js';
2
+ import '../../chunk-QHNZTXPJ.js';
3
3
  import '../../chunk-3AYG73DK.js';
4
4
  import '../../chunk-TSXUUD64.js';
5
5
  import '../../chunk-GXWVFQCK.js';
@@ -4,6 +4,7 @@ import { A as AdminDetailErrorKind } from '../../admin-BVYdWtEy.js';
4
4
  import { a as AdminListSearchMode } from '../../useAdminListPage-C4ZTTllP.js';
5
5
  import { DateRange } from 'react-day-picker';
6
6
  import { LucideIcon } from 'lucide-react';
7
+ import { a as SelectOption, b as SelectTranslations } from '../../index-Ckfrh1rP.js';
7
8
  export { d as dateRangePickerTranslations } from '../../dateRangePickerTranslations-B99F2WQA.js';
8
9
  import '@tanstack/react-query';
9
10
  import '../../pagination-CFqoqiAG.js';
@@ -188,6 +189,21 @@ interface EntityRowProps {
188
189
  */
189
190
  declare function EntityRow({ icon: Icon, title, titleTooltip, description, subtitle, onClick, actions, archived, children, className, }: EntityRowProps): React$1.JSX.Element;
190
191
 
192
+ type LabeledSelectProps = {
193
+ label: string;
194
+ value: string;
195
+ onValueChange: (value: string) => void;
196
+ options: SelectOption[];
197
+ placeholder?: string;
198
+ disabled?: boolean;
199
+ className?: string;
200
+ triggerClassName?: string;
201
+ searchable?: boolean;
202
+ translations?: SelectTranslations;
203
+ };
204
+ /** Toolbar filter select with a visible label + shared Select dropdown. */
205
+ declare function LabeledSelect({ label, value, onValueChange, options, placeholder, disabled, className, triggerClassName, searchable, translations, }: LabeledSelectProps): React$1.JSX.Element;
206
+
191
207
  interface PageLoaderProps {
192
208
  className?: string;
193
209
  spinnerClassName?: string;
@@ -281,4 +297,4 @@ interface ThemeToggleProps {
281
297
  */
282
298
  declare function ThemeToggle({ useThemeStore: useThemeStoreProp, ariaLabel, }: ThemeToggleProps): React$1.JSX.Element;
283
299
 
284
- export { AdminDetailErrorKind, AdminDetailPage, type AdminDetailPageProps, AdminListPage, type AdminListPageColumn, type AdminListPageProps, AdminListSearchMode, type AdminListSelectionMode, type AuditLogFilterOption, AuditLogListFilters, type AuditLogListFiltersProps, type BoundQueryStateProps, DateRangeFilter, type DateRangeFilterProps, type DetailField, DetailFieldList, type DetailFieldListProps, type DetailFieldVariant, EntityRow, type EntityRowAction, type EntityRowProps, PageLoader, type PageLoaderProps, QueryState, type QueryStateBindings, type QueryStateProps, RouteSuspense, type RouteSuspenseProps, ThemeProvider, type ThemeProviderProps, type ThemeStore, ThemeToggle, type ThemeToggleProps, createBoundQueryState, useDefaultThemeStore, useThemeStoreContext };
300
+ export { AdminDetailErrorKind, AdminDetailPage, type AdminDetailPageProps, AdminListPage, type AdminListPageColumn, type AdminListPageProps, AdminListSearchMode, type AdminListSelectionMode, type AuditLogFilterOption, AuditLogListFilters, type AuditLogListFiltersProps, type BoundQueryStateProps, DateRangeFilter, type DateRangeFilterProps, type DetailField, DetailFieldList, type DetailFieldListProps, type DetailFieldVariant, EntityRow, type EntityRowAction, type EntityRowProps, LabeledSelect, type LabeledSelectProps, PageLoader, type PageLoaderProps, QueryState, type QueryStateBindings, type QueryStateProps, RouteSuspense, type RouteSuspenseProps, ThemeProvider, type ThemeProviderProps, type ThemeStore, ThemeToggle, type ThemeToggleProps, createBoundQueryState, useDefaultThemeStore, useThemeStoreContext };
@@ -1,5 +1,5 @@
1
- export { AdminDetailPage, AdminListPage, AuditLogListFilters, DateRangeFilter, DetailFieldList, EntityRow, PageLoader, QueryState, RouteSuspense, ThemeProvider, ThemeToggle, createBoundQueryState, useDefaultThemeStore, useThemeStoreContext } from '../../chunk-3GBM327E.js';
2
- import '../../chunk-XCDKWHJJ.js';
1
+ export { AdminDetailPage, AdminListPage, AuditLogListFilters, DateRangeFilter, DetailFieldList, EntityRow, LabeledSelect, PageLoader, QueryState, RouteSuspense, ThemeProvider, ThemeToggle, createBoundQueryState, useDefaultThemeStore, useThemeStoreContext } from '../../chunk-WZ64FPVI.js';
2
+ import '../../chunk-QHNZTXPJ.js';
3
3
  import '../../chunk-3AYG73DK.js';
4
4
  export { dateRangePickerTranslations } from '../../chunk-UCJ76BEC.js';
5
5
  import '../../chunk-TSXUUD64.js';
@@ -17,6 +17,7 @@ import * as LabelPrimitive from '@radix-ui/react-label';
17
17
  import { Slot } from '@radix-ui/react-slot';
18
18
  import * as PopoverPrimitive from '@radix-ui/react-popover';
19
19
  import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area';
20
+ export { S as Select, a as SelectOption, b as SelectTranslations } from '../../index-Ckfrh1rP.js';
20
21
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
21
22
  import * as SwitchPrimitive from '@radix-ui/react-switch';
22
23
  import * as TabsPrimitive from '@radix-ui/react-tabs';
@@ -186,6 +187,51 @@ type DropdownSelectSearchInputProps = {
186
187
  };
187
188
  declare function DropdownSelectSearchInput({ value, onChange, placeholder, className, autoFocus, }: DropdownSelectSearchInputProps): React.JSX.Element;
188
189
 
190
+ /** A single calendar event shown in {@link EventCalendar}. */
191
+ interface EventCalendarEvent {
192
+ id: string;
193
+ title: string;
194
+ /** Inclusive start (date or datetime). */
195
+ start: Date;
196
+ /** Exclusive end; defaults to end of start day for all-day display. */
197
+ end?: Date;
198
+ /** Optional accent — CSS color or theme token class via `colorClassName`. */
199
+ color?: string;
200
+ colorClassName?: string;
201
+ allDay?: boolean;
202
+ }
203
+ type EventCalendarView = 'month' | 'week' | 'day';
204
+ interface EventCalendarProps {
205
+ events: EventCalendarEvent[];
206
+ /** Controlled visible date (any day within the visible range). */
207
+ value?: Date;
208
+ /** Uncontrolled initial date. */
209
+ defaultValue?: Date;
210
+ view?: EventCalendarView;
211
+ defaultView?: EventCalendarView;
212
+ onValueChange?: (date: Date) => void;
213
+ onViewChange?: (view: EventCalendarView) => void;
214
+ onEventClick?: (event: EventCalendarEvent) => void;
215
+ onSlotClick?: (date: Date) => void;
216
+ className?: string;
217
+ /** Week starts on Monday when true (default). */
218
+ weekStartsOnMonday?: boolean;
219
+ labels?: {
220
+ today?: string;
221
+ month?: string;
222
+ week?: string;
223
+ day?: string;
224
+ };
225
+ }
226
+
227
+ /**
228
+ * Month / week / day event calendar shell for app surfaces (time-off, holidays, meetings).
229
+ * Distinct from the day-picker {@link Calendar} used in forms.
230
+ *
231
+ * Storybook: UI/EventCalendar
232
+ */
233
+ declare function EventCalendar({ events, value, defaultValue, view: viewProp, defaultView, onValueChange, onViewChange, onEventClick, onSlotClick, className, weekStartsOnMonday, labels, }: EventCalendarProps): React.JSX.Element;
234
+
189
235
  declare const Form: <TFieldValues extends FieldValues, TContext = any, TTransformedValues = TFieldValues>({ children, watch, getValues, getFieldState, setError, clearErrors, setValue, setValues, trigger, formState, resetField, reset, handleSubmit, unregister, control, register, setFocus, subscribe, }: react_hook_form.FormProviderProps<TFieldValues, TContext, TTransformedValues>) => React.JSX.Element;
190
236
  declare const FormField: <TFieldValues extends FieldValues = FieldValues, TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>>({ ...props }: ControllerProps<TFieldValues, TName>) => React.JSX.Element;
191
237
  declare const useFormField: () => {
@@ -277,28 +323,28 @@ declare function PopoverContent({ className, align, sideOffset, collisionPadding
277
323
  declare const ScrollArea: React.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
278
324
  declare const ScrollBar: React.ForwardRefExoticComponent<Omit<ScrollAreaPrimitive.ScrollAreaScrollbarProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
279
325
 
280
- interface SelectOption {
281
- value: string;
282
- label: string;
283
- }
284
- interface SelectTranslations {
285
- searchPlaceholder?: string;
286
- noOptionsText?: string;
287
- }
288
- interface SelectProps {
326
+ type SearchFieldProps = {
289
327
  value: string;
290
328
  onValueChange: (value: string) => void;
291
- options: SelectOption[];
329
+ onSubmit: () => void;
330
+ /** Clears draft/applied search. Shown only when value is non-empty. */
331
+ onClear?: () => void;
292
332
  placeholder?: string;
293
- disabled?: boolean;
294
- className?: string;
295
- triggerClassName?: string;
296
- /** When omitted, search appears automatically for 8+ options. */
297
- searchable?: boolean;
298
- translations?: SelectTranslations;
333
+ /** Accessible label for the text field (defaults to placeholder). */
299
334
  'aria-label'?: string;
300
- }
301
- declare function Select({ value, onValueChange, options, placeholder, disabled, className, triggerClassName, searchable, translations, 'aria-label': ariaLabel, }: SelectProps): React.JSX.Element;
335
+ searchButtonLabel?: string;
336
+ clearButtonLabel?: string;
337
+ className?: string;
338
+ inputClassName?: string;
339
+ disabled?: boolean;
340
+ id?: string;
341
+ name?: string;
342
+ autoComplete?: string;
343
+ };
344
+ /**
345
+ * Joined search control: text field + optional clear (X) + primary magnifier submit.
346
+ */
347
+ declare function SearchField({ value, onValueChange, onSubmit, onClear, placeholder, 'aria-label': ariaLabel, searchButtonLabel, clearButtonLabel, className, inputClassName, disabled, id, name, autoComplete, }: SearchFieldProps): React.JSX.Element;
302
348
 
303
349
  /** Show search in single-select dropdowns when option count reaches this threshold. */
304
350
  declare const SEARCHABLE_SELECT_MIN_OPTIONS = 8;
@@ -426,4 +472,4 @@ interface UploadDropzoneFileProps extends UploadDropzoneBaseProps {
426
472
  type UploadDropzoneProps = UploadDropzoneImageProps | UploadDropzoneFileProps;
427
473
  declare function UploadDropzone(props: UploadDropzoneProps): React.JSX.Element;
428
474
 
429
- export { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarFallback, AvatarImage, Badge, Button, Calendar, type CalendarProps, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, ConfirmDialog, type ConfirmDialogProps, DatePicker, type DatePickerProps, DateRangePicker, DateRangePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownScrollableList, type DropdownScrollableListProps, DropdownSelectSearchInput, type DropdownSelectSearchInputProps, Form, FormControl, FormDescription, FormDrawer, type FormDrawerProps, FormField, FormItem, FormLabel, FormMessage, H3, Heading, Input, Label, Link, type LinkProps, MultiSelect, type MultiSelectOption, type MultiSelectTranslations, Paragraph, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, SEARCHABLE_SELECT_MIN_OPTIONS, ScrollArea, ScrollBar, Select, type SelectOption, type SelectSearchableOption, type SelectTranslations, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Tooltip, type TooltipProps, TooltipProvider, UploadDropzone, type UploadDropzoneFileProps, type UploadDropzoneImageProps, type UploadDropzoneProps, type UploadDropzoneTranslations, badgeVariants, buttonVariants, dropdownMenuSelectOptionsMaxHeightClassName, filterSelectOptions, foldSearchText, headingVariants, isSelectSearchable, linkStyles, paragraphVariants, useFormField };
475
+ export { Alert, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, Avatar, AvatarFallback, AvatarImage, Badge, Button, Calendar, type CalendarProps, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Checkbox, ConfirmDialog, type ConfirmDialogProps, DatePicker, type DatePickerProps, DateRangePicker, DateRangePickerProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, DropdownScrollableList, type DropdownScrollableListProps, DropdownSelectSearchInput, type DropdownSelectSearchInputProps, EventCalendar, type EventCalendarEvent, type EventCalendarProps, type EventCalendarView, Form, FormControl, FormDescription, FormDrawer, type FormDrawerProps, FormField, FormItem, FormLabel, FormMessage, H3, Heading, Input, Label, Link, type LinkProps, MultiSelect, type MultiSelectOption, type MultiSelectTranslations, Paragraph, Popover, PopoverAnchor, PopoverContent, PopoverTrigger, SEARCHABLE_SELECT_MIN_OPTIONS, ScrollArea, ScrollBar, SearchField, type SearchFieldProps, type SelectSearchableOption, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetOverlay, SheetPortal, SheetTitle, SheetTrigger, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, Tooltip, type TooltipProps, TooltipProvider, UploadDropzone, type UploadDropzoneFileProps, type UploadDropzoneImageProps, type UploadDropzoneProps, type UploadDropzoneTranslations, badgeVariants, buttonVariants, dropdownMenuSelectOptionsMaxHeightClassName, filterSelectOptions, foldSearchText, headingVariants, isSelectSearchable, linkStyles, paragraphVariants, useFormField };