periplo-ui 4.2.1 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/components/Combobox/Combobox.d.ts +6 -42
  2. package/dist/components/Combobox/Combobox.js +25 -54
  3. package/dist/components/Combobox/Combobox.js.map +1 -1
  4. package/dist/components/Combobox/ComboboxTrigger.d.ts +14 -0
  5. package/dist/components/Combobox/ComboboxTrigger.js +74 -0
  6. package/dist/components/Combobox/ComboboxTrigger.js.map +1 -0
  7. package/dist/components/Combobox/StaticComboboxList.js +1 -1
  8. package/dist/components/Combobox/StaticComboboxList.js.map +1 -1
  9. package/dist/components/Combobox/VirtualizedComboboxList.js +1 -1
  10. package/dist/components/Combobox/VirtualizedComboboxList.js.map +1 -1
  11. package/dist/components/Combobox/hooks/index.d.ts +6 -0
  12. package/dist/components/Combobox/hooks/index.js +7 -0
  13. package/dist/components/Combobox/hooks/index.js.map +1 -0
  14. package/dist/components/Combobox/hooks/useComboboxOpenState.d.ts +7 -0
  15. package/dist/components/Combobox/hooks/useComboboxOpenState.js +18 -0
  16. package/dist/components/Combobox/hooks/useComboboxOpenState.js.map +1 -0
  17. package/dist/components/Combobox/hooks/useComboboxSelection.d.ts +7 -0
  18. package/dist/components/Combobox/hooks/useComboboxSelection.js +49 -0
  19. package/dist/components/Combobox/hooks/useComboboxSelection.js.map +1 -0
  20. package/dist/components/Combobox/hooks/useDebouncedState.d.ts +5 -0
  21. package/dist/components/Combobox/hooks/useDebouncedState.js +19 -0
  22. package/dist/components/Combobox/hooks/useDebouncedState.js.map +1 -0
  23. package/dist/components/Combobox/hooks/useDisplayValue.d.ts +11 -0
  24. package/dist/components/Combobox/hooks/useDisplayValue.js +32 -0
  25. package/dist/components/Combobox/hooks/useDisplayValue.js.map +1 -0
  26. package/dist/components/Combobox/hooks/usePaginatedOptions.d.ts +24 -0
  27. package/dist/components/Combobox/hooks/usePaginatedOptions.js +54 -0
  28. package/dist/components/Combobox/hooks/usePaginatedOptions.js.map +1 -0
  29. package/dist/components/Combobox/hooks/useSelectedCache.d.ts +4 -0
  30. package/dist/components/Combobox/hooks/useSelectedCache.js +17 -0
  31. package/dist/components/Combobox/hooks/useSelectedCache.js.map +1 -0
  32. package/dist/components/Combobox/useCombobox.d.ts +3 -3
  33. package/dist/components/Combobox/useCombobox.js +25 -158
  34. package/dist/components/Combobox/useCombobox.js.map +1 -1
  35. package/dist/components/Tooltip/Tooltip.d.ts +7 -1
  36. package/dist/components/Tooltip/Tooltip.js +31 -24
  37. package/dist/components/Tooltip/Tooltip.js.map +1 -1
  38. package/dist/components/Tooltip/index.js +1 -1
  39. package/dist/index.js +1 -1
  40. package/package.json +1 -1
