@fuego-systems/react 0.1.7 → 0.1.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceAutocomplete.js","sourceRoot":"","sources":["../../src/search/ServiceAutocomplete.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Autocomplete, AutocompleteProps, Badge, Box, Group, Loader, Text } from '@mantine/core'\nimport { useDebouncedValue } from '@mantine/hooks'\nimport { JSX, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nexport interface ServiceAutocompleteProps<T>\n extends Omit<AutocompleteProps, 'data' | 'value' | 'defaultValue' | 'onChange' | 'onOptionSubmit' | 'renderOption'> {\n /** Search function called with the debounced query string. */\n readonly searchFn: (query: string) => Promise<T[]>\n /** Extract a unique identifier from each result. */\n readonly getId: (item: T) => string\n /** Extract the display label from each result. */\n readonly getLabel: (item: T) => string\n /** Optional: extract a short code shown as a badge next to the label. */\n readonly getCode?: (item: T) => string\n /** Optional: custom render function for each option row. */\n readonly renderOption?: (item: T) => ReactNode\n /** Currently selected value (controlled). */\n readonly value?: T\n /** Called when the user selects or clears a value. */\n readonly onChange: (item: T | undefined) => void\n readonly placeholder?: string\n /** Minimum characters before triggering a search. @default 2 */\n readonly minQueryLength?: number\n /** Debounce delay in ms. @default 250 */\n readonly debounceMs?: number\n}\n\nexport function ServiceAutocomplete<T> (props: ServiceAutocompleteProps<T>): JSX.Element {\n const {\n searchFn,\n getId,\n getLabel,\n getCode,\n renderOption: customRenderOption,\n value,\n onChange,\n placeholder = 'Buscar...',\n minQueryLength = 2,\n debounceMs = 250,\n clearable = true,\n rightSection,\n ...inputProps\n } = props\n\n const [query, setQuery] = useState<string>(value ? getLabel(value) : '')\n const [debounced] = useDebouncedValue(query, debounceMs)\n const [loading, setLoading] = useState(false)\n const [results, setResults] = useState<T[]>([])\n const lastSelectedIdRef = useRef<string | undefined>(value ? getId(value) : undefined)\n\n // Keep displayed text in sync when the controlled value changes externally.\n useEffect(() => {\n const currentId = value ? getId(value) : undefined\n if (currentId !== lastSelectedIdRef.current) {\n lastSelectedIdRef.current = currentId\n setQuery(value ? getLabel(value) : '')\n }\n }, [value, getId, getLabel])\n\n // Fetch search results whenever the debounced query changes.\n useEffect(() => {\n let cancelled = false\n\n async function run (): Promise<void> {\n const q = debounced.trim()\n if (q.length < minQueryLength) {\n setResults([])\n setLoading(false)\n return\n }\n setLoading(true)\n try {\n const list = await searchFn(q)\n if (!cancelled) {\n setResults(Array.isArray(list) ? list : [])\n }\n } catch (err) {\n if (!cancelled) {\n console.error('[ServiceAutocomplete]', err)\n setResults([])\n }\n } finally {\n if (!cancelled) {\n setLoading(false)\n }\n }\n }\n\n run().catch(console.error)\n return () => {\n cancelled = true\n }\n }, [debounced, searchFn, minQueryLength])\n\n // Build the string options and the id → item lookup map.\n const { data, optionsById } = useMemo(() => {\n const data: string[] = []\n const optionsById = new Map<string, T>()\n\n for (const item of results ?? []) {\n const id = getId(item)\n if (!id) {continue}\n data.push(id)\n optionsById.set(id, item)\n }\n\n return { data, optionsById }\n }, [results, getId])\n\n const handleOptionSubmit = useCallback((id: string): void => {\n const chosen = optionsById.get(id)\n if (chosen) {\n lastSelectedIdRef.current = getId(chosen)\n onChange(chosen)\n setQuery(getLabel(chosen))\n }\n }, [optionsById, getId, getLabel, onChange])\n\n const handleClear = useCallback((): void => {\n onChange(undefined)\n setQuery('')\n }, [onChange])\n\n const handleBlur = useCallback((): void => {\n setQuery(value ? getLabel(value) : '')\n }, [value, getLabel])\n\n return (\n <Autocomplete\n {...inputProps}\n value={query}\n placeholder={placeholder}\n data={Array.isArray(data) ? data : []}\n onChange={setQuery}\n onOptionSubmit={handleOptionSubmit}\n renderOption={({ option }) => {\n const item = optionsById.get(option.value)\n if (!item) {return <Text size=\"sm\">{option.value}</Text>}\n\n if (customRenderOption) {\n return <>{customRenderOption(item)}</>\n }\n\n const label = getLabel(item)\n const code = getCode?.(item) ?? ''\n return (\n <Group gap=\"xs\" wrap=\"nowrap\" style={{ width: '100%' }}>\n <Box style={{ flex: 1, minWidth: 0 }}>\n <Text size=\"sm\" fw={500} truncate>{label}</Text>\n </Box>\n {code && (\n <Badge size=\"xs\" variant=\"light\" color=\"blue\" style={{ flexShrink: 0 }}>\n {code}\n </Badge>\n )}\n </Group>\n )\n }}\n onBlur={(event) => {\n inputProps.onBlur?.(event)\n handleBlur()\n }}\n clearable={clearable}\n onClear={() => {\n inputProps.onClear?.()\n handleClear()\n }}\n filter={({ options }) => options}\n rightSection={loading ? <Loader size=\"xs\"/> : rightSection}\n rightSectionPointerEvents={loading ? 'none' : inputProps.rightSectionPointerEvents}\n />\n )\n}\n"]}
1
+ {"version":3,"file":"ServiceAutocomplete.js","sourceRoot":"","sources":["../../src/search/ServiceAutocomplete.tsx"],"names":[],"mappings":"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","sourcesContent":["import { Autocomplete, AutocompleteProps, Badge, Box, Group, Loader, Text } from '@mantine/core'\nimport { useDebouncedValue } from '@mantine/hooks'\nimport { JSX, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nexport interface ServiceAutocompleteProps<T>\n extends Omit<AutocompleteProps, 'data' | 'value' | 'defaultValue' | 'onChange' | 'onOptionSubmit' | 'renderOption'> {\n /** Search function called with the debounced query string. */\n readonly searchFn: (query: string) => Promise<T[]>\n /** Extract a unique identifier from each result. */\n readonly getId: (item: T) => string\n /** Extract the display label from each result. */\n readonly getLabel: (item: T) => string\n /** Optional: extract a short code shown as a badge next to the label. */\n readonly getCode?: (item: T) => string\n /** Optional: custom render function for each option row. */\n readonly renderOption?: (item: T) => ReactNode\n /** Currently selected value (controlled). */\n readonly value?: T\n /** Called when the user selects or clears a value. */\n readonly onChange: (item: T | undefined) => void\n readonly placeholder?: string\n /** Minimum characters before triggering a search. @default 2 */\n readonly minQueryLength?: number\n /** Debounce delay in ms. @default 250 */\n readonly debounceMs?: number\n}\n\nexport function ServiceAutocomplete<T> (props: ServiceAutocompleteProps<T>): JSX.Element {\n const {\n searchFn,\n getId,\n getLabel,\n getCode,\n renderOption: customRenderOption,\n value,\n onChange,\n placeholder = 'Buscar...',\n minQueryLength = 2,\n debounceMs = 250,\n clearable = true,\n rightSection,\n ...inputProps\n } = props\n\n const [query, setQuery] = useState(value ? getLabel(value) : '')\n const [debounced] = useDebouncedValue(query, debounceMs)\n const [loading, setLoading] = useState(false)\n const [results, setResults] = useState<T[]>([])\n const lastSelectedIdRef = useRef(value ? getId(value) : undefined)\n\n // Keep displayed text in sync when the controlled value changes externally.\n useEffect(() => {\n const currentId = value ? getId(value) : undefined\n if (currentId !== lastSelectedIdRef.current) {\n lastSelectedIdRef.current = currentId\n setQuery(value ? getLabel(value) : '')\n }\n }, [value, getId, getLabel])\n\n // Fetch search results whenever the debounced query changes.\n useEffect(() => {\n let cancelled = false\n\n async function run (): Promise<void> {\n const q = debounced.trim()\n if (q.length < minQueryLength) {\n setResults([])\n setLoading(false)\n return\n }\n setLoading(true)\n try {\n const list = await searchFn(q)\n if (!cancelled) {\n setResults(Array.isArray(list) ? list : [])\n }\n } catch (err) {\n if (!cancelled) {\n console.error('[ServiceAutocomplete]', err)\n setResults([])\n }\n } finally {\n if (!cancelled) {\n setLoading(false)\n }\n }\n }\n\n run().catch(console.error)\n return () => {\n cancelled = true\n }\n }, [debounced, searchFn, minQueryLength])\n\n // Build the string options and the id → item lookup map.\n const { data, optionsById } = useMemo(() => {\n const data: string[] = []\n const optionsById = new Map<string, T>()\n\n for (const item of results ?? []) {\n const id = getId(item)\n if (!id) {continue}\n data.push(id)\n optionsById.set(id, item)\n }\n\n return { data, optionsById }\n }, [results, getId])\n\n const handleOptionSubmit = useCallback((id: string): void => {\n const chosen = optionsById.get(id)\n if (chosen) {\n lastSelectedIdRef.current = getId(chosen)\n onChange(chosen)\n setQuery(getLabel(chosen))\n }\n }, [optionsById, getId, getLabel, onChange])\n\n const handleClear = useCallback((): void => {\n onChange(undefined)\n setQuery('')\n }, [onChange])\n\n const handleBlur = useCallback((): void => {\n setQuery(value ? getLabel(value) : '')\n }, [value, getLabel])\n\n return (\n <Autocomplete\n {...inputProps}\n value={query}\n placeholder={placeholder}\n data={Array.isArray(data) ? data : []}\n onChange={setQuery}\n onOptionSubmit={handleOptionSubmit}\n renderOption={({ option }) => {\n const item = optionsById.get(option.value)\n if (!item) {return <Text size=\"sm\">{option.value}</Text>}\n\n if (customRenderOption) {\n return <>{customRenderOption(item)}</>\n }\n\n const label = getLabel(item)\n const code = getCode?.(item) ?? ''\n return (\n <Group gap=\"xs\" wrap=\"nowrap\" style={{ width: '100%' }}>\n <Box style={{ flex: 1, minWidth: 0 }}>\n <Text size=\"sm\" fw={500} truncate>{label}</Text>\n </Box>\n {code && (\n <Badge size=\"xs\" variant=\"light\" color=\"blue\" style={{ flexShrink: 0 }}>\n {code}\n </Badge>\n )}\n </Group>\n )\n }}\n onBlur={(event) => {\n inputProps.onBlur?.(event)\n handleBlur()\n }}\n clearable={clearable}\n onClear={() => {\n inputProps.onClear?.()\n handleClear()\n }}\n filter={({ options }) => options}\n rightSection={loading ? <Loader size=\"xs\"/> : rightSection}\n rightSectionPointerEvents={loading ? 'none' : inputProps.rightSectionPointerEvents}\n />\n )\n}\n"]}