@douglasneuroinformatics/libui 3.1.5 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-K2YKS4A5.js → chunk-AFNJZUOE.js} +23 -11
- package/dist/chunk-AFNJZUOE.js.map +1 -0
- package/dist/components.d.ts +6 -2
- package/dist/components.js +13 -5
- package/dist/components.js.map +1 -1
- package/dist/douglasneuroinformatics-libui-3.3.0.tgz +0 -0
- package/dist/hooks.d.ts +23 -14
- package/dist/hooks.js +5 -1
- package/dist/tailwind/config.cjs +82 -72
- package/dist/tailwind/config.cjs.map +1 -1
- package/dist/tailwind/config.d.cts +5 -2
- package/package.json +1 -1
- package/src/components/SearchBar/SearchBar.tsx +13 -2
- package/src/components/StatisticCard/StatisticCard.tsx +3 -2
- package/src/hooks/index.ts +1 -1
- package/src/hooks/useStorage/index.ts +3 -0
- package/src/hooks/useStorage/useLocalStorage.test.ts +16 -0
- package/src/hooks/useStorage/useLocalStorage.ts +12 -0
- package/src/hooks/useStorage/useSessionStorage.test.ts +16 -0
- package/src/hooks/useStorage/useSessionStorage.ts +12 -0
- package/src/hooks/useStorage/useStorage.test.ts +193 -0
- package/src/hooks/{useSessionStorage/useSessionStorage.ts → useStorage/useStorage.ts} +31 -46
- package/src/tailwind/config.cts +86 -73
- package/src/testing/mocks.ts +4 -5
- package/dist/chunk-K2YKS4A5.js.map +0 -1
- package/dist/douglasneuroinformatics-libui-3.1.5.tgz +0 -0
- package/src/hooks/useSessionStorage/index.ts +0 -1
- package/src/hooks/useSessionStorage/useSessionStorage.test.ts +0 -187
|
@@ -150,10 +150,11 @@ function useOnClickOutside(ref, handler, mouseEvent = "mousedown") {
|
|
|
150
150
|
});
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
// src/hooks/
|
|
153
|
+
// src/hooks/useStorage/useStorage.ts
|
|
154
154
|
import { useCallback as useCallback2, useEffect as useEffect6, useState as useState3 } from "react";
|
|
155
|
-
function
|
|
155
|
+
function useStorage(key, initialValue, storageName, options = {}) {
|
|
156
156
|
const { initializeWithValue = true } = options;
|
|
157
|
+
const storage = window[storageName];
|
|
157
158
|
const serializer = useCallback2(
|
|
158
159
|
(value) => {
|
|
159
160
|
if (options.serializer) {
|
|
@@ -167,8 +168,7 @@ function useSessionStorage(key, initialValue, options = {}) {
|
|
|
167
168
|
(value) => {
|
|
168
169
|
if (options.deserializer) {
|
|
169
170
|
return options.deserializer(value);
|
|
170
|
-
}
|
|
171
|
-
if (value === "undefined") {
|
|
171
|
+
} else if (value === "undefined") {
|
|
172
172
|
return void 0;
|
|
173
173
|
}
|
|
174
174
|
const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;
|
|
@@ -188,7 +188,7 @@ function useSessionStorage(key, initialValue, options = {}) {
|
|
|
188
188
|
if (!isBrowser()) {
|
|
189
189
|
return initialValueToUse;
|
|
190
190
|
}
|
|
191
|
-
const raw =
|
|
191
|
+
const raw = storage.getItem(key);
|
|
192
192
|
return raw ? deserializer(raw) : initialValueToUse;
|
|
193
193
|
}, [initialValue, key, deserializer]);
|
|
194
194
|
const [storedValue, setStoredValue] = useState3(() => {
|
|
@@ -199,15 +199,15 @@ function useSessionStorage(key, initialValue, options = {}) {
|
|
|
199
199
|
});
|
|
200
200
|
const setValue = useEventCallback((value) => {
|
|
201
201
|
if (!isBrowser()) {
|
|
202
|
-
console.warn(`Tried setting
|
|
202
|
+
console.warn(`Tried setting storage key \u201C${key}\u201D even though environment is not a client`);
|
|
203
203
|
}
|
|
204
204
|
try {
|
|
205
205
|
const newValue = value instanceof Function ? value(readValue()) : value;
|
|
206
|
-
|
|
206
|
+
storage.setItem(key, serializer(newValue));
|
|
207
207
|
setStoredValue(newValue);
|
|
208
|
-
window.dispatchEvent(new StorageEvent(
|
|
208
|
+
window.dispatchEvent(new StorageEvent(storageName, { key }));
|
|
209
209
|
} catch (error) {
|
|
210
|
-
console.warn(`Error setting
|
|
210
|
+
console.warn(`Error setting storage key \u201C${key}\u201D:`, error);
|
|
211
211
|
}
|
|
212
212
|
});
|
|
213
213
|
useEffect6(() => {
|
|
@@ -223,10 +223,20 @@ function useSessionStorage(key, initialValue, options = {}) {
|
|
|
223
223
|
[key, readValue]
|
|
224
224
|
);
|
|
225
225
|
useEventListener("storage", handleStorageChange);
|
|
226
|
-
useEventListener(
|
|
226
|
+
useEventListener(storageName, handleStorageChange);
|
|
227
227
|
return [storedValue, setValue];
|
|
228
228
|
}
|
|
229
229
|
|
|
230
|
+
// src/hooks/useStorage/useLocalStorage.ts
|
|
231
|
+
function useLocalStorage(key, initialValue, options = {}) {
|
|
232
|
+
return useStorage(key, initialValue, "localStorage", options);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/hooks/useStorage/useSessionStorage.ts
|
|
236
|
+
function useSessionStorage(key, initialValue, options = {}) {
|
|
237
|
+
return useStorage(key, initialValue, "sessionStorage", options);
|
|
238
|
+
}
|
|
239
|
+
|
|
230
240
|
// src/hooks/useTheme/useTheme.ts
|
|
231
241
|
import { useEffect as useEffect7, useState as useState4 } from "react";
|
|
232
242
|
var DEFAULT_THEME = "light";
|
|
@@ -324,6 +334,8 @@ export {
|
|
|
324
334
|
useInterval,
|
|
325
335
|
useMediaQuery,
|
|
326
336
|
useOnClickOutside,
|
|
337
|
+
useStorage,
|
|
338
|
+
useLocalStorage,
|
|
327
339
|
useSessionStorage,
|
|
328
340
|
DEFAULT_THEME,
|
|
329
341
|
THEME_ATTRIBUTE,
|
|
@@ -333,4 +345,4 @@ export {
|
|
|
333
345
|
useTranslation,
|
|
334
346
|
useWindowSize
|
|
335
347
|
};
|
|
336
|
-
//# sourceMappingURL=chunk-
|
|
348
|
+
//# sourceMappingURL=chunk-AFNJZUOE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/hooks/useDownload/useDownload.ts","../src/hooks/useNotificationsStore/useNotificationsStore.ts","../src/hooks/useEventCallback/useEventCallback.ts","../src/hooks/useIsomorphicLayoutEffect/useIsomorphicLayoutEffect.ts","../src/hooks/useEventListener/useEventListener.ts","../src/hooks/useInterval/useInterval.ts","../src/hooks/useMediaQuery/useMediaQuery.ts","../src/hooks/useOnClickOutside/useOnClickOutside.ts","../src/hooks/useStorage/useStorage.ts","../src/hooks/useStorage/useLocalStorage.ts","../src/hooks/useStorage/useSessionStorage.ts","../src/hooks/useTheme/useTheme.ts","../src/hooks/useTranslation/useTranslation.ts","../src/hooks/useWindowSize/useWindowSize.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\nimport type { Promisable } from 'type-fest';\n\nimport { useNotificationsStore } from '../useNotificationsStore';\n\ntype DownloadTextOptions = {\n blobType: 'text/csv' | 'text/plain';\n};\n\ntype DownloadBlobOptions = {\n blobType: 'application/zip' | 'image/jpeg' | 'image/png' | 'image/webp';\n};\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-definitions\ninterface DownloadFunction {\n (filename: string, data: Blob, options: DownloadBlobOptions): Promise<void>;\n (filename: string, data: () => Promisable<Blob>, options: DownloadBlobOptions): Promise<void>;\n (filename: string, data: string, options?: DownloadTextOptions): Promise<void>;\n (filename: string, data: () => Promisable<string>, options?: DownloadTextOptions): Promise<void>;\n}\n\n/**\n * Used to trigger downloads of arbitrary data to the client\n * @returns A function to invoke the download\n */\nexport function useDownload(): DownloadFunction {\n const notifications = useNotificationsStore();\n const [state, setState] = useState<{\n blobType: string;\n data: Blob | string;\n filename: string;\n } | null>(null);\n\n useEffect(() => {\n if (state) {\n const { blobType, data, filename } = state;\n const anchor = document.createElement('a');\n document.body.appendChild(anchor);\n\n const blob = new Blob([data], { type: blobType });\n\n const url = URL.createObjectURL(blob);\n anchor.href = url;\n anchor.download = filename;\n anchor.click();\n URL.revokeObjectURL(url);\n anchor.remove();\n setState(null);\n }\n }, [state]);\n\n return async (filename, _data, options) => {\n try {\n const data = typeof _data === 'function' ? await _data() : _data;\n if (typeof data !== 'string' && !options?.blobType) {\n throw new Error(\"argument 'blobType' must be defined when download is called with a Blob object\");\n }\n setState({ blobType: options?.blobType ?? 'text/plain', data, filename });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'An unknown error occurred';\n notifications.addNotification({\n message,\n title: 'Error',\n type: 'error'\n });\n }\n };\n}\n","import { create } from 'zustand';\n\nexport type NotificationInterface = {\n id: number;\n message?: string;\n title?: string;\n type: 'error' | 'info' | 'success' | 'warning';\n variant?: 'critical' | 'standard';\n};\n\nexport type NotificationsStore = {\n addNotification: (notification: Omit<NotificationInterface, 'id'>) => void;\n dismissNotification: (id: number) => void;\n notifications: NotificationInterface[];\n};\n\nexport const useNotificationsStore = create<NotificationsStore>((set) => ({\n addNotification: (notification) => {\n set((state) => ({\n notifications: [...state.notifications, { id: Date.now(), ...notification }]\n }));\n },\n dismissNotification: (id) => {\n set((state) => ({\n notifications: state.notifications.filter((notification) => notification.id !== id)\n }));\n },\n notifications: []\n}));\n","import { useCallback, useRef } from 'react';\n\nimport { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect';\n\nexport function useEventCallback<Args extends unknown[], R>(fn: (...args: Args) => R) {\n const ref = useRef<typeof fn>(() => {\n throw new Error('Cannot call an event handler while rendering.');\n });\n\n useIsomorphicLayoutEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n return useCallback((...args: Args) => ref.current(...args), [ref]);\n}\n","import { useEffect, useLayoutEffect } from 'react';\n\nimport { isBrowser } from '@/utils';\n\nexport const useIsomorphicLayoutEffect = isBrowser() ? useLayoutEffect : useEffect;\n","import { type RefObject, useEffect, useRef } from 'react';\n\nimport { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect';\n\n// MediaQueryList Event based useEventListener interface\nfunction useEventListener<K extends keyof MediaQueryListEventMap>(\n eventName: K,\n handler: (event: MediaQueryListEventMap[K]) => void,\n element: RefObject<MediaQueryList>,\n options?: AddEventListenerOptions | boolean\n): void;\n\n// Window Event based useEventListener interface\nfunction useEventListener<K extends keyof WindowEventMap>(\n eventName: K,\n handler: (event: WindowEventMap[K]) => void,\n element?: undefined,\n options?: AddEventListenerOptions | boolean\n): void;\n\n// Element Event based useEventListener interface\nfunction useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = HTMLDivElement>(\n eventName: K,\n handler: (event: HTMLElementEventMap[K]) => void,\n element: RefObject<T>,\n options?: AddEventListenerOptions | boolean\n): void;\n\n// Document Event based useEventListener interface\nfunction useEventListener<K extends keyof DocumentEventMap>(\n eventName: K,\n handler: (event: DocumentEventMap[K]) => void,\n element: RefObject<Document>,\n options?: AddEventListenerOptions | boolean\n): void;\n\nfunction useEventListener<\n KW extends keyof WindowEventMap,\n KH extends keyof HTMLElementEventMap,\n KM extends keyof MediaQueryListEventMap,\n T extends HTMLElement | MediaQueryList | void = void\n>(\n eventName: KH | KM | KW,\n handler: (event: Event | HTMLElementEventMap[KH] | MediaQueryListEventMap[KM] | WindowEventMap[KW]) => void,\n element?: RefObject<T>,\n options?: AddEventListenerOptions | boolean\n) {\n // Create a ref that stores handler\n const savedHandler = useRef(handler);\n\n useIsomorphicLayoutEffect(() => {\n savedHandler.current = handler;\n }, [handler]);\n\n useEffect(() => {\n // Define the listening target\n const targetElement: T | Window = element?.current ?? window;\n\n if (!(targetElement && targetElement.addEventListener)) return;\n\n // Create event listener that calls handler function stored in ref\n const listener: typeof handler = (event) => savedHandler.current(event);\n\n targetElement.addEventListener(eventName, listener, options);\n\n // Remove event listener on cleanup\n return () => {\n targetElement.removeEventListener(eventName, listener, options);\n };\n }, [eventName, element, options]);\n}\n\nexport { useEventListener };\n","import { useEffect, useRef } from 'react';\n\nimport { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect';\n\nexport function useInterval(callback: () => void, delay: null | number) {\n const savedCallback = useRef(callback);\n\n // Remember the latest callback if it changes.\n useIsomorphicLayoutEffect(() => {\n savedCallback.current = callback;\n }, [callback]);\n\n // Set up the interval.\n useEffect(() => {\n // Don't schedule if no delay is specified.\n // Note: 0 is a valid value for delay.\n if (!delay && delay !== 0) {\n return;\n }\n\n const id = setInterval(() => savedCallback.current(), delay);\n\n return () => clearInterval(id);\n }, [delay]);\n}\n","import { useEffect, useState } from 'react';\n\nimport { isBrowser } from '@/utils';\n\n/**\n * Get the result of an arbitrary CSS media query\n *\n * @param query - the CSS media query\n * @returns a boolean indicating the result of the query\n * @example\n * // true if the viewport is at least 768px wide\n * const matches = useMediaQuery('(min-width: 768px)')\n */\nexport function useMediaQuery(query: string): boolean {\n const getMatches = (query: string): boolean => {\n // Prevents SSR issues\n if (isBrowser()) {\n return window.matchMedia(query).matches;\n }\n return false;\n };\n\n const [matches, setMatches] = useState<boolean>(getMatches(query));\n\n function handleChange() {\n setMatches(getMatches(query));\n }\n\n useEffect(() => {\n const matchMedia = window.matchMedia(query);\n\n // Triggered at the first client-side load and if query changes\n handleChange();\n\n matchMedia.addEventListener('change', handleChange);\n\n return () => {\n matchMedia.removeEventListener('change', handleChange);\n };\n }, [query]);\n\n return matches;\n}\n","import { type RefObject } from 'react';\n\nimport { useEventListener } from '../useEventListener';\n\ntype Handler = (event: MouseEvent) => void;\n\nexport function useOnClickOutside<T extends HTMLElement = HTMLElement>(\n ref: RefObject<T>,\n handler: Handler,\n mouseEvent: 'mousedown' | 'mouseup' = 'mousedown'\n): void {\n useEventListener(mouseEvent, (event) => {\n const el = ref.current;\n\n // Do nothing if clicking ref's element or descendent elements\n if (!el || el.contains(event.target as Node)) {\n return;\n }\n\n handler(event);\n });\n}\n","import { useCallback, useEffect, useState } from 'react';\nimport type { Dispatch, SetStateAction } from 'react';\n\nimport { isBrowser } from '@/utils';\n\nimport { useEventCallback } from '../useEventCallback';\nimport { useEventListener } from '../useEventListener';\n\ntype StorageName = 'localStorage' | 'sessionStorage';\n\ntype StorageEventMap = {\n [K in StorageName]: CustomEvent;\n};\n\ndeclare global {\n // eslint-disable-next-line @typescript-eslint/consistent-type-definitions, @typescript-eslint/no-empty-object-type\n interface WindowEventMap extends StorageEventMap {}\n}\n\n/**\n * Represents the options for customizing the behavior of serialization and deserialization.\n * @template T - The type of the state to be stored in storage.\n */\ntype UseStorageOptions<T> = {\n /** A function to deserialize the stored value. */\n deserializer?: (value: string) => T;\n /**\n * If `true` (default), the hook will initialize reading the storage. In SSR, you should set it to `false`, returning the initial value initially.\n * @default true\n */\n initializeWithValue?: boolean;\n /** A function to serialize the value before storing it. */\n serializer?: (value: T) => string;\n};\n\n/**\n * Custom hook that uses local or session storage to persist state across page reloads.\n * @template T - The type of the state to be stored in storage.\n * @param key - The key under which the value will be stored in storage.\n * @param initialValue - The initial value of the state or a function that returns the initial value.\n * @param options - Options for customizing the behavior of serialization and deserialization (optional).\n * @returns A tuple containing the stored value and a function to set the value.\n * @public\n * @example\n * ```tsx\n * const [count, setCount] = useStorage('count', 0);\n * // Access the `count` value and the `setCount` function to update it.\n * ```\n */\nexport function useStorage<T>(\n key: string,\n initialValue: (() => T) | T,\n storageName: StorageName,\n options: UseStorageOptions<T> = {}\n): [T, Dispatch<SetStateAction<T>>] {\n const { initializeWithValue = true } = options;\n const storage = window[storageName];\n\n const serializer = useCallback<(value: T) => string>(\n (value) => {\n if (options.serializer) {\n return options.serializer(value);\n }\n return JSON.stringify(value);\n },\n [options]\n );\n\n const deserializer = useCallback<(value: string) => T>(\n (value) => {\n if (options.deserializer) {\n return options.deserializer(value);\n } else if (value === 'undefined') {\n return undefined as unknown as T;\n }\n const defaultValue = initialValue instanceof Function ? initialValue() : initialValue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(value);\n } catch (err) {\n console.error(`Error parsing JSON: ${(err as Error).message}`);\n return defaultValue;\n }\n return parsed as T;\n },\n [options, initialValue]\n );\n\n const readValue = useCallback((): T => {\n const initialValueToUse = initialValue instanceof Function ? initialValue() : initialValue;\n if (!isBrowser()) {\n return initialValueToUse;\n }\n const raw = storage.getItem(key);\n return raw ? deserializer(raw) : initialValueToUse;\n }, [initialValue, key, deserializer]);\n\n const [storedValue, setStoredValue] = useState(() => {\n if (initializeWithValue) {\n return readValue();\n }\n return initialValue instanceof Function ? initialValue() : initialValue;\n });\n\n const setValue: Dispatch<SetStateAction<T>> = useEventCallback((value) => {\n if (!isBrowser()) {\n console.warn(`Tried setting storage key “${key}” even though environment is not a client`);\n }\n try {\n const newValue = value instanceof Function ? value(readValue()) : value;\n storage.setItem(key, serializer(newValue));\n setStoredValue(newValue);\n window.dispatchEvent(new StorageEvent(storageName, { key }));\n } catch (error) {\n console.warn(`Error setting storage key “${key}”:`, error);\n }\n });\n\n useEffect(() => {\n setStoredValue(readValue());\n }, [key]);\n\n const handleStorageChange = useCallback(\n (event: CustomEvent | StorageEvent) => {\n if ((event as StorageEvent).key && (event as StorageEvent).key !== key) {\n return;\n }\n setStoredValue(readValue());\n },\n [key, readValue]\n );\n\n // this only works for other documents, not the current one\n useEventListener('storage', handleStorageChange);\n\n useEventListener(storageName, handleStorageChange);\n\n return [storedValue, setValue];\n}\n\nexport type { StorageName, UseStorageOptions };\n","import type { Dispatch, SetStateAction } from 'react';\n\nimport { useStorage, type UseStorageOptions } from './useStorage';\n\n/** Custom hook that uses local storage to persist state across page reloads */\nexport function useLocalStorage<T>(\n key: string,\n initialValue: (() => T) | T,\n options: UseStorageOptions<T> = {}\n): [T, Dispatch<SetStateAction<T>>] {\n return useStorage(key, initialValue, 'localStorage', options);\n}\n","import type { Dispatch, SetStateAction } from 'react';\n\nimport { useStorage, type UseStorageOptions } from './useStorage';\n\n/** Custom hook that uses session storage to persist state across page reloads */\nexport function useSessionStorage<T>(\n key: string,\n initialValue: (() => T) | T,\n options: UseStorageOptions<T> = {}\n): [T, Dispatch<SetStateAction<T>>] {\n return useStorage(key, initialValue, 'sessionStorage', options);\n}\n","import { useEffect, useState } from 'react';\n\n// this is required since our storybook manager plugin cannot use vite aliases\nimport { isBrowser } from '../../utils';\n\ntype Theme = 'dark' | 'light';\n\ntype UpdateTheme = (theme: Theme) => void;\n\n/** @private */\nconst DEFAULT_THEME: Theme = 'light';\n\n/** @private */\nconst THEME_ATTRIBUTE = 'data-mode';\n\n/** @private */\nconst THEME_KEY = 'theme';\n\n/** @private */\nconst SYS_DARK_MEDIA_QUERY = '(prefers-color-scheme: dark)';\n\n/**\n * Returns the current theme and a function to update the current theme\n *\n * The reason the implementation of this hook is rather convoluted is for\n * cases where the theme is updated outside this hook\n */\nfunction useTheme(): readonly [Theme, UpdateTheme] {\n // Initial theme value is based on the value saved in local storage or the system theme\n const [theme, setTheme] = useState<Theme>(() => {\n if (!isBrowser()) {\n return DEFAULT_THEME;\n }\n const savedTheme = window.localStorage.getItem(THEME_KEY);\n let initialTheme: Theme;\n if (savedTheme === 'dark' || savedTheme === 'light') {\n initialTheme = savedTheme;\n } else {\n initialTheme = window.matchMedia(SYS_DARK_MEDIA_QUERY).matches ? 'dark' : 'light';\n }\n document.documentElement.setAttribute(THEME_ATTRIBUTE, initialTheme);\n return initialTheme;\n });\n\n useEffect(() => {\n const observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n if (mutation.attributeName === THEME_ATTRIBUTE) {\n const updatedTheme = (mutation.target as HTMLHtmlElement).getAttribute(THEME_ATTRIBUTE);\n if (updatedTheme === 'light' || updatedTheme === 'dark') {\n window.localStorage.setItem(THEME_KEY, updatedTheme);\n setTheme(updatedTheme);\n } else {\n console.error(`Unexpected value for 'data-mode' attribute: ${updatedTheme}`);\n }\n }\n });\n });\n observer.observe(document.documentElement, {\n attributes: true\n });\n return () => observer.disconnect();\n }, []);\n\n // When the user wants to change the theme\n const updateTheme = (theme: Theme) => {\n document.documentElement.setAttribute(THEME_ATTRIBUTE, theme);\n };\n\n return [theme, updateTheme] as const;\n}\n\nexport { DEFAULT_THEME, SYS_DARK_MEDIA_QUERY, type Theme, THEME_ATTRIBUTE, THEME_KEY, useTheme };\n","import { useCallback } from 'react';\n\nimport { useStore } from 'zustand';\n\nimport { translationStore } from '@/i18n';\nimport type { TranslateFunction, TranslationNamespace } from '@/i18n';\nimport { getTranslation } from '@/i18n/internal';\n\nexport function useTranslation<TNamespace extends TranslationNamespace | undefined = undefined>(\n namespace?: TNamespace\n) {\n const changeLanguage = useStore(translationStore, (store) => store.changeLanguage);\n const fallbackLanguage = useStore(translationStore, (store) => store.fallbackLanguage);\n const resolvedLanguage = useStore(translationStore, (store) => store.resolvedLanguage);\n const translations = useStore(translationStore, (store) => {\n if (namespace) {\n return store.translations[namespace];\n }\n return store.translations;\n });\n\n const t: TranslateFunction<TNamespace> = useCallback(\n (target, ...args) => {\n return getTranslation(target, { fallbackLanguage, resolvedLanguage, translations }, ...args);\n },\n [fallbackLanguage, resolvedLanguage, translations]\n );\n\n return { changeLanguage, resolvedLanguage, t };\n}\n","import { useState } from 'react';\n\nimport { useEventListener } from '../useEventListener';\nimport { useIsomorphicLayoutEffect } from '../useIsomorphicLayoutEffect';\n\nexport type WindowSize = {\n height: number;\n width: number;\n};\n\nexport function useWindowSize(): WindowSize {\n const [windowSize, setWindowSize] = useState<WindowSize>({\n height: 0,\n width: 0\n });\n\n const handleSize = () => {\n setWindowSize({\n height: window.innerHeight,\n width: window.innerWidth\n });\n };\n\n useEventListener('resize', handleSize);\n\n // Set size at the first client-side load\n useIsomorphicLayoutEffect(() => {\n handleSize();\n }, []);\n\n return windowSize;\n}\n"],"mappings":"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","names":["useEffect","useEffect","useEffect","useRef","useRef","useEffect","useEffect","useRef","useRef","useEffect","useEffect","useState","query","useState","useEffect","useCallback","useEffect","useState","useCallback","useState","useEffect","useEffect","useState","useState","useEffect","theme","useCallback","useCallback","useState","useState"]}
|
package/dist/components.d.ts
CHANGED
|
@@ -1344,8 +1344,11 @@ declare const Resizable: ResizableType;
|
|
|
1344
1344
|
declare const ScrollArea: React$1.ForwardRefExoticComponent<Omit<_radix_ui_react_scroll_area.ScrollAreaProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
1345
1345
|
|
|
1346
1346
|
type BaseSearchBarProps = {
|
|
1347
|
+
[key: `data-${string}`]: unknown;
|
|
1347
1348
|
/** Additional CSS classes to add to the wrapper form component, potentially overriding default styling */
|
|
1348
1349
|
className?: string;
|
|
1350
|
+
/** The ID to pass to the HTMLFormElement */
|
|
1351
|
+
id?: string;
|
|
1349
1352
|
/** An optional callback invoked when the user clicks the search bar */
|
|
1350
1353
|
onClick?: () => void;
|
|
1351
1354
|
/** Custom placeholder to use instead of the default */
|
|
@@ -1364,7 +1367,7 @@ type UncontrolledSearchBarProps = {
|
|
|
1364
1367
|
value?: never;
|
|
1365
1368
|
} & BaseSearchBarProps;
|
|
1366
1369
|
type SearchBarProps = ControlledSearchBarProps | UncontrolledSearchBarProps;
|
|
1367
|
-
declare const SearchBar: ({ className, onClick, onValueChange, placeholder, readOnly, value }: SearchBarProps) => react_jsx_runtime.JSX.Element;
|
|
1370
|
+
declare const SearchBar: ({ className, onClick, onValueChange, placeholder, readOnly, value, ...props }: SearchBarProps) => react_jsx_runtime.JSX.Element;
|
|
1368
1371
|
|
|
1369
1372
|
declare const Select: React$1.FC<SelectPrimitive.SelectProps> & {
|
|
1370
1373
|
Content: React$1.ForwardRefExoticComponent<Omit<SelectPrimitive.SelectContentProps & React$1.RefAttributes<HTMLDivElement>, "ref"> & React$1.RefAttributes<HTMLDivElement>>;
|
|
@@ -1402,12 +1405,13 @@ declare const Spinner: ({ className, ...props }: HTMLProps<HTMLDivElement>) => r
|
|
|
1402
1405
|
declare const SpinnerIcon: ({ className, ...props }: React$1.HTMLAttributes<SVGElement>) => react_jsx_runtime.JSX.Element;
|
|
1403
1406
|
|
|
1404
1407
|
type StatisticCardProps = {
|
|
1408
|
+
[key: `data-${string}`]: unknown;
|
|
1405
1409
|
className?: string;
|
|
1406
1410
|
icon?: JSX.Element;
|
|
1407
1411
|
label: string;
|
|
1408
1412
|
value: number;
|
|
1409
1413
|
};
|
|
1410
|
-
declare const StatisticCard: ({ className, icon, label, value }: StatisticCardProps) => react_jsx_runtime.JSX.Element;
|
|
1414
|
+
declare const StatisticCard: ({ className, icon, label, value, ...props }: StatisticCardProps) => react_jsx_runtime.JSX.Element;
|
|
1411
1415
|
|
|
1412
1416
|
declare const Switch: React$1.ForwardRefExoticComponent<Omit<SwitchPrimitives.SwitchProps & React$1.RefAttributes<HTMLButtonElement>, "ref"> & React$1.RefAttributes<HTMLButtonElement>>;
|
|
1413
1417
|
|
package/dist/components.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
useNotificationsStore,
|
|
3
3
|
useTheme,
|
|
4
4
|
useTranslation
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-AFNJZUOE.js";
|
|
6
6
|
import "./chunk-53GZFQK3.js";
|
|
7
7
|
import {
|
|
8
8
|
cn
|
|
@@ -3879,9 +3879,17 @@ var Resizable = Object.assign(ResizableRoot, {
|
|
|
3879
3879
|
// src/components/SearchBar/SearchBar.tsx
|
|
3880
3880
|
import { SearchIcon as SearchIcon2 } from "lucide-react";
|
|
3881
3881
|
import { jsx as jsx160, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
3882
|
-
var SearchBar = ({
|
|
3882
|
+
var SearchBar = ({
|
|
3883
|
+
className,
|
|
3884
|
+
onClick,
|
|
3885
|
+
onValueChange,
|
|
3886
|
+
placeholder,
|
|
3887
|
+
readOnly,
|
|
3888
|
+
value,
|
|
3889
|
+
...props
|
|
3890
|
+
}) => {
|
|
3883
3891
|
const { t } = useTranslation("libui");
|
|
3884
|
-
return /* @__PURE__ */ jsxs54("form", { className: cn("relative", className), children: [
|
|
3892
|
+
return /* @__PURE__ */ jsxs54("form", { className: cn("relative", className), ...props, children: [
|
|
3885
3893
|
/* @__PURE__ */ jsx160(SearchIcon2, { className: "absolute left-2 top-2.5 h-4 w-4 text-muted-foreground" }),
|
|
3886
3894
|
/* @__PURE__ */ jsx160(
|
|
3887
3895
|
Input,
|
|
@@ -4075,13 +4083,13 @@ var SpinnerIcon = ({ className, ...props }) => /* @__PURE__ */ jsx170(
|
|
|
4075
4083
|
import { useEffect as useEffect10 } from "react";
|
|
4076
4084
|
import { motion as motion6, useSpring, useTransform } from "framer-motion";
|
|
4077
4085
|
import { jsx as jsx171, jsxs as jsxs56 } from "react/jsx-runtime";
|
|
4078
|
-
var StatisticCard = ({ className, icon, label, value }) => {
|
|
4086
|
+
var StatisticCard = ({ className, icon, label, value, ...props }) => {
|
|
4079
4087
|
const spring = useSpring(0, { bounce: 0 });
|
|
4080
4088
|
const rounded = useTransform(spring, (latest) => Math.floor(latest));
|
|
4081
4089
|
useEffect10(() => {
|
|
4082
4090
|
spring.set(value);
|
|
4083
4091
|
}, [spring, value]);
|
|
4084
|
-
return /* @__PURE__ */ jsxs56(Card, { className: cn("flex w-full rounded-lg p-4", className), children: [
|
|
4092
|
+
return /* @__PURE__ */ jsxs56(Card, { className: cn("flex w-full rounded-lg p-4", className), ...props, children: [
|
|
4085
4093
|
icon && /* @__PURE__ */ jsx171("div", { className: "mr-2 flex items-center justify-center text-4xl", children: icon }),
|
|
4086
4094
|
/* @__PURE__ */ jsxs56("div", { className: "w-full text-center", children: [
|
|
4087
4095
|
/* @__PURE__ */ jsx171(motion6.h3, { className: "title-font text-2xl font-semibold text-slate-900 dark:text-slate-100 sm:text-3xl", children: rounded }),
|