@@ -0,0 +1,11 @@
1
+ import { ComboboxProps } from '../Combobox';
2
+ type UseDisplayValueParams<T extends object> = {
3
+ props: ComboboxProps<T>;
4
+ localOptions: Array<T>;
5
+ isVirtualized: boolean;
6
+ resolve: (value: string) => T | undefined;
7
+ recordOptions: (items: Iterable<T>) => void;
8
+ handleRemove: (value: string) => void;
9
+ };
10
+ export declare function useDisplayValue<T extends object>({ props, localOptions, isVirtualized, resolve, recordOptions, handleRemove, }: UseDisplayValueParams<T>): import('react').ReactNode;
11
+ export {};
@@ -0,0 +1,32 @@
1
+ import { useMemo } from 'react';
2
+
3
+ function useDisplayValue({
4
+ props,
5
+ localOptions,
6
+ isVirtualized,
7
+ resolve,
8
+ recordOptions,
9
+ handleRemove
10
+ }) {
11
+ const { options, getOptionValue, getOptionLabel, placeholder = "Select...", multiple, specialOptions } = props;
12
+ return useMemo(() => {
13
+ const available = isVirtualized ? localOptions : options;
14
+ const all = specialOptions ? [...specialOptions, ...available] : available;
15
+ recordOptions(all);
16
+ const lookup = (val) => all.find((option) => getOptionValue(option) === val) ?? resolve(val);
17
+ if (multiple) {
18
+ const { renderLabel: renderLabel2 } = props;
19
+ const value2 = Array.isArray(props.value) ? props.value : [];
20
+ if (value2.length === 0) return placeholder;
21
+ const selected2 = value2.map(lookup).filter((option) => option !== void 0);
22
+ return renderLabel2 ? renderLabel2(selected2, handleRemove) : selected2.map(getOptionLabel).join(", ");
23
+ }
24
+ const { value, renderLabel } = props;
25
+ const selected = value ? lookup(value) : void 0;
26
+ if (renderLabel && selected) return renderLabel(selected);
27
+ return selected ? getOptionLabel(selected) : placeholder;
28
+ }, [props, localOptions, isVirtualized, getOptionLabel, getOptionValue, placeholder, multiple, specialOptions]);
29
+ }
30
+
31
+ export { useDisplayValue };
32
+ //# sourceMappingURL=useDisplayValue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDisplayValue.js","sources":["../../../../src/components/Combobox/hooks/useDisplayValue.ts"],"sourcesContent":["import { useMemo } from 'react'\n\nimport type { ComboboxProps } from '../Combobox'\n\ntype UseDisplayValueParams<T extends object> = {\n props: ComboboxProps<T>\n localOptions: Array<T>\n isVirtualized: boolean\n resolve: (value: string) => T | undefined\n recordOptions: (items: Iterable<T>) => void\n handleRemove: (value: string) => void\n}\n\nexport function useDisplayValue<T extends object>({\n props,\n localOptions,\n isVirtualized,\n resolve,\n recordOptions,\n handleRemove,\n}: UseDisplayValueParams<T>) {\n const { options, getOptionValue, getOptionLabel, placeholder = 'Select...', multiple, specialOptions } = props\n\n return useMemo(() => {\n const available = isVirtualized ? localOptions : options\n const all = specialOptions ? [...specialOptions, ...available] : available\n recordOptions(all)\n\n const lookup = (val: string) => all.find((option) => getOptionValue(option) === val) ?? resolve(val)\n\n if (multiple) {\n const { renderLabel } = props\n const value = Array.isArray(props.value) ? props.value : []\n if (value.length === 0) return placeholder\n\n const selected = value.map(lookup).filter((option): option is T => option !== undefined)\n\n return renderLabel ? renderLabel(selected, handleRemove) : selected.map(getOptionLabel).join(', ')\n }\n\n const { value, renderLabel } = props\n const selected = value ? lookup(value) : undefined\n if (renderLabel && selected) return renderLabel(selected)\n return selected ? getOptionLabel(selected) : placeholder\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [props, localOptions, isVirtualized, getOptionLabel, getOptionValue, placeholder, multiple, specialOptions])\n}\n"],"names":["renderLabel","value","selected"],"mappings":";;AAaO,SAAS,eAAA,CAAkC;AAAA,EAChD,KAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,OAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF,CAAA,EAA6B;AAC3B,EAAA,MAAM,EAAE,SAAS,cAAA,EAAgB,cAAA,EAAgB,cAAc,WAAA,EAAa,QAAA,EAAU,gBAAe,GAAI,KAAA;AAEzG,EAAA,OAAO,QAAQ,MAAM;AACnB,IAAA,MAAM,SAAA,GAAY,gBAAgB,YAAA,GAAe,OAAA;AACjD,IAAA,MAAM,MAAM,cAAA,GAAiB,CAAC,GAAG,cAAA,EAAgB,GAAG,SAAS,CAAA,GAAI,SAAA;AACjE,IAAA,aAAA,CAAc,GAAG,CAAA;AAEjB,IAAA,MAAM,MAAA,GAAS,CAAC,GAAA,KAAgB,GAAA,CAAI,IAAA,CAAK,CAAC,MAAA,KAAW,cAAA,CAAe,MAAM,CAAA,KAAM,GAAG,CAAA,IAAK,QAAQ,GAAG,CAAA;AAEnG,IAAA,IAAI,QAAA,EAAU;AACZ,MAAA,MAAM,EAAE,WAAA,EAAAA,YAAAA,EAAY,GAAI,KAAA;AACxB,MAAA,MAAMC,MAAAA,GAAQ,MAAM,OAAA,CAAQ,KAAA,CAAM,KAAK,CAAA,GAAI,KAAA,CAAM,QAAQ,EAAC;AAC1D,MAAA,IAAIA,MAAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,WAAA;AAE/B,MAAA,MAAMC,SAAAA,GAAWD,OAAM,GAAA,CAAI,MAAM,EAAE,MAAA,CAAO,CAAC,MAAA,KAAwB,MAAA,KAAW,MAAS,CAAA;AAEvF,MAAA,OAAOD,YAAAA,GAAcA,YAAAA,CAAYE,SAAAA,EAAU,YAAY,CAAA,GAAIA,UAAS,GAAA,CAAI,cAAc,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA;AAAA,IACnG;AAEA,IAAA,MAAM,EAAE,KAAA,EAAO,WAAA,EAAY,GAAI,KAAA;AAC/B,IAAA,MAAM,QAAA,GAAW,KAAA,GAAQ,MAAA,CAAO,KAAK,CAAA,GAAI,MAAA;AACzC,IAAA,IAAI,WAAA,IAAe,QAAA,EAAU,OAAO,WAAA,CAAY,QAAQ,CAAA;AACxD,IAAA,OAAO,QAAA,GAAW,cAAA,CAAe,QAAQ,CAAA,GAAI,WAAA;AAAA,EAE/C,CAAA,EAAG,CAAC,KAAA,EAAO,YAAA,EAAc,aAAA,EAAe,gBAAgB,cAAA,EAAgB,WAAA,EAAa,QAAA,EAAU,cAAc,CAAC,CAAA;AAChH;;;;"}
@@ -0,0 +1,24 @@
1
+ type FetchPageResult<T> = {
2
+ items: Array<T>;
3
+ hasNextPage: boolean;
4
+ nextPage: number;
5
+ };
6
+ type FetchPage<T> = (params: {
7
+ page: number;
8
+ search?: string;
9
+ }) => Promise<FetchPageResult<T>>;
10
+ type UsePaginatedOptionsParams<T> = {
11
+ fetchPage?: FetchPage<T>;
12
+ debouncedSearchTerm: string;
13
+ open: boolean;
14
+ prefetch?: boolean;
15
+ loading: boolean;
16
+ onItemsLoaded: (items: Array<T>) => void;
17
+ };
18
+ export declare function usePaginatedOptions<T>({ fetchPage, debouncedSearchTerm, open, prefetch, loading, onItemsLoaded, }: UsePaginatedOptionsParams<T>): {
19
+ localOptions: T[];
20
+ hasNextPage: boolean;
21
+ loadingMore: boolean;
22
+ loadNextPage: () => Promise<void>;
23
+ };
24
+ export {};
@@ -0,0 +1,54 @@
1
+ import { useState, useRef, useEffect } from 'react';
2
+
3
+ function usePaginatedOptions({
4
+ fetchPage,
5
+ debouncedSearchTerm,
6
+ open,
7
+ prefetch,
8
+ loading,
9
+ onItemsLoaded
10
+ }) {
11
+ const enabled = !!fetchPage;
12
+ const [page, setPage] = useState(1);
13
+ const [localOptions, setLocalOptions] = useState([]);
14
+ const [hasNextPage, setHasNextPage] = useState(true);
15
+ const [loadingMore, setLoadingMore] = useState(false);
16
+ const loadStateRef = useRef({ token: 0, inFlight: false });
17
+ useEffect(() => {
18
+ if (!enabled) return;
19
+ loadStateRef.current.token++;
20
+ loadStateRef.current.inFlight = false;
21
+ setPage(1);
22
+ setLocalOptions([]);
23
+ setHasNextPage(true);
24
+ setLoadingMore(false);
25
+ }, [debouncedSearchTerm, enabled]);
26
+ const loadNextPage = async () => {
27
+ if (!fetchPage || loadStateRef.current.inFlight || !hasNextPage || loading) return;
28
+ loadStateRef.current.inFlight = true;
29
+ const token = loadStateRef.current.token;
30
+ setLoadingMore(true);
31
+ try {
32
+ const result = await fetchPage({ page, search: debouncedSearchTerm || void 0 });
33
+ if (token !== loadStateRef.current.token) return;
34
+ onItemsLoaded(result.items);
35
+ setLocalOptions((prev) => [...prev, ...result.items]);
36
+ setPage(result.nextPage);
37
+ setHasNextPage(result.hasNextPage);
38
+ } finally {
39
+ if (token === loadStateRef.current.token) {
40
+ loadStateRef.current.inFlight = false;
41
+ setLoadingMore(false);
42
+ }
43
+ }
44
+ };
45
+ useEffect(() => {
46
+ if (enabled && (open || prefetch) && localOptions.length === 0 && !loading && !loadingMore) {
47
+ loadNextPage();
48
+ }
49
+ }, [enabled, open, prefetch, localOptions.length, loading, loadingMore, debouncedSearchTerm]);
50
+ return { localOptions, hasNextPage, loadingMore, loadNextPage };
51
+ }
52
+
53
+ export { usePaginatedOptions };
54
+ //# sourceMappingURL=usePaginatedOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePaginatedOptions.js","sources":["../../../../src/components/Combobox/hooks/usePaginatedOptions.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react'\n\ntype FetchPageResult<T> = { items: Array<T>; hasNextPage: boolean; nextPage: number }\n\ntype FetchPage<T> = (params: { page: number; search?: string }) => Promise<FetchPageResult<T>>\n\ntype UsePaginatedOptionsParams<T> = {\n fetchPage?: FetchPage<T>\n debouncedSearchTerm: string\n open: boolean\n prefetch?: boolean\n loading: boolean\n onItemsLoaded: (items: Array<T>) => void\n}\n\nexport function usePaginatedOptions<T>({\n fetchPage,\n debouncedSearchTerm,\n open,\n prefetch,\n loading,\n onItemsLoaded,\n}: UsePaginatedOptionsParams<T>) {\n const enabled = !!fetchPage\n const [page, setPage] = useState(1)\n const [localOptions, setLocalOptions] = useState<Array<T>>([])\n const [hasNextPage, setHasNextPage] = useState(true)\n const [loadingMore, setLoadingMore] = useState(false)\n const loadStateRef = useRef({ token: 0, inFlight: false })\n\n useEffect(() => {\n if (!enabled) return\n loadStateRef.current.token++\n loadStateRef.current.inFlight = false\n setPage(1)\n setLocalOptions([])\n setHasNextPage(true)\n setLoadingMore(false)\n }, [debouncedSearchTerm, enabled])\n\n const loadNextPage = async () => {\n if (!fetchPage || loadStateRef.current.inFlight || !hasNextPage || loading) return\n\n loadStateRef.current.inFlight = true\n const token = loadStateRef.current.token\n setLoadingMore(true)\n try {\n const result = await fetchPage({ page, search: debouncedSearchTerm || undefined })\n if (token !== loadStateRef.current.token) return\n onItemsLoaded(result.items)\n setLocalOptions((prev) => [...prev, ...result.items])\n setPage(result.nextPage)\n setHasNextPage(result.hasNextPage)\n } finally {\n if (token === loadStateRef.current.token) {\n loadStateRef.current.inFlight = false\n setLoadingMore(false)\n }\n }\n }\n\n useEffect(() => {\n if (enabled && (open || prefetch) && localOptions.length === 0 && !loading && !loadingMore) {\n loadNextPage()\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, open, prefetch, localOptions.length, loading, loadingMore, debouncedSearchTerm])\n\n return { localOptions, hasNextPage, loadingMore, loadNextPage }\n}\n"],"names":[],"mappings":";;AAeO,SAAS,mBAAA,CAAuB;AAAA,EACrC,SAAA;AAAA,EACA,mBAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAiC;AAC/B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,SAAA;AAClB,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,SAAS,CAAC,CAAA;AAClC,EAAA,MAAM,CAAC,YAAA,EAAc,eAAe,CAAA,GAAI,QAAA,CAAmB,EAAE,CAAA;AAC7D,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,IAAI,CAAA;AACnD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAS,KAAK,CAAA;AACpD,EAAA,MAAM,eAAe,MAAA,CAAO,EAAE,OAAO,CAAA,EAAG,QAAA,EAAU,OAAO,CAAA;AAEzD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,OAAA,EAAS;AACd,IAAA,YAAA,CAAa,OAAA,CAAQ,KAAA,EAAA;AACrB,IAAA,YAAA,CAAa,QAAQ,QAAA,GAAW,KAAA;AAChC,IAAA,OAAA,CAAQ,CAAC,CAAA;AACT,IAAA,eAAA,CAAgB,EAAE,CAAA;AAClB,IAAA,cAAA,CAAe,IAAI,CAAA;AACnB,IAAA,cAAA,CAAe,KAAK,CAAA;AAAA,EACtB,CAAA,EAAG,CAAC,mBAAA,EAAqB,OAAO,CAAC,CAAA;AAEjC,EAAA,MAAM,eAAe,YAAY;AAC/B,IAAA,IAAI,CAAC,SAAA,IAAa,YAAA,CAAa,QAAQ,QAAA,IAAY,CAAC,eAAe,OAAA,EAAS;AAE5E,IAAA,YAAA,CAAa,QAAQ,QAAA,GAAW,IAAA;AAChC,IAAA,MAAM,KAAA,GAAQ,aAAa,OAAA,CAAQ,KAAA;AACnC,IAAA,cAAA,CAAe,IAAI,CAAA;AACnB,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,SAAA,CAAU,EAAE,MAAM,MAAA,EAAQ,mBAAA,IAAuB,QAAW,CAAA;AACjF,MAAA,IAAI,KAAA,KAAU,YAAA,CAAa,OAAA,CAAQ,KAAA,EAAO;AAC1C,MAAA,aAAA,CAAc,OAAO,KAAK,CAAA;AAC1B,MAAA,eAAA,CAAgB,CAAC,SAAS,CAAC,GAAG,MAAM,GAAG,MAAA,CAAO,KAAK,CAAC,CAAA;AACpD,MAAA,OAAA,CAAQ,OAAO,QAAQ,CAAA;AACvB,MAAA,cAAA,CAAe,OAAO,WAAW,CAAA;AAAA,IACnC,CAAA,SAAE;AACA,MAAA,IAAI,KAAA,KAAU,YAAA,CAAa,OAAA,CAAQ,KAAA,EAAO;AACxC,QAAA,YAAA,CAAa,QAAQ,QAAA,GAAW,KAAA;AAChC,QAAA,cAAA,CAAe,KAAK,CAAA;AAAA,MACtB;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAA,KAAY,QAAQ,QAAA,CAAA,IAAa,YAAA,CAAa,WAAW,CAAA,IAAK,CAAC,OAAA,IAAW,CAAC,WAAA,EAAa;AAC1F,MAAA,YAAA,EAAa;AAAA,IACf;AAAA,EAEF,CAAA,EAAG,CAAC,OAAA,EAAS,IAAA,EAAM,QAAA,EAAU,aAAa,MAAA,EAAQ,OAAA,EAAS,WAAA,EAAa,mBAAmB,CAAC,CAAA;AAE5F,EAAA,OAAO,EAAE,YAAA,EAAc,WAAA,EAAa,WAAA,EAAa,YAAA,EAAa;AAChE;;;;"}
@@ -0,0 +1,4 @@
1
+ export declare function useSelectedCache<T>(getOptionValue: (option: T) => string): {
2
+ record: (items: Iterable<T>) => void;
3
+ resolve: (value: string) => T | undefined;
4
+ };
@@ -0,0 +1,17 @@
1
+ import { useRef, useCallback } from 'react';
2
+
3
+ function useSelectedCache(getOptionValue) {
4
+ const cacheRef = useRef(/* @__PURE__ */ new Map());
5
+ const getValueRef = useRef(getOptionValue);
6
+ getValueRef.current = getOptionValue;
7
+ const record = useCallback((items) => {
8
+ for (const item of items) {
9
+ cacheRef.current.set(getValueRef.current(item), item);
10
+ }
11
+ }, []);
12
+ const resolve = useCallback((value) => cacheRef.current.get(value), []);
13
+ return { record, resolve };
14
+ }
15
+
16
+ export { useSelectedCache };
17
+ //# sourceMappingURL=useSelectedCache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSelectedCache.js","sources":["../../../../src/components/Combobox/hooks/useSelectedCache.ts"],"sourcesContent":["import { useCallback, useRef } from 'react'\n\nexport function useSelectedCache<T>(getOptionValue: (option: T) => string) {\n const cacheRef = useRef<Map<string, T>>(new Map())\n const getValueRef = useRef(getOptionValue)\n getValueRef.current = getOptionValue\n\n const record = useCallback((items: Iterable<T>) => {\n for (const item of items) {\n cacheRef.current.set(getValueRef.current(item), item)\n }\n }, [])\n\n const resolve = useCallback((value: string) => cacheRef.current.get(value), [])\n\n return { record, resolve }\n}\n"],"names":[],"mappings":";;AAEO,SAAS,iBAAoB,cAAA,EAAuC;AACzE,EAAA,MAAM,QAAA,GAAW,MAAA,iBAAuB,IAAI,GAAA,EAAK,CAAA;AACjD,EAAA,MAAM,WAAA,GAAc,OAAO,cAAc,CAAA;AACzC,EAAA,WAAA,CAAY,OAAA,GAAU,cAAA;AAEtB,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,CAAC,KAAA,KAAuB;AACjD,IAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACxB,MAAA,QAAA,CAAS,QAAQ,GAAA,CAAI,WAAA,CAAY,OAAA,CAAQ,IAAI,GAAG,IAAI,CAAA;AAAA,IACtD;AAAA,EACF,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,CAAC,KAAA,KAAkB,QAAA,CAAS,QAAQ,GAAA,CAAI,KAAK,CAAA,EAAG,EAAE,CAAA;AAE9E,EAAA,OAAO,EAAE,QAAQ,OAAA,EAAQ;AAC3B;;;;"}
@@ -1,9 +1,9 @@
1
1
  import { ComboboxProps } from './Combobox';
2
2
  export declare const useCombobox: <T extends object>(props: ComboboxProps<T>) => {
3
3
  open: boolean;
4
- setOpen: import('react').Dispatch<import('react').SetStateAction<boolean>>;
4
+ setOpen: (next: boolean) => void;
5
5
  searchTerm: string;
6
- setSearchTerm: import('react').Dispatch<import('react').SetStateAction<string>>;
6
+ setSearchTerm: (next: string) => void;
7
7
  isHovered: boolean;
8
8
  setIsHovered: import('react').Dispatch<import('react').SetStateAction<boolean>>;
9
9
  localOptions: T[];
@@ -12,7 +12,7 @@ export declare const useCombobox: <T extends object>(props: ComboboxProps<T>) =>
12
12
  isVirtualized: boolean;
13
13
  filteredOptions: T[];
14
14
  displayValue: import('react').ReactNode;
15
- hasValue: boolean | undefined;
15
+ hasValue: boolean;
16
16
  showClearButton: boolean | undefined;
17
17
  handleSelect: (currentValue: string) => void;
18
18
  handleRemove: (valueToRemove: string) => void;
@@ -1,173 +1,42 @@
1
- import { useState, useRef, useEffect, useCallback, useMemo } from 'react';
1
+ import { useMemo, useState } from 'react';
2
+ import { useComboboxOpenState } from './hooks/useComboboxOpenState.js';
3
+ import { useComboboxSelection } from './hooks/useComboboxSelection.js';
4
+ import { useDisplayValue } from './hooks/useDisplayValue.js';
5
+ import { usePaginatedOptions } from './hooks/usePaginatedOptions.js';
6
+ import { useSelectedCache } from './hooks/useSelectedCache.js';
2
7
 
3
8
  const useCombobox = (props) => {
4
- const {
5
- options,
6
- getOptionValue,
7
- getOptionLabel,
8
- placeholder = "Select...",
9
- loading = false,
10
- filterOptions,
11
- multiple,
12
- clearable = true,
13
- onClear,
14
- fetchPage,
15
- specialOptions
16
- } = props;
17
- const [open, setOpen] = useState(false);
18
- const [searchTerm, setSearchTerm] = useState("");
19
- const [debouncedSearchTerm, setDebouncedSearchTerm] = useState("");
20
- const [isHovered, setIsHovered] = useState(false);
21
- const [page, setPage] = useState(1);
22
- const [localOptions, setLocalOptions] = useState(options);
23
- const [hasNextPage, setHasNextPage] = useState(true);
24
- const [loadingMore, setLoadingMore] = useState(false);
25
- const debounceTimerRef = useRef(void 0);
26
- const closeOnSelect = props.closeOnSelect ?? !props.multiple;
9
+ const { options, getOptionValue, getOptionLabel, loading = false, filterOptions, fetchPage, onClear, clearable = true } = props;
10
+ const { open, setOpen, searchTerm, debouncedSearchTerm, setSearchTerm } = useComboboxOpenState();
27
11
  const isVirtualized = !!fetchPage;
28
- useEffect(() => {
29
- if (!isVirtualized) return;
30
- clearTimeout(debounceTimerRef.current);
31
- debounceTimerRef.current = setTimeout(() => {
32
- setDebouncedSearchTerm(searchTerm);
33
- }, 300);
34
- return () => {
35
- clearTimeout(debounceTimerRef.current);
36
- };
37
- }, [searchTerm, isVirtualized]);
38
- useEffect(() => {
39
- if (isVirtualized) {
40
- setPage(1);
41
- setLocalOptions([]);
42
- setHasNextPage(true);
43
- setLoadingMore(false);
44
- }
45
- }, [debouncedSearchTerm, isVirtualized]);
46
- const loadNextPage = useCallback(async () => {
47
- if (!fetchPage || loadingMore || !hasNextPage || loading) return;
48
- setLoadingMore(true);
49
- try {
50
- const result = await fetchPage({ page, search: debouncedSearchTerm || void 0 });
51
- setLocalOptions((prev) => [...prev, ...result.items]);
52
- setPage(result.nextPage);
53
- setHasNextPage(result.hasNextPage);
54
- } finally {
55
- setLoadingMore(false);
56
- }
57
- }, [fetchPage, loadingMore, hasNextPage, loading, page, debouncedSearchTerm]);
58
- useEffect(() => {
59
- if (isVirtualized && open && localOptions.length === 0 && !loading && !loadingMore) {
60
- loadNextPage();
61
- }
62
- }, [isVirtualized, open, localOptions.length, loading, loadingMore, loadNextPage]);
12
+ const cache = useSelectedCache(getOptionValue);
13
+ const { localOptions, hasNextPage, loadingMore, loadNextPage } = usePaginatedOptions({
14
+ fetchPage,
15
+ debouncedSearchTerm,
16
+ open,
17
+ prefetch: props.prefetch,
18
+ loading,
19
+ onItemsLoaded: cache.record
20
+ });
63
21
  const filteredOptions = useMemo(() => {
64
- if (isVirtualized) {
65
- return localOptions;
66
- }
22
+ if (isVirtualized) return localOptions;
67
23
  if (!filterOptions) {
68
24
  return options.filter((option) => getOptionLabel(option).toLowerCase().includes(searchTerm.toLowerCase()));
69
25
  }
70
26
  return searchTerm ? filterOptions(options, searchTerm) : options;
71
27
  }, [isVirtualized, localOptions, filterOptions, options, searchTerm, getOptionLabel]);
72
- const handleSelect = useCallback(
73
- (currentValue) => {
74
- if (multiple) {
75
- const { value = [], onChange } = props;
76
- const isRemoving = value.includes(currentValue);
77
- if (specialOptions && specialOptions.length > 0) {
78
- if (isRemoving) {
79
- onChange([]);
80
- } else {
81
- onChange([currentValue]);
82
- }
83
- } else {
84
- if (isRemoving && !clearable && value.length === 1) {
85
- return;
86
- }
87
- const newValues = isRemoving ? value.filter((val) => val !== currentValue) : [...value, currentValue];
88
- onChange(newValues);
89
- }
90
- } else {
91
- const { value, onChange } = props;
92
- const newValue = clearable && currentValue === value ? "" : currentValue;
93
- onChange(newValue);
94
- }
95
- if (closeOnSelect) {
96
- setOpen(false);
97
- }
98
- },
99
- [multiple, clearable, closeOnSelect, props, specialOptions]
100
- );
101
- const handleRemove = useCallback(
102
- (valueToRemove) => {
103
- if (props.multiple) {
104
- const { value = [], onChange } = props;
105
- if (!clearable && value.length === 1) {
106
- return;
107
- }
108
- const newValues = value.filter((val) => val !== valueToRemove);
109
- onChange(newValues);
110
- }
111
- },
112
- [props, clearable]
113
- );
114
- const handleClear = useCallback(
115
- (event) => {
116
- event.preventDefault();
117
- event.stopPropagation();
118
- if (multiple) {
119
- const { onChange } = props;
120
- if (clearable) {
121
- onChange([]);
122
- }
123
- } else {
124
- const { onChange } = props;
125
- onChange("");
126
- }
127
- if (typeof onClear === "function") {
128
- onClear();
129
- }
130
- },
131
- [multiple, clearable, onClear, props]
132
- );
133
- const displayValue = useMemo(() => {
134
- const availableOptions = isVirtualized ? localOptions : options;
135
- const allAvailableOptions = specialOptions ? [...specialOptions, ...availableOptions] : availableOptions;
136
- if (multiple) {
137
- const { value: value2 = [], renderLabel: renderLabel2 } = props;
138
- if (value2.length === 0) return placeholder;
139
- const selectedOptions = allAvailableOptions.filter((option) => value2.includes(getOptionValue(option)));
140
- if (renderLabel2) {
141
- return renderLabel2(selectedOptions, handleRemove);
142
- }
143
- return selectedOptions.map(getOptionLabel).join(", ");
144
- }
145
- const { value, renderLabel } = props;
146
- const selectedOption = allAvailableOptions.find((option) => getOptionValue(option) === value);
147
- if (renderLabel && selectedOption) {
148
- return renderLabel(selectedOption);
149
- }
150
- return selectedOption ? getOptionLabel(selectedOption) : placeholder;
151
- }, [
28
+ const { handleSelect, handleRemove, handleClear, hasValue } = useComboboxSelection(props, setOpen);
29
+ const [isHovered, setIsHovered] = useState(false);
30
+ const displayValue = useDisplayValue({
152
31
  props,
153
- getOptionLabel,
154
- getOptionValue,
155
- options,
156
32
  localOptions,
157
33
  isVirtualized,
158
- placeholder,
159
- multiple,
160
- specialOptions
161
- ]);
162
- const hasValue = useMemo(() => {
163
- if (multiple) {
164
- return props.value && props.value.length > 0;
165
- }
166
- return !!props.value;
167
- }, [props.value, multiple]);
34
+ resolve: cache.resolve,
35
+ recordOptions: cache.record,
36
+ handleRemove
37
+ });
168
38
  const showClearButton = onClear && hasValue && isHovered && clearable;
169
39
  return {
170
- // State
171
40
  open,
172
41
  setOpen,
173
42
  searchTerm,
@@ -177,13 +46,11 @@ const useCombobox = (props) => {
177
46
  localOptions,
178
47
  hasNextPage,
179
48
  loadingMore,
180
- // Computed values
181
49
  isVirtualized,
182
50
  filteredOptions,
183
51
  displayValue,
184
52
  hasValue,
185
53
  showClearButton,
186
- // Handlers
187
54
  handleSelect,
188
55
  handleRemove,
189
56
  handleClear,
@@ -1 +1 @@
1
- {"version":3,"file":"useCombobox.js","sources":["../../../src/components/Combobox/useCombobox.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react'\n\nimport type { ComboboxProps } from './Combobox'\n\nexport const useCombobox = <T extends object>(props: ComboboxProps<T>) => {\n const {\n options,\n getOptionValue,\n getOptionLabel,\n placeholder = 'Select...',\n loading = false,\n filterOptions,\n multiple,\n clearable = true,\n onClear,\n fetchPage,\n specialOptions,\n } = props\n\n const [open, setOpen] = useState(false)\n const [searchTerm, setSearchTerm] = useState('')\n const [debouncedSearchTerm, setDebouncedSearchTerm] = useState('')\n const [isHovered, setIsHovered] = useState(false)\n\n const [page, setPage] = useState(1)\n const [localOptions, setLocalOptions] = useState<Array<T>>(options)\n const [hasNextPage, setHasNextPage] = useState(true)\n const [loadingMore, setLoadingMore] = useState(false)\n\n const debounceTimerRef = useRef<NodeJS.Timeout | undefined>(undefined)\n\n const closeOnSelect = props.closeOnSelect ?? !props.multiple\n const isVirtualized = !!fetchPage\n\n useEffect(() => {\n if (!isVirtualized) return\n\n clearTimeout(debounceTimerRef.current)\n\n debounceTimerRef.current = setTimeout(() => {\n setDebouncedSearchTerm(searchTerm)\n }, 300)\n\n return () => {\n clearTimeout(debounceTimerRef.current)\n }\n }, [searchTerm, isVirtualized])\n\n useEffect(() => {\n if (isVirtualized) {\n setPage(1)\n setLocalOptions([])\n setHasNextPage(true)\n setLoadingMore(false)\n }\n }, [debouncedSearchTerm, isVirtualized])\n\n const loadNextPage = useCallback(async () => {\n if (!fetchPage || loadingMore || !hasNextPage || loading) return\n\n setLoadingMore(true)\n try {\n const result = await fetchPage({ page, search: debouncedSearchTerm || undefined })\n setLocalOptions((prev) => [...prev, ...result.items])\n setPage(result.nextPage)\n setHasNextPage(result.hasNextPage)\n } finally {\n setLoadingMore(false)\n }\n }, [fetchPage, loadingMore, hasNextPage, loading, page, debouncedSearchTerm])\n\n // Load initial page when combobox opens\n useEffect(() => {\n if (isVirtualized && open && localOptions.length === 0 && !loading && !loadingMore) {\n loadNextPage()\n }\n }, [isVirtualized, open, localOptions.length, loading, loadingMore, loadNextPage])\n\n const filteredOptions = useMemo(() => {\n if (isVirtualized) {\n return localOptions\n }\n\n if (!filterOptions) {\n return options.filter((option) => getOptionLabel(option).toLowerCase().includes(searchTerm.toLowerCase()))\n }\n\n return searchTerm ? filterOptions(options, searchTerm) : options\n }, [isVirtualized, localOptions, filterOptions, options, searchTerm, getOptionLabel])\n\n const handleSelect = useCallback(\n (currentValue: string) => {\n if (multiple) {\n const { value = [], onChange } = props\n const isRemoving = value.includes(currentValue)\n\n if (specialOptions && specialOptions.length > 0) {\n if (isRemoving) {\n onChange([])\n } else {\n onChange([currentValue])\n }\n } else {\n if (isRemoving && !clearable && value.length === 1) {\n return\n }\n\n const newValues = isRemoving ? value.filter((val) => val !== currentValue) : [...value, currentValue]\n onChange(newValues)\n }\n } else {\n const { value, onChange } = props\n const newValue = clearable && currentValue === value ? '' : currentValue\n onChange(newValue)\n }\n\n if (closeOnSelect) {\n setOpen(false)\n }\n },\n [multiple, clearable, closeOnSelect, props, specialOptions],\n )\n\n const handleRemove = useCallback(\n (valueToRemove: string) => {\n if (props.multiple) {\n const { value = [], onChange } = props\n\n if (!clearable && value.length === 1) {\n return\n }\n\n const newValues = value.filter((val) => val !== valueToRemove)\n onChange(newValues)\n }\n },\n [props, clearable],\n )\n\n const handleClear = useCallback(\n (event: React.MouseEvent) => {\n event.preventDefault()\n event.stopPropagation()\n\n if (multiple) {\n const { onChange } = props\n\n if (clearable) {\n onChange([])\n }\n } else {\n const { onChange } = props\n onChange('')\n }\n\n if (typeof onClear === 'function') {\n onClear()\n }\n },\n [multiple, clearable, onClear, props],\n )\n\n const displayValue = useMemo(() => {\n const availableOptions = isVirtualized ? localOptions : options\n const allAvailableOptions = specialOptions ? [...specialOptions, ...availableOptions] : availableOptions\n\n if (multiple) {\n const { value = [], renderLabel } = props\n if (value.length === 0) return placeholder\n\n const selectedOptions = allAvailableOptions.filter((option) => value.includes(getOptionValue(option)))\n\n if (renderLabel) {\n return renderLabel(selectedOptions, handleRemove)\n }\n\n return selectedOptions.map(getOptionLabel).join(', ')\n }\n\n const { value, renderLabel } = props\n const selectedOption = allAvailableOptions.find((option) => getOptionValue(option) === value)\n if (renderLabel && selectedOption) {\n return renderLabel(selectedOption)\n }\n return selectedOption ? getOptionLabel(selectedOption) : placeholder\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n props,\n getOptionLabel,\n getOptionValue,\n options,\n localOptions,\n isVirtualized,\n placeholder,\n multiple,\n specialOptions,\n ])\n\n const hasValue = useMemo(() => {\n if (multiple) {\n return props.value && props.value.length > 0\n }\n return !!props.value\n }, [props.value, multiple])\n\n const showClearButton = onClear && hasValue && isHovered && clearable\n\n return {\n // State\n open,\n setOpen,\n searchTerm,\n setSearchTerm,\n isHovered,\n setIsHovered,\n localOptions,\n hasNextPage,\n loadingMore,\n\n // Computed values\n isVirtualized,\n filteredOptions,\n displayValue,\n hasValue,\n showClearButton,\n\n // Handlers\n handleSelect,\n handleRemove,\n handleClear,\n loadNextPage,\n }\n}\n"],"names":["value","renderLabel"],"mappings":"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"}
1
+ {"version":3,"file":"useCombobox.js","sources":["../../../src/components/Combobox/useCombobox.ts"],"sourcesContent":["import { useMemo, useState } from 'react'\n\nimport type { ComboboxProps } from './Combobox'\nimport {\n useComboboxOpenState,\n useComboboxSelection,\n useDisplayValue,\n usePaginatedOptions,\n useSelectedCache,\n} from './hooks'\n\nexport const useCombobox = <T extends object>(props: ComboboxProps<T>) => {\n const { options, getOptionValue, getOptionLabel, loading = false, filterOptions, fetchPage, onClear, clearable = true } = props\n\n const { open, setOpen, searchTerm, debouncedSearchTerm, setSearchTerm } = useComboboxOpenState()\n const isVirtualized = !!fetchPage\n\n const cache = useSelectedCache<T>(getOptionValue)\n\n const { localOptions, hasNextPage, loadingMore, loadNextPage } = usePaginatedOptions<T>({\n fetchPage,\n debouncedSearchTerm,\n open,\n prefetch: props.prefetch,\n loading,\n onItemsLoaded: cache.record,\n })\n\n const filteredOptions = useMemo(() => {\n if (isVirtualized) return localOptions\n\n if (!filterOptions) {\n return options.filter((option) => getOptionLabel(option).toLowerCase().includes(searchTerm.toLowerCase()))\n }\n\n return searchTerm ? filterOptions(options, searchTerm) : options\n }, [isVirtualized, localOptions, filterOptions, options, searchTerm, getOptionLabel])\n\n const { handleSelect, handleRemove, handleClear, hasValue } = useComboboxSelection(props, setOpen)\n\n const [isHovered, setIsHovered] = useState(false)\n\n const displayValue = useDisplayValue<T>({\n props,\n localOptions,\n isVirtualized,\n resolve: cache.resolve,\n recordOptions: cache.record,\n handleRemove,\n })\n\n const showClearButton = onClear && hasValue && isHovered && clearable\n\n return {\n open,\n setOpen,\n searchTerm,\n setSearchTerm,\n isHovered,\n setIsHovered,\n localOptions,\n hasNextPage,\n loadingMore,\n isVirtualized,\n filteredOptions,\n displayValue,\n hasValue,\n showClearButton,\n handleSelect,\n handleRemove,\n handleClear,\n loadNextPage,\n }\n}\n"],"names":[],"mappings":";;;;;;;AAWO,MAAM,WAAA,GAAc,CAAmB,KAAA,KAA4B;AACxE,EAAA,MAAM,EAAE,OAAA,EAAS,cAAA,EAAgB,cAAA,EAAgB,OAAA,GAAU,KAAA,EAAO,aAAA,EAAe,SAAA,EAAW,OAAA,EAAS,SAAA,GAAY,IAAA,EAAK,GAAI,KAAA;AAE1H,EAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,YAAY,mBAAA,EAAqB,aAAA,KAAkB,oBAAA,EAAqB;AAC/F,EAAA,MAAM,aAAA,GAAgB,CAAC,CAAC,SAAA;AAExB,EAAA,MAAM,KAAA,GAAQ,iBAAoB,cAAc,CAAA;AAEhD,EAAA,MAAM,EAAE,YAAA,EAAc,WAAA,EAAa,WAAA,EAAa,YAAA,KAAiB,mBAAA,CAAuB;AAAA,IACtF,SAAA;AAAA,IACA,mBAAA;AAAA,IACA,IAAA;AAAA,IACA,UAAU,KAAA,CAAM,QAAA;AAAA,IAChB,OAAA;AAAA,IACA,eAAe,KAAA,CAAM;AAAA,GACtB,CAAA;AAED,EAAA,MAAM,eAAA,GAAkB,QAAQ,MAAM;AACpC,IAAA,IAAI,eAAe,OAAO,YAAA;AAE1B,IAAA,IAAI,CAAC,aAAA,EAAe;AAClB,MAAA,OAAO,OAAA,CAAQ,MAAA,CAAO,CAAC,MAAA,KAAW,cAAA,CAAe,MAAM,CAAA,CAAE,WAAA,EAAY,CAAE,QAAA,CAAS,UAAA,CAAW,WAAA,EAAa,CAAC,CAAA;AAAA,IAC3G;AAEA,IAAA,OAAO,UAAA,GAAa,aAAA,CAAc,OAAA,EAAS,UAAU,CAAA,GAAI,OAAA;AAAA,EAC3D,CAAA,EAAG,CAAC,aAAA,EAAe,YAAA,EAAc,eAAe,OAAA,EAAS,UAAA,EAAY,cAAc,CAAC,CAAA;AAEpF,EAAA,MAAM,EAAE,cAAc,YAAA,EAAc,WAAA,EAAa,UAAS,GAAI,oBAAA,CAAqB,OAAO,OAAO,CAAA;AAEjG,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAEhD,EAAA,MAAM,eAAe,eAAA,CAAmB;AAAA,IACtC,KAAA;AAAA,IACA,YAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAS,KAAA,CAAM,OAAA;AAAA,IACf,eAAe,KAAA,CAAM,MAAA;AAAA,IACrB;AAAA,GACD,CAAA;AAED,EAAA,MAAM,eAAA,GAAkB,OAAA,IAAW,QAAA,IAAY,SAAA,IAAa,SAAA;AAE5D,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,OAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA,WAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA,QAAA;AAAA,IACA,eAAA;AAAA,IACA,YAAA;AAAA,IACA,YAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -15,8 +15,14 @@ declare const TooltipRoot: React.FC<TooltipPrimitive.TooltipProps>;
15
15
  * Wrap with asChild to use custom components as triggers.
16
16
  */
17
17
  declare const TooltipTrigger: React.ForwardRefExoticComponent<TooltipPrimitive.TooltipTriggerProps & React.RefAttributes<HTMLButtonElement>>;
18
+ declare const TooltipPortal: React.FC<TooltipPrimitive.TooltipPortalProps>;
18
19
  declare const TooltipContent: React.ForwardRefExoticComponent<Omit<TooltipPrimitive.TooltipContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & {
19
20
  arrow?: boolean;
21
+ /**
22
+ * Container for the portal. When provided, the tooltip is portaled into this element instead of `document.body`.
23
+ * Pass `null` to disable portaling and render inline (legacy behavior).
24
+ */
25
+ container?: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Portal>["container"] | null;
20
26
  } & React.RefAttributes<HTMLDivElement>>;
21
27
  export type TooltipProps = {
22
28
  /**
@@ -99,4 +105,4 @@ export declare function Tooltip({ triggerElement, children, side, className, del
99
105
  * </TooltipRoot>
100
106
  * </TooltipProvider>
101
107
  */
102
- export { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger };
108
+ export { TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger };
@@ -8,29 +8,36 @@ import { cn } from '../../lib/utils.js';
8
8
  const TooltipProvider = TooltipPrimitive.Provider;
9
9
  const TooltipRoot = TooltipPrimitive.Root;
10
10
  const TooltipTrigger = TooltipPrimitive.Trigger;
11
- const TooltipContent = React.forwardRef(({ className, sideOffset = 4, arrow, children, ...props }, ref) => /* @__PURE__ */ jsxs(
12
- TooltipPrimitive.Content,
13
- {
14
- ref,
15
- sideOffset,
16
- className: cn(
17
- "z-50 rounded-lg bg-white px-3 py-1.5 text-sm",
18
- "shadow-tooltip",
19
- "animate-in fade-in-0 zoom-in-95",
20
- "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
21
- "data-[side=bottom]:slide-in-from-top-2",
22
- "data-[side=left]:slide-in-from-right-2",
23
- "data-[side=right]:slide-in-from-left-2",
24
- "data-[side=top]:slide-in-from-bottom-2",
25
- className
26
- ),
27
- ...props,
28
- children: [
29
- children,
30
- arrow && /* @__PURE__ */ jsx(TooltipPrimitive.Arrow, { fill: "white" })
31
- ]
11
+ const TooltipPortal = TooltipPrimitive.Portal;
12
+ const TooltipContent = React.forwardRef(
13
+ ({ className, sideOffset = 4, arrow, container, children, ...props }, ref) => {
14
+ const content = /* @__PURE__ */ jsxs(
15
+ TooltipPrimitive.Content,
16
+ {
17
+ ref,
18
+ sideOffset,
19
+ className: cn(
20
+ "z-50 rounded-lg bg-white px-3 py-1.5 text-sm",
21
+ "shadow-tooltip",
22
+ "animate-in fade-in-0 zoom-in-95",
23
+ "data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
24
+ "data-[side=bottom]:slide-in-from-top-2",
25
+ "data-[side=left]:slide-in-from-right-2",
26
+ "data-[side=right]:slide-in-from-left-2",
27
+ "data-[side=top]:slide-in-from-bottom-2",
28
+ className
29
+ ),
30
+ ...props,
31
+ children: [
32
+ children,
33
+ arrow && /* @__PURE__ */ jsx(TooltipPrimitive.Arrow, { fill: "white" })
34
+ ]
35
+ }
36
+ );
37
+ if (container === null) return content;
38
+ return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, { container: container ?? void 0, children: content });
32
39
  }
33
- ));
40
+ );
34
41
  TooltipContent.displayName = TooltipPrimitive.Content.displayName;
35
42
  function Tooltip({
36
43
  triggerElement,
@@ -60,9 +67,9 @@ function Tooltip({
60
67
  }
61
68
  ) : /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
62
69
  /* @__PURE__ */ jsx(TooltipTrigger, { asChild: true, children: triggerElement }),
63
- /* @__PURE__ */ jsx(TooltipContent, { side, className, arrow, children })
70
+ /* @__PURE__ */ jsx(TooltipContent, { side, className, arrow, container, children })
64
71
  ] }) });
65
72
  }
66
73
 
67
- export { Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger };
74
+ export { Tooltip, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger };
68
75
  //# sourceMappingURL=Tooltip.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tooltip.js","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport * as React from 'react'\n\nimport { Popover } from '../Popover/Popover'\n\nimport { useIsMobile } from '@/lib/useMobile'\nimport { cn } from '@/lib/utils'\n\n/**\n * Provider component that wraps all tooltip instances.\n * Controls the delay duration and positioning of tooltips app-wide.\n */\nconst TooltipProvider = TooltipPrimitive.Provider\n\n/**\n * The root component that wraps the trigger and content.\n * Manages the open state and hover interactions.\n */\nconst TooltipRoot = TooltipPrimitive.Root\n\n/**\n * The element that triggers the tooltip when hovered or focused.\n * Wrap with asChild to use custom components as triggers.\n */\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\nconst TooltipContent = React.forwardRef<\n React.ComponentRef<typeof TooltipPrimitive.Content>,\n React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & { arrow?: boolean }\n>(({ className, sideOffset = 4, arrow, children, ...props }, ref) => (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 rounded-lg bg-white px-3 py-1.5 text-sm',\n 'shadow-tooltip',\n 'animate-in fade-in-0 zoom-in-95',\n 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n {...props}\n >\n {children}\n {arrow && <TooltipPrimitive.Arrow fill=\"white\" />}\n </TooltipPrimitive.Content>\n))\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport type TooltipProps = {\n /**\n * The content to be displayed inside the tooltip\n */\n children: React.ReactElement | string\n\n /**\n * The element that triggers the tooltip on hover\n */\n triggerElement: React.ReactElement | string\n\n /**\n * The preferred side of the trigger to render the tooltip\n */\n side?: 'top' | 'right' | 'bottom' | 'left'\n\n /**\n * Optional custom className for additional styling\n */\n className?: string\n\n /**\n * Delay duration for showing the tooltip in milliseconds\n * @default 700\n */\n delayDuration?: number\n\n /**\n * Whether to show an arrow pointer on the tooltip\n * @default false\n */\n arrow?: boolean\n\n /**\n * The preferred side of the trigger to render the mobile\n */\n mobileSide?: 'top' | 'right' | 'bottom' | 'left'\n\n /**\n * The preferred alignment of the mobile\n */\n mobileAlign?: 'start' | 'center' | 'end'\n\n /**\n * The preferred side offset of the mobile\n */\n mobileSideOffset?: number\n\n /**\n * The container to position the mobile\n */\n container?: HTMLElement\n}\n\n/**\n * A versatile tooltip component that shows additional information on hover.\n * Built on top of Radix UI's tooltip primitives with custom styling and animations.\n *\n * @example\n * // Basic usage\n * <Tooltip triggerElement={<button>Hover me</button>} side=\"top\">\n * Helpful information\n * </Tooltip>\n *\n * @example\n * // With custom delay and className\n * <Tooltip\n * triggerElement={<Icon />}\n * side=\"right\"\n * delayDuration={300}\n * className=\"custom-tooltip\"\n * >\n * Icon description\n * </Tooltip>\n */\nexport function Tooltip({\n triggerElement,\n children,\n side = 'top',\n className,\n delayDuration = 700,\n arrow = false,\n mobileSide,\n mobileAlign,\n mobileSideOffset,\n container,\n ...props\n}: Readonly<TooltipProps>) {\n const isMobile = useIsMobile()\n\n return isMobile ? (\n <Popover\n side={mobileSide}\n className={className}\n align={mobileAlign}\n sideOffset={mobileSideOffset}\n triggerElement={triggerElement}\n container={container}\n {...props}\n >\n {children}\n </Popover>\n ) : (\n <TooltipProvider>\n <TooltipRoot delayDuration={delayDuration}>\n <TooltipTrigger asChild>{triggerElement}</TooltipTrigger>\n <TooltipContent side={side} className={className} arrow={arrow}>\n {children}\n </TooltipContent>\n </TooltipRoot>\n </TooltipProvider>\n )\n}\n\n/**\n * Export primitive components for custom tooltip implementations.\n * Use these when you need more control over the tooltip behavior and styling.\n *\n * @example\n * // Custom implementation using primitives\n * <TooltipProvider>\n * <TooltipRoot>\n * <TooltipTrigger asChild>\n * <button>Hover</button>\n * </TooltipTrigger>\n * <TooltipContent>Custom tooltip</TooltipContent>\n * </TooltipRoot>\n * </TooltipProvider>\n */\nexport { TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger }\n"],"names":[],"mappings":";;;;;;;AAYA,MAAM,kBAAkB,gBAAA,CAAiB;AAMzC,MAAM,cAAc,gBAAA,CAAiB;AAMrC,MAAM,iBAAiB,gBAAA,CAAiB;AAExC,MAAM,cAAA,GAAiB,KAAA,CAAM,UAAA,CAG3B,CAAC,EAAE,SAAA,EAAW,UAAA,GAAa,CAAA,EAAG,KAAA,EAAO,QAAA,EAAU,GAAG,KAAA,IAAS,GAAA,qBAC3D,IAAA;AAAA,EAAC,gBAAA,CAAiB,OAAA;AAAA,EAAjB;AAAA,IACC,GAAA;AAAA,IACA,UAAA;AAAA,IACA,SAAA,EAAW,EAAA;AAAA,MACT,8CAAA;AAAA,MACA,gBAAA;AAAA,MACA,iCAAA;AAAA,MACA,gGAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA,wCAAA;AAAA,MACA;AAAA,KACF;AAAA,IACC,GAAG,KAAA;AAAA,IAEH,QAAA,EAAA;AAAA,MAAA,QAAA;AAAA,MACA,yBAAS,GAAA,CAAC,gBAAA,CAAiB,KAAA,EAAjB,EAAuB,MAAK,OAAA,EAAQ;AAAA;AAAA;AACjD,CACD;AACD,cAAA,CAAe,WAAA,GAAc,iBAAiB,OAAA,CAAQ,WAAA;AA6E/C,SAAS,OAAA,CAAQ;AAAA,EACtB,cAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,SAAA;AAAA,EACA,aAAA,GAAgB,GAAA;AAAA,EAChB,KAAA,GAAQ,KAAA;AAAA,EACR,UAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA2B;AACzB,EAAA,MAAM,WAAW,WAAA,EAAY;AAE7B,EAAA,OAAO,QAAA,mBACL,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,UAAA;AAAA,MACN,SAAA;AAAA,MACA,KAAA,EAAO,WAAA;AAAA,MACP,UAAA,EAAY,gBAAA;AAAA,MACZ,cAAA;AAAA,MACA,SAAA;AAAA,MACC,GAAG,KAAA;AAAA,MAEH;AAAA;AAAA,GACH,mBAEA,GAAA,CAAC,eAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,eAAY,aAAA,EACX,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAO,IAAA,EAAE,QAAA,EAAA,cAAA,EAAe,CAAA;AAAA,oBACxC,GAAA,CAAC,cAAA,EAAA,EAAe,IAAA,EAAY,SAAA,EAAsB,OAC/C,QAAA,EACH;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"Tooltip.js","sources":["../../../src/components/Tooltip/Tooltip.tsx"],"sourcesContent":["import * as TooltipPrimitive from '@radix-ui/react-tooltip'\nimport * as React from 'react'\n\nimport { Popover } from '../Popover/Popover'\n\nimport { useIsMobile } from '@/lib/useMobile'\nimport { cn } from '@/lib/utils'\n\n/**\n * Provider component that wraps all tooltip instances.\n * Controls the delay duration and positioning of tooltips app-wide.\n */\nconst TooltipProvider = TooltipPrimitive.Provider\n\n/**\n * The root component that wraps the trigger and content.\n * Manages the open state and hover interactions.\n */\nconst TooltipRoot = TooltipPrimitive.Root\n\n/**\n * The element that triggers the tooltip when hovered or focused.\n * Wrap with asChild to use custom components as triggers.\n */\nconst TooltipTrigger = TooltipPrimitive.Trigger\n\nconst TooltipPortal = TooltipPrimitive.Portal\n\ntype TooltipContentProps = React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {\n arrow?: boolean\n /**\n * Container for the portal. When provided, the tooltip is portaled into this element instead of `document.body`.\n * Pass `null` to disable portaling and render inline (legacy behavior).\n */\n container?: React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Portal>['container'] | null\n}\n\nconst TooltipContent = React.forwardRef<React.ComponentRef<typeof TooltipPrimitive.Content>, TooltipContentProps>(\n ({ className, sideOffset = 4, arrow, container, children, ...props }, ref) => {\n const content = (\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n 'z-50 rounded-lg bg-white px-3 py-1.5 text-sm',\n 'shadow-tooltip',\n 'animate-in fade-in-0 zoom-in-95',\n 'data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95',\n 'data-[side=bottom]:slide-in-from-top-2',\n 'data-[side=left]:slide-in-from-right-2',\n 'data-[side=right]:slide-in-from-left-2',\n 'data-[side=top]:slide-in-from-bottom-2',\n className,\n )}\n {...props}\n >\n {children}\n {arrow && <TooltipPrimitive.Arrow fill=\"white\" />}\n </TooltipPrimitive.Content>\n )\n\n if (container === null) return content\n return <TooltipPrimitive.Portal container={container ?? undefined}>{content}</TooltipPrimitive.Portal>\n },\n)\nTooltipContent.displayName = TooltipPrimitive.Content.displayName\n\nexport type TooltipProps = {\n /**\n * The content to be displayed inside the tooltip\n */\n children: React.ReactElement | string\n\n /**\n * The element that triggers the tooltip on hover\n */\n triggerElement: React.ReactElement | string\n\n /**\n * The preferred side of the trigger to render the tooltip\n */\n side?: 'top' | 'right' | 'bottom' | 'left'\n\n /**\n * Optional custom className for additional styling\n */\n className?: string\n\n /**\n * Delay duration for showing the tooltip in milliseconds\n * @default 700\n */\n delayDuration?: number\n\n /**\n * Whether to show an arrow pointer on the tooltip\n * @default false\n */\n arrow?: boolean\n\n /**\n * The preferred side of the trigger to render the mobile\n */\n mobileSide?: 'top' | 'right' | 'bottom' | 'left'\n\n /**\n * The preferred alignment of the mobile\n */\n mobileAlign?: 'start' | 'center' | 'end'\n\n /**\n * The preferred side offset of the mobile\n */\n mobileSideOffset?: number\n\n /**\n * The container to position the mobile\n */\n container?: HTMLElement\n}\n\n/**\n * A versatile tooltip component that shows additional information on hover.\n * Built on top of Radix UI's tooltip primitives with custom styling and animations.\n *\n * @example\n * // Basic usage\n * <Tooltip triggerElement={<button>Hover me</button>} side=\"top\">\n * Helpful information\n * </Tooltip>\n *\n * @example\n * // With custom delay and className\n * <Tooltip\n * triggerElement={<Icon />}\n * side=\"right\"\n * delayDuration={300}\n * className=\"custom-tooltip\"\n * >\n * Icon description\n * </Tooltip>\n */\nexport function Tooltip({\n triggerElement,\n children,\n side = 'top',\n className,\n delayDuration = 700,\n arrow = false,\n mobileSide,\n mobileAlign,\n mobileSideOffset,\n container,\n ...props\n}: Readonly<TooltipProps>) {\n const isMobile = useIsMobile()\n\n return isMobile ? (\n <Popover\n side={mobileSide}\n className={className}\n align={mobileAlign}\n sideOffset={mobileSideOffset}\n triggerElement={triggerElement}\n container={container}\n {...props}\n >\n {children}\n </Popover>\n ) : (\n <TooltipProvider>\n <TooltipRoot delayDuration={delayDuration}>\n <TooltipTrigger asChild>{triggerElement}</TooltipTrigger>\n <TooltipContent side={side} className={className} arrow={arrow} container={container}>\n {children}\n </TooltipContent>\n </TooltipRoot>\n </TooltipProvider>\n )\n}\n\n/**\n * Export primitive components for custom tooltip implementations.\n * Use these when you need more control over the tooltip behavior and styling.\n *\n * @example\n * // Custom implementation using primitives\n * <TooltipProvider>\n * <TooltipRoot>\n * <TooltipTrigger asChild>\n * <button>Hover</button>\n * </TooltipTrigger>\n * <TooltipContent>Custom tooltip</TooltipContent>\n * </TooltipRoot>\n * </TooltipProvider>\n */\nexport { TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger }\n"],"names":[],"mappings":";;;;;;;AAYA,MAAM,kBAAkB,gBAAA,CAAiB;AAMzC,MAAM,cAAc,gBAAA,CAAiB;AAMrC,MAAM,iBAAiB,gBAAA,CAAiB;AAExC,MAAM,gBAAgB,gBAAA,CAAiB;AAWvC,MAAM,iBAAiB,KAAA,CAAM,UAAA;AAAA,EAC3B,CAAC,EAAE,SAAA,EAAW,UAAA,GAAa,CAAA,EAAG,KAAA,EAAO,SAAA,EAAW,QAAA,EAAU,GAAG,KAAA,EAAM,EAAG,GAAA,KAAQ;AAC5E,IAAA,MAAM,OAAA,mBACJ,IAAA;AAAA,MAAC,gBAAA,CAAiB,OAAA;AAAA,MAAjB;AAAA,QACC,GAAA;AAAA,QACA,UAAA;AAAA,QACA,SAAA,EAAW,EAAA;AAAA,UACT,8CAAA;AAAA,UACA,gBAAA;AAAA,UACA,iCAAA;AAAA,UACA,gGAAA;AAAA,UACA,wCAAA;AAAA,UACA,wCAAA;AAAA,UACA,wCAAA;AAAA,UACA,wCAAA;AAAA,UACA;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA;AAAA,UAAA,QAAA;AAAA,UACA,yBAAS,GAAA,CAAC,gBAAA,CAAiB,KAAA,EAAjB,EAAuB,MAAK,OAAA,EAAQ;AAAA;AAAA;AAAA,KACjD;AAGF,IAAA,IAAI,SAAA,KAAc,MAAM,OAAO,OAAA;AAC/B,IAAA,2BAAQ,gBAAA,CAAiB,MAAA,EAAjB,EAAwB,SAAA,EAAW,SAAA,IAAa,QAAY,QAAA,EAAA,OAAA,EAAQ,CAAA;AAAA,EAC9E;AACF;AACA,cAAA,CAAe,WAAA,GAAc,iBAAiB,OAAA,CAAQ,WAAA;AA6E/C,SAAS,OAAA,CAAQ;AAAA,EACtB,cAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA,GAAO,KAAA;AAAA,EACP,SAAA;AAAA,EACA,aAAA,GAAgB,GAAA;AAAA,EAChB,KAAA,GAAQ,KAAA;AAAA,EACR,UAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,GAAG;AACL,CAAA,EAA2B;AACzB,EAAA,MAAM,WAAW,WAAA,EAAY;AAE7B,EAAA,OAAO,QAAA,mBACL,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,UAAA;AAAA,MACN,SAAA;AAAA,MACA,KAAA,EAAO,WAAA;AAAA,MACP,UAAA,EAAY,gBAAA;AAAA,MACZ,cAAA;AAAA,MACA,SAAA;AAAA,MACC,GAAG,KAAA;AAAA,MAEH;AAAA;AAAA,GACH,mBAEA,GAAA,CAAC,eAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,eAAY,aAAA,EACX,QAAA,EAAA;AAAA,oBAAA,GAAA,CAAC,cAAA,EAAA,EAAe,OAAA,EAAO,IAAA,EAAE,QAAA,EAAA,cAAA,EAAe,CAAA;AAAA,wBACvC,cAAA,EAAA,EAAe,IAAA,EAAY,SAAA,EAAsB,KAAA,EAAc,WAC7D,QAAA,EACH;AAAA,GAAA,EACF,CAAA,EACF,CAAA;AAEJ;;;;"}
@@ -1,2 +1,2 @@
1
- export { Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from './Tooltip.js';
1
+ export { Tooltip, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger } from './Tooltip.js';
2
2
  //# sourceMappingURL=index.js.map
package/dist/index.js CHANGED
@@ -42,7 +42,7 @@ export { Textarea } from './components/Textarea/Textarea.js';
42
42
  export { Toaster, toast } from './components/Toaster/Toaster.js';
43
43
  export { Toggle, toggleVariants } from './components/Toggle/Toggle.js';
44
44
  export { ToggleGroup, ToggleGroupItem } from './components/ToggleGroup/ToggleGroup.js';
45
- export { Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger } from './components/Tooltip/Tooltip.js';
45
+ export { Tooltip, TooltipContent, TooltipPortal, TooltipProvider, TooltipRoot, TooltipTrigger } from './components/Tooltip/Tooltip.js';
46
46
  export { TruncatedTypographyWithTooltip } from './components/TruncatedTypographyWithTooltip/TruncatedTypographyWithTooltip.js';
47
47
  export { Typography, typographyVariants } from './components/Typography/Typography.js';
48
48
  export { InputDate } from './components/InputDate/InputDate.js';
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "periplo-ui",
3
3
  "description": "IATI UI library",
4
4
  "private": false,
5
- "version": "4.2.1",
5
+ "version": "4.3.1",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "types": "dist/index.d.ts",